feat: detect potential incremental routes and bruteforce them

This commit is contained in:
Brendan Le Glaunec
2026-01-28 18:44:11 +01:00
parent 777bd2a488
commit 510a9af2fd
3 changed files with 327 additions and 3 deletions
+99 -3
View File
@@ -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 {