mirror of
https://github.com/nmap/nmap.git
synced 2026-10-21 19:32:18 +00:00
Check for non-200 responses that may indicate url is present.
This commit is contained in:
parent
96e6f10b8c
commit
23ed953352
1 changed files with 75 additions and 38 deletions
|
|
@ -8,6 +8,11 @@ local table = require "table"
|
|||
|
||||
description = [[
|
||||
Attempts to enumerate RTSP media URLS by testing for common paths on devices such as surveillance IP cameras.
|
||||
|
||||
The script attempts to discover valid RTSP URLs by sending a DESCRIBE
|
||||
request for each URL in the dictionary. It then parses the response, based
|
||||
on which it determines whether the URL is valid or not.
|
||||
|
||||
]]
|
||||
|
||||
---
|
||||
|
|
@ -18,12 +23,20 @@ Attempts to enumerate RTSP media URLS by testing for common paths on devices suc
|
|||
-- PORT STATE SERVICE
|
||||
-- 554/tcp open rtsp
|
||||
-- | rtsp-url-brute:
|
||||
-- | Discovered URLs
|
||||
-- |_ rtsp://camera.example.com/mpeg4
|
||||
--
|
||||
-- The script attempts to discover valid RTSP URLs by sending a DESCRIBE
|
||||
-- request for each URL in the dictionary. It then parses the response, based
|
||||
-- on which it determines whether the URL is valid or not.
|
||||
-- | discovered:
|
||||
-- | rtsp://camera.example.com/mpeg4
|
||||
-- | other responses:
|
||||
-- | 401:
|
||||
-- |_ rtsp://camera.example.com/live/mpeg4
|
||||
-- @xmloutput
|
||||
-- <table key="discovered">
|
||||
-- <elem>rtsp://camera.example.com/mpeg4</elem>
|
||||
-- </table>
|
||||
-- <table key="other responses">
|
||||
-- <table key="401">
|
||||
-- <elem>rtsp://camera.example.com/live/mpeg4</elem>
|
||||
-- </table>
|
||||
-- </table>
|
||||
--
|
||||
-- @args rtsp-url-brute.urlfile sets an alternate URL dictionary file
|
||||
-- @args rtsp-url-brute.threads sets the maximum number of parallel threads to run
|
||||
|
|
@ -57,6 +70,26 @@ urlIterator = function(fd)
|
|||
return coroutine.wrap( getNextUrl )
|
||||
end
|
||||
|
||||
local function fetch_url(host, port, url)
|
||||
local helper = rtsp.Helper:new(host, port)
|
||||
local status = helper:connect()
|
||||
|
||||
if not status then
|
||||
stdnse.debug2("ERROR: Connecting to RTSP server url: %s", url)
|
||||
return nil
|
||||
end
|
||||
|
||||
local response
|
||||
status, response = helper:describe(url)
|
||||
if not status then
|
||||
stdnse.debug2("ERROR: Sending DESCRIBE request to url: %s", url)
|
||||
return nil, response
|
||||
end
|
||||
|
||||
helper:close()
|
||||
return true, response
|
||||
end
|
||||
|
||||
-- Fetches the next url from the iterator, creates an absolute url and tries
|
||||
-- to fetch it from the RTSP service.
|
||||
-- @param host table containing the host table as received by action
|
||||
|
|
@ -65,30 +98,16 @@ end
|
|||
-- @param result table containing the urls that were successfully retrieved
|
||||
local function processURL(host, port, url_iter, result)
|
||||
local condvar = nmap.condvar(result)
|
||||
local name = stdnse.get_hostname(host)
|
||||
for u in url_iter do
|
||||
local name = ( host.targetname and #host.targetname > 0 ) and host.targetname or
|
||||
( host.name and #host.name > 0 ) and host.name or
|
||||
host.ip
|
||||
local url = ("rtsp://%s%s"):format(name, u)
|
||||
local helper = rtsp.Helper:new(host, port)
|
||||
local status = helper:connect()
|
||||
|
||||
if ( not(status) ) then
|
||||
stdnse.debug2("ERROR: Connecting to RTSP server url: %s", url)
|
||||
local status, response = fetch_url(host, port, url)
|
||||
if not status then
|
||||
table.insert(result, { url = url, status = -1 } )
|
||||
break
|
||||
else
|
||||
table.insert(result, { url = url, status = response.status } )
|
||||
end
|
||||
|
||||
local response
|
||||
status, response = helper:describe(url)
|
||||
if ( not(status) ) then
|
||||
stdnse.debug2("ERROR: Sending DESCRIBE request to url: %s", url)
|
||||
table.insert(result, { url = url, status = -1 } )
|
||||
break
|
||||
end
|
||||
|
||||
table.insert(result, { url = url, status = response.status } )
|
||||
helper:close()
|
||||
end
|
||||
condvar "signal"
|
||||
end
|
||||
|
|
@ -118,6 +137,16 @@ action = function(host, port)
|
|||
return stdnse.format_output(false, ("Could not open the URL dictionary: %s"):format(f))
|
||||
end
|
||||
|
||||
-- Try to see what a nonexistent URL looks like
|
||||
local status, response = fetch_url(
|
||||
host, port, ("rtsp://%s/%s"):format(
|
||||
stdnse.get_hostname(host), stdnse.generate_random_string(14))
|
||||
)
|
||||
local status_404 = 404
|
||||
if status then
|
||||
local status_404 = response.status
|
||||
end
|
||||
|
||||
local threads = {}
|
||||
for t=1, threadcount do
|
||||
local co = stdnse.new_thread(processURL, host, port, url_iter, result)
|
||||
|
|
@ -135,30 +164,38 @@ action = function(host, port)
|
|||
|
||||
-- urls that could not be retrieved due to low level errors, such as
|
||||
-- failure in socket send or receive
|
||||
local failure_urls = { name='An error occurred while testing the following URLs' }
|
||||
local failure_urls = {}
|
||||
|
||||
-- urls that elicited a 200 OK response
|
||||
local success_urls = { name='Discovered URLs' }
|
||||
local success_urls = {}
|
||||
|
||||
-- urls requiring authentication
|
||||
-- local auth_urls = { name='URL requiring authentication' }
|
||||
-- urls that got some non-404-type response
|
||||
local urls_by_code = {}
|
||||
|
||||
for _, r in ipairs(result) do
|
||||
if ( r.status == -1 ) then
|
||||
table.insert(failure_urls, r.url)
|
||||
elseif ( r.status == 200 ) then
|
||||
table.insert(success_urls, r.url)
|
||||
-- elseif ( r.status == 401 ) then
|
||||
-- table.insert(auth_urls, r.url )
|
||||
elseif r.status ~= status_404 then
|
||||
local s = tostring(r.status)
|
||||
urls_by_code[s] = urls_by_code[s] or {}
|
||||
table.insert(urls_by_code[s], r.url)
|
||||
end
|
||||
end
|
||||
|
||||
local result = { success_urls, failure_urls }
|
||||
local output = stdnse.output_table()
|
||||
if next(failure_urls) then
|
||||
output.errors = failure_urls
|
||||
end
|
||||
if next(success_urls) then
|
||||
output.discovered = success_urls
|
||||
end
|
||||
if next(urls_by_code) then
|
||||
output["other responses"] = urls_by_code
|
||||
end
|
||||
|
||||
-- insert our URLs requiring auth ONLY if not ALL urls returned auth
|
||||
--if (#result > #auth_urls) then
|
||||
-- table.insert(result, 2, auth_urls)
|
||||
--end
|
||||
|
||||
return stdnse.format_output(true, result )
|
||||
if #output > 0 then
|
||||
return output
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue