mirror of
https://github.com/nmap/nmap.git
synced 2025-12-09 14:11:29 +00:00
Added sip-call-spoof script which spoofs a call to a SIP phone and detects the action taken by the target.
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
# Nmap Changelog ($Id$); -*-text-*-
|
||||
o [NSE] Added sip-call-spoof script which spoofs a call to a SIP phone and
|
||||
detects the action taken by the target. [Hani Benhabiles]
|
||||
|
||||
o [NSOCK] Modified multiple scripts that operated against HTTP based services
|
||||
so as to remove false positives that were generated when the target service
|
||||
answers with a 200 response to all requests. [Tom Sellers]
|
||||
|
||||
@@ -317,6 +317,7 @@ Entry { filename = "rtsp-url-brute.nse", categories = { "brute", "intrusive", }
|
||||
Entry { filename = "samba-vuln-cve-2012-1182.nse", categories = { "intrusive", "vuln", } }
|
||||
Entry { filename = "servicetags.nse", categories = { "default", "discovery", "safe", } }
|
||||
Entry { filename = "sip-brute.nse", categories = { "brute", "intrusive", } }
|
||||
Entry { filename = "sip-call-spoof.nse", categories = { "discovery", "intrusive", } }
|
||||
Entry { filename = "sip-enum-users.nse", categories = { "auth", "intrusive", } }
|
||||
Entry { filename = "skypev2-version.nse", categories = { "version", } }
|
||||
Entry { filename = "smb-brute.nse", categories = { "brute", "intrusive", } }
|
||||
|
||||
174
scripts/sip-call-spoof.nse
Normal file
174
scripts/sip-call-spoof.nse
Normal file
@@ -0,0 +1,174 @@
|
||||
local shortport = require "shortport"
|
||||
local sip = require "sip"
|
||||
local stdnse = require "stdnse"
|
||||
local table = require "table"
|
||||
|
||||
description = [[
|
||||
Spoofs a call to a SIP phone and detects the action taken by the target.
|
||||
|
||||
This works by sending a fake sip invite request to the target phone and checking
|
||||
the responses. A response with status code 180 means that the phone is ringing.
|
||||
The script waits for the next responses until timeout is reached or a special
|
||||
response is received. Special responses include: Busy (486), Decline (603),
|
||||
Timeout (408) or Hang up (200).
|
||||
]]
|
||||
|
||||
---
|
||||
--@args sip-call-spoof.ua Source application's user agent. Defaults to
|
||||
-- <code>Ekiga</code>.
|
||||
--
|
||||
--@args sip-call-spoof.from Caller user ID. Defaults to <code>Home</code>.
|
||||
--
|
||||
--@args sip-call-spoof.extension SIP Extension to send request from. Defaults to
|
||||
-- <code>100</code>.
|
||||
--
|
||||
--@args sip-call-spoof.src Source address to spoof.
|
||||
--
|
||||
--@args sip-call-spoof.timeout Time to wait for a response. Defaults to
|
||||
-- <code>5</code> seconds.
|
||||
--
|
||||
-- @usage
|
||||
-- nmap --script=sip-call-spoof -sU -p 5060 <targets>
|
||||
-- nmap --script=sip-call-spoof -sU -p 5060 --script-args
|
||||
-- 'sip-call-spoof.ua=Nmap, sip-call-spoof.from=Boss' <targets>
|
||||
--
|
||||
--@output
|
||||
-- 5060/udp open sip
|
||||
-- | sip-call-spoof:
|
||||
-- |_ Target hung up. (After 10.9 seconds)
|
||||
|
||||
|
||||
author = "Hani Benhabiles"
|
||||
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
|
||||
categories = {"discovery", "intrusive"}
|
||||
|
||||
|
||||
portrule = shortport.port_or_service(5060, "sip", {"tcp", "udp"})
|
||||
|
||||
|
||||
--- Function that sends an invite request with given parameters.
|
||||
-- @arg session SIP Session to use.
|
||||
-- @arg ua User Agent to use.
|
||||
-- @arg from SIP From field.
|
||||
-- @arg src Request source address to spoof.
|
||||
-- @arg extension Request SIP extension.
|
||||
-- @return status True if we got a response, false else.
|
||||
-- @return resp Response table if status is true, error string else.
|
||||
local sendinvite = function(session, ua, from, src, extension)
|
||||
local request = sip.Request:new(sip.Method.INVITE)
|
||||
|
||||
request:setUri("sip:" .. session.sessdata:getServer())
|
||||
request:setUA(ua)
|
||||
if src then
|
||||
session.sessdata:setDomain(src)
|
||||
end
|
||||
session.sessdata:setUsername(extension)
|
||||
session.sessdata:setName(from)
|
||||
request:setSessionData(session.sessdata)
|
||||
|
||||
return session:exch(request)
|
||||
end
|
||||
|
||||
--- Function that waits for certain responses for an amount of time.
|
||||
-- @arg session SIP Session to use.
|
||||
-- @arg timeout Max time to wait for responses other than ringing.
|
||||
-- @return ringing True if we got a ringing response, false else.
|
||||
-- @return responsecode Code for the latest meaningful response.
|
||||
-- could be 180, 200, 486, 408 or 603
|
||||
local waitresponses = function(session,timeout)
|
||||
local response, status, data, responsecode, ringing, waittime
|
||||
local start = nmap.clock_ms()
|
||||
|
||||
while (nmap.clock_ms() - start) < timeout do
|
||||
status, data = session.conn:recv()
|
||||
if status then
|
||||
response = sip.Response:new(data)
|
||||
responsecode = response:getErrorCode()
|
||||
waittime = nmap.clock_ms() - start
|
||||
if responsecode == sip.Error.RING then
|
||||
ringing = true
|
||||
elseif responsecode == sip.Error.BUSY then
|
||||
return ringing, sip.Error.BUSY
|
||||
elseif responsecode == sip.Error.DECLINE then
|
||||
return ringing, sip.Error.DECLINE, waittime
|
||||
elseif responsecode == sip.Error.OK then
|
||||
return ringing, sip.Error.OK, waittime
|
||||
elseif responsecode == sip.Error.TIMEOUT then
|
||||
return ringing, sip.Error.OK
|
||||
end
|
||||
end
|
||||
end
|
||||
if ringing then
|
||||
return ringing, sip.Error.RING
|
||||
end
|
||||
end
|
||||
|
||||
--- Function that spoofs an invite request and listens for responses.
|
||||
-- @arg session SIP Session to use.
|
||||
-- @arg ua User Agent to use.
|
||||
-- @arg from SIP From field.
|
||||
-- @arg src Request source address to spoof.
|
||||
-- @arg extension Request SIP extension.
|
||||
-- @arg timeout Max time to wait for responses other than ringing.
|
||||
-- @return ringing True if we got a ringing response, false else.
|
||||
-- @return responsecode Code for the latest meaningful response.
|
||||
-- could be 180, 200, 486, 408 or 603
|
||||
local invitespoof = function(session, ua, from, src, extension, timeout)
|
||||
|
||||
local status, response = sendinvite(session, ua, from, src, extension)
|
||||
-- check if we got a 100 Trying response.
|
||||
if status and response:getErrorCode() == 100 then
|
||||
-- wait for responses
|
||||
return waitresponses(session, timeout)
|
||||
end
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
local status, session
|
||||
|
||||
local ua = stdnse.get_script_args(SCRIPT_NAME .. ".ua") or "Ekiga"
|
||||
local from = stdnse.get_script_args(SCRIPT_NAME .. ".from") or "Home"
|
||||
local src = stdnse.get_script_args(SCRIPT_NAME .. ".src")
|
||||
local extension = stdnse.get_script_args(SCRIPT_NAME .. ".extension") or 100
|
||||
local timeout = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".timeout"))
|
||||
|
||||
-- Default timeout value = 5 seconds.
|
||||
if timeout then
|
||||
timeout = timeout * 1000
|
||||
else
|
||||
timeout = 5000
|
||||
end
|
||||
|
||||
session = sip.Session:new(host, port)
|
||||
status = session:connect()
|
||||
if not status then
|
||||
return "ERROR: Failed to connect to the SIP server."
|
||||
end
|
||||
|
||||
local ringing, result, waittime = invitespoof(session, ua, from, src, extension, timeout)
|
||||
-- If we get a response, we set the port to open.
|
||||
if result then
|
||||
if nmap.get_port_state(host, port) ~= "open" then
|
||||
nmap.set_port_state(host, port, "open")
|
||||
end
|
||||
end
|
||||
|
||||
-- We check for ringing to skip false positives.
|
||||
if ringing then
|
||||
if result == sip.Error.BUSY then
|
||||
return stdnse.format_output(true, "Target line is busy.")
|
||||
elseif result == sip.Error.DECLINE then
|
||||
return stdnse.format_output(true, ("Target declined the call. (After %.1f seconds)"):format(waittime / 1000))
|
||||
elseif result == sip.Error.OK then
|
||||
return stdnse.format_output(true, ("Target hung up. (After %.1f seconds)"):format(waittime / 1000))
|
||||
elseif result == sip.Error.TIMEOUT then
|
||||
return stdnse.format_output(true, "Ringing, no answer.")
|
||||
elseif result == sip.Error.RING then
|
||||
return stdnse.format_output(true, "Ringing, got no answer. (script timeout)")
|
||||
end
|
||||
else
|
||||
stdnse.print_debug(SCRIPT_NAME .. "Target phone didn't ring.")
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user