feat: detect potential incremental routes and bruteforce them
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/Ullaakut/cameradar/v6"
|
||||
@@ -232,7 +233,12 @@ func (a Attacker) attackCredentialsForStream(ctx context.Context, target camerad
|
||||
msg := fmt.Sprintf("Credentials found for %s:%d", target.Address.String(), target.Port)
|
||||
a.reporter.Progress(cameradar.StepAttackCredentials, msg)
|
||||
|
||||
return target, nil
|
||||
updated, err := a.tryIncrementalRoutes(ctx, target, target.Route(), true, true)
|
||||
if err != nil {
|
||||
return target, err
|
||||
}
|
||||
|
||||
return updated, nil
|
||||
}
|
||||
time.Sleep(a.attackInterval)
|
||||
}
|
||||
@@ -257,7 +263,7 @@ func (a Attacker) attackRoutesForStream(ctx context.Context, target cameradar.St
|
||||
}
|
||||
if ok {
|
||||
target.RouteFound = true
|
||||
target.Routes = append(target.Routes, "/")
|
||||
target.Routes = appendRouteIfMissing(target.Routes, "/")
|
||||
a.reporter.Progress(cameradar.StepAttackRoutes, fmt.Sprintf("Default route accepted for %s:%d", target.Address.String(), target.Port))
|
||||
return target, nil
|
||||
}
|
||||
@@ -279,8 +285,14 @@ func (a Attacker) attackRoutesForStream(ctx context.Context, target cameradar.St
|
||||
}
|
||||
if ok {
|
||||
target.RouteFound = true
|
||||
target.Routes = append(target.Routes, route)
|
||||
target.Routes = appendRouteIfMissing(target.Routes, route)
|
||||
a.reporter.Progress(cameradar.StepAttackRoutes, fmt.Sprintf("Route found for %s:%d -> %s", target.Address.String(), target.Port, route))
|
||||
|
||||
updated, err := a.tryIncrementalRoutes(ctx, target, route, emitProgress, false)
|
||||
if err != nil {
|
||||
return target, err
|
||||
}
|
||||
target = updated
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,6 +376,90 @@ func (a Attacker) routeAttack(stream cameradar.Stream, route string) (bool, erro
|
||||
return access, nil
|
||||
}
|
||||
|
||||
func (a Attacker) routeAttackWithCredentials(stream cameradar.Stream, route string) (bool, error) {
|
||||
u, urlStr, err := buildRTSPURL(stream, route, stream.Username, stream.Password)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("building rtsp url: %w", err)
|
||||
}
|
||||
|
||||
code, err := a.describeStatus(u)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("performing describe request at %q: %w", urlStr, err)
|
||||
}
|
||||
|
||||
a.reporter.Debug(cameradar.StepAttackRoutes, fmt.Sprintf("DESCRIBE %s RTSP/1.0 > %d", urlStr, code))
|
||||
return code == base.StatusOK, nil
|
||||
}
|
||||
|
||||
func (a Attacker) tryIncrementalRoutes(ctx context.Context,
|
||||
target cameradar.Stream, route string,
|
||||
emitProgress, useCredentials bool,
|
||||
) (cameradar.Stream, error) {
|
||||
match, ok := detectIncrementalRoute(route)
|
||||
if !ok {
|
||||
return target, nil
|
||||
}
|
||||
|
||||
nextNumber := match.number + 1
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return target, ctx.Err()
|
||||
case <-time.After(a.attackInterval):
|
||||
}
|
||||
|
||||
nextRoute := buildIncrementedRoute(match, nextNumber)
|
||||
if slices.Contains(target.Routes, nextRoute) {
|
||||
if !match.isChannel {
|
||||
return target, nil
|
||||
}
|
||||
nextNumber++
|
||||
continue
|
||||
}
|
||||
|
||||
if emitProgress {
|
||||
a.reporter.Progress(cameradar.StepAttackRoutes, cameradar.ProgressTickMessage())
|
||||
}
|
||||
|
||||
ok, err := a.incrementalRouteAttack(target, nextRoute, useCredentials)
|
||||
if err != nil {
|
||||
a.reporter.Debug(cameradar.StepAttackRoutes, fmt.Sprintf("incremental route attempt failed for %s:%d (%s): %v",
|
||||
target.Address.String(),
|
||||
target.Port,
|
||||
nextRoute,
|
||||
err,
|
||||
))
|
||||
return target, nil
|
||||
}
|
||||
if !ok {
|
||||
return target, nil
|
||||
}
|
||||
|
||||
target.RouteFound = true
|
||||
target.Routes = appendRouteIfMissing(target.Routes, nextRoute)
|
||||
a.reporter.Progress(cameradar.StepAttackRoutes, fmt.Sprintf("Incremental route found for %s:%d -> %s", target.Address.String(), target.Port, nextRoute))
|
||||
|
||||
if !match.isChannel {
|
||||
return target, nil
|
||||
}
|
||||
nextNumber++
|
||||
}
|
||||
}
|
||||
|
||||
func (a Attacker) incrementalRouteAttack(stream cameradar.Stream, route string, useCredentials bool) (bool, error) {
|
||||
if useCredentials {
|
||||
return a.routeAttackWithCredentials(stream, route)
|
||||
}
|
||||
return a.routeAttack(stream, route)
|
||||
}
|
||||
|
||||
func appendRouteIfMissing(routes []string, route string) []string {
|
||||
if slices.Contains(routes, route) {
|
||||
return routes
|
||||
}
|
||||
return append(routes, route)
|
||||
}
|
||||
|
||||
func (a Attacker) credAttack(stream cameradar.Stream, username, password string) (bool, error) {
|
||||
u, urlStr, err := buildRTSPURL(stream, stream.Route(), username, password)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user