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
import "time"
// Stream represents a camera's RTSP stream
type Stream struct {
Device string
Username string
Password string
Route string
Address string `validate:"required"`
Port uint `validate:"required"`
Device string `json:"device"`
Username string `json:"username"`
Password string `json:"password"`
Route string `json:"route"`
Address string `json:"address" validate:"required"`
Port uint `json:"port" validate:"required"`
CredentialsFound bool
RouteFound bool
CredentialsFound bool `json:"credentials_found"`
RouteFound bool `json:"route_found"`
}
// Credentials is a map of credentials
@@ -36,3 +38,14 @@ type Credentials struct {
// Routes is a slice of Routes
// ['/live.sdp', '/media.amp', ...]
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"`
}
+10 -8
View File
@@ -12,6 +12,8 @@
package jsonrpc2
import "github.com/EtixLabs/cameradar"
// 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.
@@ -36,18 +38,18 @@ const (
// 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"`
JSONRPC string `json:"jsonrpc" validate:"eq=2.0"`
Method string `json:"method" validate:"required"`
Params cmrdr.Options `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"`
JSONRPC string `json:"jsonrpc" validate:"eq=2.0"`
Result []cmrdr.Stream `json:"result"`
Error Error `json:"error"`
ID string `json:"id"`
}
// Error represents a JSONRPC response's error
+72 -26
View File
@@ -33,8 +33,12 @@ func (c *Cameradar) handleRequest(message string) {
Message: jsonrpc2.ParseErrorMessage,
Data: err.Error(),
}
c.respondToClient(ret, "", JSONRPCErr)
return
}
println("1")
validate := v.New()
err = validate.Struct(request)
if err != nil {
@@ -43,36 +47,32 @@ func (c *Cameradar) handleRequest(message string) {
Message: jsonrpc2.InvalidRequestMessage,
Data: err.Error(),
}
c.respondToClient(ret, request.ID, JSONRPCErr)
return
}
println("1")
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)
c.SetOptions(request.Params)
println("2")
switch request.Method {
case "discover":
ret, err = c.Discover()
case "attack_credentials":
ret, err = c.Discover()
case "attack_routes":
ret, err = c.Discover()
ret, err = c.AttackCredentials()
case "attack_route":
ret, err = c.AttackRoute()
case "discover_and_attack":
ret, err = c.DiscoverAndAttack()
c.discoverAndAttack(request.ID)
return
default:
JSONRPCErr = jsonrpc2.Error{
Code: jsonrpc2.MethodNotFound,
Message: jsonrpc2.MethodNotFoundMessage,
Data: err.Error(),
Data: "method" + request.Method + "not found",
}
}
println("3")
if err != nil {
JSONRPCErr = jsonrpc2.Error{
Code: jsonrpc2.InternalError,
@@ -81,18 +81,64 @@ func (c *Cameradar) handleRequest(message string) {
}
}
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)
println("4")
c.respondToClient(ret, 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)
r := jsonrpc2.Response{
JSONRPC: "2.0",
+21 -44
View File
@@ -24,23 +24,12 @@ import (
type Cameradar struct {
Streams []cmrdr.Stream
options *Options
options *cmrdr.Options
toClient 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
func New(routesFilePath, credentialsFilePath string, fromClient <-chan string, toClient chan<- string) (*Cameradar, error) {
routes, err := cmrdr.LoadRoutes(routesFilePath)
@@ -55,10 +44,11 @@ func New(routesFilePath, credentialsFilePath string, fromClient <-chan string, t
cameradar := &Cameradar{
Streams: nil,
options: &Options{
options: &cmrdr.Options{
Ports: "554,8554",
Routes: routes,
Credentials: credentials,
OutputFile: "/tmp/cameradar_nmap_result.xml",
Speed: 4,
Timeout: 2000,
},
@@ -75,38 +65,11 @@ func New(routesFilePath, credentialsFilePath string, fromClient <-chan string, t
// using the instructions received over websocket
func (c *Cameradar) Run() {
for {
msg, ok := <-c.fromClient
if !ok {
println("client disconnected")
return
}
msg := <-c.fromClient
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
func (c *Cameradar) Discover() ([]cmrdr.Stream, error) {
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
func (c *Cameradar) SetOptions(options Options) {
c.options = &options
func (c *Cameradar) SetOptions(options cmrdr.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
@@ -172,7 +149,7 @@ func (c *Cameradar) SetSpeed(speed int) error {
}
// SetTimeout sets the Timeout option
func (c *Cameradar) SetTimeout(timeout int) error {
func (c *Cameradar) SetTimeout(timeout time.Duration) error {
if timeout < 0 {
return fmt.Errorf("invalid timeout value '%d'. should be superior to 0", timeout)
}