Cameradar service scans & attacks over WS
This commit is contained in:
committed by
Brendan Le Glaunec
parent
6ea4f6e123
commit
1dadb93452
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user