Cameradar service scans & attacks over WS

This commit is contained in:
Brendan LE GLAUNEC
2017-10-31 11:22:02 +01:00
committed by Brendan Le Glaunec
parent 6ea4f6e123
commit 1dadb93452
4 changed files with 124 additions and 86 deletions
+21 -8
View File
@@ -12,17 +12,19 @@
package cmrdr package cmrdr
import "time"
// Stream represents a camera's RTSP stream // Stream represents a camera's RTSP stream
type Stream struct { type Stream struct {
Device string Device string `json:"device"`
Username string Username string `json:"username"`
Password string Password string `json:"password"`
Route string Route string `json:"route"`
Address string `validate:"required"` Address string `json:"address" validate:"required"`
Port uint `validate:"required"` Port uint `json:"port" validate:"required"`
CredentialsFound bool CredentialsFound bool `json:"credentials_found"`
RouteFound bool RouteFound bool `json:"route_found"`
} }
// Credentials is a map of credentials // Credentials is a map of credentials
@@ -36,3 +38,14 @@ type Credentials struct {
// Routes is a slice of Routes // Routes is a slice of Routes
// ['/live.sdp', '/media.amp', ...] // ['/live.sdp', '/media.amp', ...]
type Routes []string type Routes []string
// Options contains all options needed to launch a complete cameradar scan
type Options struct {
Target string `json:"target" validate:"required"`
Ports string `json:"ports"`
OutputFile string `json:"output_file"`
Routes Routes `json:"routes"`
Credentials Credentials `json:"credentials"`
Speed int `json:"speed"`
Timeout time.Duration `json:"timeout"`
}
+4 -2
View File
@@ -12,6 +12,8 @@
package jsonrpc2 package jsonrpc2
import "github.com/EtixLabs/cameradar"
// http://www.jsonrpc.org/specification // http://www.jsonrpc.org/specification
const ( const (
ParseError = -32700 // Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text. ParseError = -32700 // Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.
@@ -38,14 +40,14 @@ const (
type Request struct { type Request struct {
JSONRPC string `json:"jsonrpc" validate:"eq=2.0"` JSONRPC string `json:"jsonrpc" validate:"eq=2.0"`
Method string `json:"method" validate:"required"` Method string `json:"method" validate:"required"`
Params string `json:"params" validate:"required"` Params cmrdr.Options `json:"params" validate:"required"`
ID string `json:"id"` ID string `json:"id"`
} }
// Response represents a JSONRPC response // Response represents a JSONRPC response
type Response struct { type Response struct {
JSONRPC string `json:"jsonrpc" validate:"eq=2.0"` JSONRPC string `json:"jsonrpc" validate:"eq=2.0"`
Result string `json:"result"` Result []cmrdr.Stream `json:"result"`
Error Error `json:"error"` Error Error `json:"error"`
ID string `json:"id"` ID string `json:"id"`
} }
+72 -26
View File
@@ -33,8 +33,12 @@ func (c *Cameradar) handleRequest(message string) {
Message: jsonrpc2.ParseErrorMessage, Message: jsonrpc2.ParseErrorMessage,
Data: err.Error(), Data: err.Error(),
} }
c.respondToClient(ret, "", JSONRPCErr)
return
} }
println("1")
validate := v.New() validate := v.New()
err = validate.Struct(request) err = validate.Struct(request)
if err != nil { if err != nil {
@@ -43,36 +47,32 @@ func (c *Cameradar) handleRequest(message string) {
Message: jsonrpc2.InvalidRequestMessage, Message: jsonrpc2.InvalidRequestMessage,
Data: err.Error(), Data: err.Error(),
} }
c.respondToClient(ret, request.ID, JSONRPCErr)
return
} }
println("1")
var options Options c.SetOptions(request.Params)
err = json.Unmarshal([]byte(request.Params), &options) println("2")
if err != nil {
JSONRPCErr = jsonrpc2.Error{
Code: jsonrpc2.InvalidParams,
Message: jsonrpc2.InvalidParamsMessage,
Data: err.Error(),
}
}
c.SetOptions(options)
switch request.Method { switch request.Method {
case "discover": case "discover":
ret, err = c.Discover() ret, err = c.Discover()
case "attack_credentials": case "attack_credentials":
ret, err = c.Discover() ret, err = c.AttackCredentials()
case "attack_routes": case "attack_route":
ret, err = c.Discover() ret, err = c.AttackRoute()
case "discover_and_attack": case "discover_and_attack":
ret, err = c.DiscoverAndAttack() c.discoverAndAttack(request.ID)
return
default: default:
JSONRPCErr = jsonrpc2.Error{ JSONRPCErr = jsonrpc2.Error{
Code: jsonrpc2.MethodNotFound, Code: jsonrpc2.MethodNotFound,
Message: jsonrpc2.MethodNotFoundMessage, Message: jsonrpc2.MethodNotFoundMessage,
Data: err.Error(), Data: "method" + request.Method + "not found",
} }
} }
println("3")
if err != nil { if err != nil {
JSONRPCErr = jsonrpc2.Error{ JSONRPCErr = jsonrpc2.Error{
Code: jsonrpc2.InternalError, Code: jsonrpc2.InternalError,
@@ -81,18 +81,64 @@ func (c *Cameradar) handleRequest(message string) {
} }
} }
result, err := json.Marshal(ret) println("4")
if err != nil { c.respondToClient(ret, request.ID, JSONRPCErr)
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) { func (c *Cameradar) discoverAndAttack(ID string) {
var JSONRPCErr jsonrpc2.Error
streams, err := c.Discover()
if err != nil {
c.respondToClient(streams, ID, jsonrpc2.Error{
Code: jsonrpc2.InternalError,
Message: jsonrpc2.InternalErrorMessage,
Data: err.Error(),
})
return
}
c.respondToClient(streams, ID, JSONRPCErr)
streams, err = c.AttackRoute()
if err != nil {
c.respondToClient(streams, ID, jsonrpc2.Error{
Code: jsonrpc2.InternalError,
Message: jsonrpc2.InternalErrorMessage,
Data: err.Error(),
})
return
}
c.respondToClient(streams, ID, JSONRPCErr)
streams, err = c.AttackCredentials()
if err != nil {
c.respondToClient(streams, ID, jsonrpc2.Error{
Code: jsonrpc2.InternalError,
Message: jsonrpc2.InternalErrorMessage,
Data: err.Error(),
})
return
}
c.respondToClient(streams, ID, JSONRPCErr)
for _, stream := range streams {
if stream.RouteFound == false {
streams, err = c.AttackCredentials()
if err != nil {
c.respondToClient(streams, ID, jsonrpc2.Error{
Code: jsonrpc2.InternalError,
Message: jsonrpc2.InternalErrorMessage,
Data: err.Error(),
})
return
}
c.respondToClient(streams, ID, JSONRPCErr)
return
}
}
}
func (c *Cameradar) respondToClient(result []cmrdr.Stream, ID string, JSONRPCErr jsonrpc2.Error) {
println(result) println(result)
r := jsonrpc2.Response{ r := jsonrpc2.Response{
JSONRPC: "2.0", JSONRPC: "2.0",
+21 -44
View File
@@ -24,23 +24,12 @@ import (
type Cameradar struct { type Cameradar struct {
Streams []cmrdr.Stream Streams []cmrdr.Stream
options *Options options *cmrdr.Options
toClient chan<- string toClient chan<- string
fromClient <-chan string fromClient <-chan string
} }
// Options contains all options needed to launch a complete cameradar scan
type Options struct {
Target string
Ports string
OutputFile string
Routes cmrdr.Routes
Credentials cmrdr.Credentials
Speed int
Timeout time.Duration
}
// New instanciates a new Cameradar service // New instanciates a new Cameradar service
func New(routesFilePath, credentialsFilePath string, fromClient <-chan string, toClient chan<- string) (*Cameradar, error) { func New(routesFilePath, credentialsFilePath string, fromClient <-chan string, toClient chan<- string) (*Cameradar, error) {
routes, err := cmrdr.LoadRoutes(routesFilePath) routes, err := cmrdr.LoadRoutes(routesFilePath)
@@ -55,10 +44,11 @@ func New(routesFilePath, credentialsFilePath string, fromClient <-chan string, t
cameradar := &Cameradar{ cameradar := &Cameradar{
Streams: nil, Streams: nil,
options: &Options{ options: &cmrdr.Options{
Ports: "554,8554", Ports: "554,8554",
Routes: routes, Routes: routes,
Credentials: credentials, Credentials: credentials,
OutputFile: "/tmp/cameradar_nmap_result.xml",
Speed: 4, Speed: 4,
Timeout: 2000, Timeout: 2000,
}, },
@@ -75,38 +65,11 @@ func New(routesFilePath, credentialsFilePath string, fromClient <-chan string, t
// using the instructions received over websocket // using the instructions received over websocket
func (c *Cameradar) Run() { func (c *Cameradar) Run() {
for { for {
msg, ok := <-c.fromClient msg := <-c.fromClient
if !ok {
println("client disconnected")
return
}
go c.handleRequest(msg) go c.handleRequest(msg)
} }
} }
// 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 // Discover launches a Cameradar scan using the service's options
func (c *Cameradar) Discover() ([]cmrdr.Stream, 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) streams, err := cmrdr.Discover(c.options.Target, c.options.Ports, c.options.OutputFile, c.options.Speed, true)
@@ -138,8 +101,22 @@ func (c *Cameradar) AttackCredentials() ([]cmrdr.Stream, error) {
} }
// SetOptions sets all options using an option structure // SetOptions sets all options using an option structure
func (c *Cameradar) SetOptions(options Options) { func (c *Cameradar) SetOptions(options cmrdr.Options) {
c.options = &options c.options.Target = options.Target
if len(options.Ports) > 0 {
c.options.Ports = options.Ports
}
if len(options.OutputFile) > 0 {
c.options.OutputFile = options.OutputFile
}
// TODO: Add custom dictionary support through ws
c.SetSpeed(options.Speed)
c.SetTimeout(options.Timeout)
} }
// SetNmapOutputFile sets the OutputFile option // SetNmapOutputFile sets the OutputFile option
@@ -172,7 +149,7 @@ func (c *Cameradar) SetSpeed(speed int) error {
} }
// SetTimeout sets the Timeout option // SetTimeout sets the Timeout option
func (c *Cameradar) SetTimeout(timeout int) error { func (c *Cameradar) SetTimeout(timeout time.Duration) error {
if timeout < 0 { if timeout < 0 {
return fmt.Errorf("invalid timeout value '%d'. should be superior to 0", timeout) return fmt.Errorf("invalid timeout value '%d'. should be superior to 0", timeout)
} }