Increase test coverage, mock libcurl & uniformize error messages

This commit is contained in:
Brendan LE GLAUNEC
2018-02-14 13:49:28 +01:00
committed by Brendan Le Glaunec
parent c1ea6b167c
commit 74672f6625
8 changed files with 478 additions and 203 deletions
+92 -112
View File
@@ -14,120 +14,110 @@ func doNotWrite([]uint8, interface{}) bool {
return true
}
func routeAttack(camera Stream, route string, timeout time.Duration, enableLogs bool) bool {
easy := curl.EasyInit()
defer easy.Cleanup()
func routeAttack(c Curler, camera Stream, route string, timeout time.Duration, enableLogs bool) bool {
attackURL := fmt.Sprintf(
"rtsp://%s:%s@%s:%d/%s",
camera.Username,
camera.Password,
camera.Address,
camera.Port,
route,
)
if easy != nil {
attackURL := fmt.Sprintf(
"rtsp://%s:%s@%s:%d/%s",
camera.Username,
camera.Password,
camera.Address,
camera.Port,
route,
)
if enableLogs {
// Debug logs when logs are enabled
c.Setopt(curl.OPT_VERBOSE, 1)
} else {
// Do not write sdp in stdout
c.Setopt(curl.OPT_WRITEFUNCTION, doNotWrite)
}
if enableLogs {
// Debug logs when logs are enabled
easy.Setopt(curl.OPT_VERBOSE, 1)
} else {
// Do not write sdp in stdout
easy.Setopt(curl.OPT_WRITEFUNCTION, doNotWrite)
}
// Do not send a body in the describe request
c.Setopt(curl.OPT_NOBODY, 1)
// Send a request to the URL of the camera we want to attack
c.Setopt(curl.OPT_URL, attackURL)
// Set the RTSP STREAM URI as the camera URL
c.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
// 2 is CURL_RTSPREQ_DESCRIBE
c.Setopt(curl.OPT_RTSP_REQUEST, 2)
// Set custom timeout
c.Setopt(curl.OPT_TIMEOUT_MS, int(timeout/time.Millisecond))
// Do not send a body in the describe request
easy.Setopt(curl.OPT_NOBODY, 1)
// Send a request to the URL of the camera we want to attack
easy.Setopt(curl.OPT_URL, attackURL)
// Set the RTSP STREAM URI as the camera URL
easy.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
// 2 is CURL_RTSPREQ_DESCRIBE
easy.Setopt(curl.OPT_RTSP_REQUEST, 2)
// Set custom timeout
easy.Setopt(curl.OPT_TIMEOUT_MS, int(timeout/time.Millisecond))
// Perform the request
err := c.Perform()
if err != nil {
fmt.Printf("\nERROR: curl timeout on camera '%s' reached after %s.\nconsider increasing the timeout (-T, --timeout parameter) to at least 5000ms if scanning an unstable network.\n", camera.Address, timeout.String())
return false
}
// Perform the request
err := easy.Perform()
if err != nil {
fmt.Printf("\nERROR: curl timeout on camera '%s' reached after %s.\nconsider increasing the timeout (-T, --timeout parameter) to at least 5000ms if scanning an unstable network.\n", camera.Address, timeout.String())
return false
}
// Get return code for the request
rc, err := c.Getinfo(curl.INFO_RESPONSE_CODE)
if err != nil {
return false
}
// Get return code for the request
rc, err := easy.Getinfo(curl.INFO_RESPONSE_CODE)
if err != nil {
return false
}
// If it's a 401 or 403, it means that the credentials are wrong but the route might be okay
// If it's a 200, the camera is accessed successfully
if rc == 200 || rc == 401 || rc == 403 {
return true
}
// If it's a 401 or 403, it means that the credentials are wrong but the route might be okay
// If it's a 200, the camera is accessed successfully
if rc == 200 || rc == 401 || rc == 403 {
return true
}
return false
}
func credAttack(camera Stream, username string, password string, timeout time.Duration, enableLogs bool) bool {
easy := curl.EasyInit()
defer easy.Cleanup()
func credAttack(c Curler, camera Stream, username string, password string, timeout time.Duration, enableLogs bool) bool {
attackURL := fmt.Sprintf(
"rtsp://%s:%s@%s:%d/%s",
username,
password,
camera.Address,
camera.Port,
camera.Route,
)
if easy != nil {
attackURL := fmt.Sprintf(
"rtsp://%s:%s@%s:%d/%s",
username,
password,
camera.Address,
camera.Port,
camera.Route,
)
if enableLogs {
// Debug logs when logs are enabled
c.Setopt(curl.OPT_VERBOSE, 1)
} else {
// Do not write sdp in stdout
c.Setopt(curl.OPT_WRITEFUNCTION, doNotWrite)
}
if enableLogs {
// Debug logs when logs are enabled
easy.Setopt(curl.OPT_VERBOSE, 1)
} else {
// Do not write sdp in stdout
easy.Setopt(curl.OPT_WRITEFUNCTION, doNotWrite)
}
// Do not send a body in the describe request
c.Setopt(curl.OPT_NOBODY, 1)
// Send a request to the URL of the camera we want to attack
c.Setopt(curl.OPT_URL, attackURL)
// Set the RTSP STREAM URI as the camera URL
c.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
// 2 is CURL_RTSPREQ_DESCRIBE
c.Setopt(curl.OPT_RTSP_REQUEST, 2)
// Set custom timeout
c.Setopt(curl.OPT_TIMEOUT_MS, int(timeout/time.Millisecond))
// Do not send a body in the describe request
easy.Setopt(curl.OPT_NOBODY, 1)
// Send a request to the URL of the camera we want to attack
easy.Setopt(curl.OPT_URL, attackURL)
// Set the RTSP STREAM URI as the camera URL
easy.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
// 2 is CURL_RTSPREQ_DESCRIBE
easy.Setopt(curl.OPT_RTSP_REQUEST, 2)
// Set custom timeout
easy.Setopt(curl.OPT_TIMEOUT_MS, int(timeout/time.Millisecond))
// Perform the request
err := c.Perform()
if err != nil {
fmt.Printf("\nERROR: curl timeout on camera '%s' reached after %s.\nconsider increasing the timeout (-T, --timeout parameter) to at least 5000ms if scanning an unstable network.\n", camera.Address, timeout.String())
return false
}
// Perform the request
err := easy.Perform()
if err != nil {
fmt.Printf("\nERROR: curl timeout on camera '%s' reached after %s.\nconsider increasing the timeout (-T, --timeout parameter) to at least 5000ms if scanning an unstable network.\n", camera.Address, timeout.String())
return false
}
// Get return code for the request
rc, err := c.Getinfo(curl.INFO_RESPONSE_CODE)
if err != nil {
return false
}
// Get return code for the request
rc, err := easy.Getinfo(curl.INFO_RESPONSE_CODE)
if err != nil {
return false
}
// If it's a 404, it means that the route is incorrect but the credentials might be okay
// If it's a 200, the camera is accessed successfully
if rc == 200 || rc == 404 {
return true
}
// If it's a 404, it means that the route is incorrect but the credentials might be okay
// If it's a 200, the camera is accessed successfully
if rc == 200 || rc == 404 {
return true
}
return false
}
func attackCameraCredentials(target Stream, credentials Credentials, resultsChan chan<- Stream, timeout time.Duration, log bool) {
func attackCameraCredentials(c Curler, target Stream, credentials Credentials, resultsChan chan<- Stream, timeout time.Duration, log bool) {
for _, username := range credentials.Usernames {
for _, password := range credentials.Passwords {
ok := credAttack(target, username, password, timeout, log)
ok := credAttack(c, target, username, password, timeout, log)
if ok {
target.CredentialsFound = true
target.Username = username
@@ -141,9 +131,9 @@ func attackCameraCredentials(target Stream, credentials Credentials, resultsChan
resultsChan <- target
}
func attackCameraRoute(target Stream, routes Routes, resultsChan chan<- Stream, timeout time.Duration, log bool) {
func attackCameraRoute(c Curler, target Stream, routes Routes, resultsChan chan<- Stream, timeout time.Duration, log bool) {
for _, route := range routes {
ok := routeAttack(target, route, timeout, log)
ok := routeAttack(c, target, route, timeout, log)
if ok {
target.RouteFound = true
target.Route = route
@@ -157,12 +147,7 @@ func attackCameraRoute(target Stream, routes Routes, resultsChan chan<- Stream,
// AttackCredentials attempts to guess the provided targets' credentials using the given
// dictionary or the default dictionary if none was provided by the user.
func AttackCredentials(targets []Stream, credentials Credentials, timeout time.Duration, log bool) ([]Stream, error) {
err := curl.GlobalInit(curl.GLOBAL_ALL)
if err != nil {
return targets, errors.Wrap(err, "could not initialize curl")
}
func AttackCredentials(c Curler, targets []Stream, credentials Credentials, timeout time.Duration, log bool) ([]Stream, error) {
attacks := make(chan Stream)
defer close(attacks)
@@ -170,10 +155,10 @@ func AttackCredentials(targets []Stream, credentials Credentials, timeout time.D
for _, target := range targets {
err := validate.Struct(target)
if err != nil {
return targets, errors.Wrap(err, "invalid streams")
return targets, errors.Wrap(err, "invalid targets")
}
go attackCameraCredentials(target, credentials, attacks, timeout, log)
go attackCameraCredentials(c, target, credentials, attacks, timeout, log)
}
attackResults := []Stream{}
@@ -197,12 +182,7 @@ func AttackCredentials(targets []Stream, credentials Credentials, timeout time.D
// AttackRoute attempts to guess the provided targets' streaming routes using the given
// dictionary or the default dictionary if none was provided by the user.
func AttackRoute(targets []Stream, routes Routes, timeout time.Duration, log bool) ([]Stream, error) {
err := curl.GlobalInit(curl.GLOBAL_ALL)
if err != nil {
return targets, errors.Wrap(err, "could not initialize curl")
}
func AttackRoute(c Curler, targets []Stream, routes Routes, timeout time.Duration, log bool) ([]Stream, error) {
attacks := make(chan Stream)
defer close(attacks)
@@ -210,10 +190,10 @@ func AttackRoute(targets []Stream, routes Routes, timeout time.Duration, log boo
for _, target := range targets {
err := validate.Struct(target)
if err != nil {
return targets, errors.Wrap(err, "invalid streams")
return targets, errors.Wrap(err, "invalid targets")
}
go attackCameraRoute(target, routes, attacks, timeout, log)
go attackCameraRoute(c, target, routes, attacks, timeout, log)
}
attackResults := []Stream{}