From 6ea4f6e12330fd675a0ff4f50438f40ba7552436 Mon Sep 17 00:00:00 2001 From: Brendan LE GLAUNEC Date: Tue, 31 Oct 2017 10:23:17 +0100 Subject: [PATCH] WIP JSONRPC2 implementation --- glide.lock | 33 +-------- server/adaptor/jsonrpc2/jsonrpc2.go | 58 +++++++++++++++ server/service/handler.go | 110 ++++++++++++++++++++++++++++ server/service/service.go | 68 +++++++++-------- 4 files changed, 207 insertions(+), 62 deletions(-) create mode 100644 server/adaptor/jsonrpc2/jsonrpc2.go create mode 100644 server/service/handler.go diff --git a/glide.lock b/glide.lock index 6c8f130..70f82ca 100644 --- a/glide.lock +++ b/glide.lock @@ -1,57 +1,28 @@ hash: f646c12961eac693464d18f1ab91a7dd734514a1de59dfce2fe6de1507512bf7 -updated: 2017-10-20T08:57:53.219213734+02:00 +updated: 2017-10-31T09:52:06.986193695+01:00 imports: - name: github.com/andelf/go-curl version: f8b334df3789fbdf98df3b3b22815e958b956c19 -- name: github.com/davecgh/go-spew - version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9 - subpackages: - - spew - name: github.com/fatih/color version: 570b54cabe6b8eb0bc2dfce68d964677d63b5260 - name: github.com/gernest/wow - version: 8da164fc5bfb8099d4aceccb1c20d5934054723d + version: 57298475c6371a5a652e74dcf624c80edfc5ae1a subpackages: - spin - name: github.com/go-playground/locales version: e4cbcb5d0652150d40ad0646651076b6bd2be4f6 - subpackages: - - currency - name: github.com/go-playground/universal-translator version: b32fa301c9fe55953584134cb6853a13c87ec0a1 - name: github.com/gorilla/websocket version: ea4d1f681babbce9545c9c5f3d5194a789c89f5b - name: github.com/jessevdk/go-flags version: 96dc06278ce32a0e9d957d590bb987c81ee66407 -- name: github.com/mattn/go-colorable - version: 5411d3eea5978e6cdc258b30de592b60df6aba96 - repo: https://github.com/mattn/go-colorable -- name: github.com/mattn/go-isatty - version: 57fdcb988a5c543893cc61bce354a6e24ab70022 - repo: https://github.com/mattn/go-isatty - name: github.com/pkg/errors version: 645ef00459ed84a119197bfb8d8205042c6df63d -- name: github.com/pmezard/go-difflib - version: d8ed2627bdf02c080bf22230dbb337003b7aba2d - subpackages: - - difflib -- name: github.com/stretchr/objx - version: cbeaeb16a013161a98496fad62933b1d21786672 - name: github.com/stretchr/testify version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0 subpackages: - - assert - mock -- name: golang.org/x/crypto - version: 9419663f5a44be8b34ca85f08abc5fe1be11f8a3 - subpackages: - - ssh/terminal -- name: golang.org/x/sys - version: e24f485414aeafb646f6fca458b0bf869c0880a1 - repo: https://go.googlesource.com/sys - subpackages: - - unix - - windows - name: gopkg.in/go-playground/validator.v9 version: a021b2ec9a8a8bb970f3f15bc42617cb520e8a64 - name: gopkg.in/tylerb/graceful.v1 diff --git a/server/adaptor/jsonrpc2/jsonrpc2.go b/server/adaptor/jsonrpc2/jsonrpc2.go new file mode 100644 index 0000000..e5acd48 --- /dev/null +++ b/server/adaptor/jsonrpc2/jsonrpc2.go @@ -0,0 +1,58 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package jsonrpc2 + +// http://www.jsonrpc.org/specification +const ( + ParseError = -32700 // Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text. + InvalidRequest = -32600 // The JSON sent is not a valid Request object. + MethodNotFound = -32601 // The method does not exist / is not available. + InvalidParams = -32602 // Invalid method parameter(s). + InternalError = -32603 // Internal JSON-RPC error. +) + +const ( + // ParseErrorMessage is the message associated with the ParseError error + ParseErrorMessage = "Parse error" + // InvalidRequestMessage is the message associated with the InvalidRequest error + InvalidRequestMessage = "Invalid Request" + // MethodNotFoundMessage is the message associated with the MethodNotFound error + MethodNotFoundMessage = "Method not found" + // InvalidParamsMessage is the message associated with the InvalidParams error + InvalidParamsMessage = "Invalid params" + // InternalErrorMessage is the message associated with the InternalError error + InternalErrorMessage = "Internal error" +) + +// Request represents a JSONRPC request +type Request struct { + JSONRPC string `json:"jsonrpc" validate:"eq=2.0"` + Method string `json:"method" validate:"required"` + Params string `json:"params" validate:"required"` + ID string `json:"id"` +} + +// Response represents a JSONRPC response +type Response struct { + JSONRPC string `json:"jsonrpc" validate:"eq=2.0"` + Result string `json:"result"` + Error Error `json:"error"` + ID string `json:"id"` +} + +// Error represents a JSONRPC response's error +type Error struct { + Code int `json:"code"` + Message string `json:"message"` + Data string `json:"data"` +} diff --git a/server/service/handler.go b/server/service/handler.go new file mode 100644 index 0000000..b7d4d7b --- /dev/null +++ b/server/service/handler.go @@ -0,0 +1,110 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package service + +import ( + "encoding/json" + "fmt" + + "github.com/EtixLabs/cameradar" + "github.com/EtixLabs/cameradar/server/adaptor/jsonrpc2" + v "gopkg.in/go-playground/validator.v9" +) + +func (c *Cameradar) handleRequest(message string) { + var ret []cmrdr.Stream + var JSONRPCErr jsonrpc2.Error + + var request jsonrpc2.Request + err := json.Unmarshal([]byte(message), &request) + if err != nil { + JSONRPCErr = jsonrpc2.Error{ + Code: jsonrpc2.ParseError, + Message: jsonrpc2.ParseErrorMessage, + Data: err.Error(), + } + } + + validate := v.New() + err = validate.Struct(request) + if err != nil { + JSONRPCErr = jsonrpc2.Error{ + Code: jsonrpc2.InvalidRequest, + Message: jsonrpc2.InvalidRequestMessage, + Data: err.Error(), + } + } + + var options Options + err = json.Unmarshal([]byte(request.Params), &options) + if err != nil { + JSONRPCErr = jsonrpc2.Error{ + Code: jsonrpc2.InvalidParams, + Message: jsonrpc2.InvalidParamsMessage, + Data: err.Error(), + } + } + + c.SetOptions(options) + + switch request.Method { + case "discover": + ret, err = c.Discover() + case "attack_credentials": + ret, err = c.Discover() + case "attack_routes": + ret, err = c.Discover() + case "discover_and_attack": + ret, err = c.DiscoverAndAttack() + default: + JSONRPCErr = jsonrpc2.Error{ + Code: jsonrpc2.MethodNotFound, + Message: jsonrpc2.MethodNotFoundMessage, + Data: err.Error(), + } + } + if err != nil { + JSONRPCErr = jsonrpc2.Error{ + Code: jsonrpc2.InternalError, + Message: jsonrpc2.InternalErrorMessage, + Data: err.Error(), + } + } + + result, err := json.Marshal(ret) + if err != nil { + JSONRPCErr = jsonrpc2.Error{ + Code: jsonrpc2.InternalError, + Message: jsonrpc2.InternalErrorMessage, + Data: err.Error(), + } + } + c.respondToClient(string(result), request.ID, JSONRPCErr) +} + +func (c *Cameradar) respondToClient(result, ID string, JSONRPCErr jsonrpc2.Error) { + println(result) + r := jsonrpc2.Response{ + JSONRPC: "2.0", + Result: result, + Error: JSONRPCErr, + ID: ID, + } + + response, err := json.Marshal(r) + if err != nil { + c.toClient <- "{\"jsonrpc\": \"2.0\",\"result\":null,\"error\":{\"code\":" + fmt.Sprint(jsonrpc2.InternalError) + ",\"" + jsonrpc2.InternalErrorMessage + "\",\"data\":\"could not marshal response\"},\"id\":\"" + ID + "\"}" + } + + c.toClient <- string(response) +} diff --git a/server/service/service.go b/server/service/service.go index 181b220..6b3bba1 100644 --- a/server/service/service.go +++ b/server/service/service.go @@ -13,7 +13,6 @@ package service import ( - "encoding/json" "fmt" "time" @@ -31,12 +30,6 @@ type Cameradar struct { fromClient <-chan string } -type request struct { - Method string - Target string - Ports string -} - // Options contains all options needed to launch a complete cameradar scan type Options struct { Target string @@ -84,56 +77,69 @@ func (c *Cameradar) Run() { for { msg, ok := <-c.fromClient if !ok { - println("disconnected") + println("client disconnected") return } + go c.handleRequest(msg) + } +} - var req request - err := json.Unmarshal([]byte(msg), &req) - if err != nil { - c.toClient <- "invalid request: " + err.Error() - continue - } - - switch req.Method { - case "discover": - c.toClient <- "" - case "attack": - c.toClient <- "" - default: - c.toClient <- "invalid method: " + req.Method +// DiscoverAndAttack launches a Cameradar scan followed by all necessary +// attacks to access the cameras +func (c *Cameradar) DiscoverAndAttack() ([]cmrdr.Stream, error) { + streams, err := c.Discover() + if err != nil { + return streams, err + } + streams, err = c.AttackRoute() + if err != nil { + return streams, err + } + streams, err = c.AttackCredentials() + if err != nil { + return streams, err + } + for _, stream := range streams { + if stream.RouteFound == false { + return c.AttackCredentials() } } + return streams, nil } // Discover launches a Cameradar scan using the service's options -func (c *Cameradar) Discover() error { +func (c *Cameradar) Discover() ([]cmrdr.Stream, error) { streams, err := cmrdr.Discover(c.options.Target, c.options.Ports, c.options.OutputFile, c.options.Speed, true) if err != nil { - return errors.Wrap(err, "could not discover streams") + return streams, errors.Wrap(err, "could not discover streams") } c.Streams = streams - return nil + return streams, nil } // AttackRoute launches a Cameradar route attack using the service's options -func (c *Cameradar) AttackRoute() error { +func (c *Cameradar) AttackRoute() ([]cmrdr.Stream, error) { streams, err := cmrdr.AttackRoute(c.Streams, c.options.Routes, c.options.Timeout, true) if err != nil { - return errors.Wrap(err, "could not discover streams") + return streams, errors.Wrap(err, "could not discover streams") } c.Streams = streams - return nil + return streams, nil } // AttackCredentials launches a Cameradar credential attack using the service's options -func (c *Cameradar) AttackCredentials() error { +func (c *Cameradar) AttackCredentials() ([]cmrdr.Stream, error) { streams, err := cmrdr.AttackCredentials(c.Streams, c.options.Credentials, c.options.Timeout, true) if err != nil { - return errors.Wrap(err, "could not discover streams") + return streams, errors.Wrap(err, "could not discover streams") } c.Streams = streams - return nil + return streams, nil +} + +// SetOptions sets all options using an option structure +func (c *Cameradar) SetOptions(options Options) { + c.options = &options } // SetNmapOutputFile sets the OutputFile option