1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00
Files
nmap/scripts/sip-enum-users.nse

145 lines
4.2 KiB
Lua

description = [[
Attempts to enumerate valid user account using SIP (Session Initiation
Protocol - http://en.wikipedia.org/wiki/Session_Initiation_Protocol).
This protocol is most commonly associated with VoIP
sessions. Currently only the SIP server Asterisk is supported.
* Asterisk
- The script enumerates valid accounts by checking the SIP servers response
to the REGISTER request. If TRYING is returned, the account does not
exist. If REGISTER is returned the account is valid.
]]
---
-- @usage
-- nmap -sU -p 5060 <target> --script=sip-brute
--
-- PORT STATE SERVICE
-- 5060/udp open|filtered sip
-- | sip-enum-users:
-- | Valid SIP accounts
-- | 1000
-- |_ 1001
-- Version 0.1
-- Created 04/03/2011 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"intrusive", "auth"}
require "shortport"
require "sip"
require "unpwdb"
portrule = shortport.port_or_service(5060, "sip", "udp")
-- Send a register request to the server and returned the unparsed response
-- @param session instance of Session class
-- @param username string containing the name of the user
-- @return status true on success false on failure
-- @return response instance of sip.Response (on success)
-- @return err string containing the error message (on failure)
local function register(session, username)
local request = sip.Request:new(sip.Method.REGISTER)
local callid = sip.Util.get_random_string(20)
session.sessdata:setUsername(username)
request:setUri("sip:" .. session.sessdata:getServer() )
request:setSessionData(session.sessdata)
request:setCallId(callid)
request:setExpires(0)
request:setAllow({"PRACK","INVITE","ACK","BYE","CANCEL","UPDATE",
"SUBSCRIBE","NOTIFY","REFER","MESSAGE","OPTIONS"})
request:setContentLength(0)
local status, response = session:exch(request)
if (not(status)) then return false, response end
return true, response
end
-- Confirm the server is a valid and supported one
-- @param host table as passed to the action method
-- @param port table as passed to the action method
-- @return status true on success, false on failure
-- @return header string containing the server name
local function confirmServer(host, port)
local user = "nmap_banner_check"
local session = sip.Session:new( host, port )
local status = session:connect()
if ( not(status) ) then
return "ERROR: Failed to connect to the SIP server"
end
local response
status, response = register(session, user)
if ( status ) then
return true, (
response:getHeader("User-Agent") or
response:getHeader("Server")
)
end
return false
end
-- Asterisk specific function used to check for valid usernames
-- @param session instance of SIP Session
-- @param username string containing the SIP username
-- @return status true on success, false on failure
-- @return err on failure
local function checkAsteriskUsername(session, username)
local status, response = register(session, username)
if ( status and response:getErrorCode() == 401 ) then
return true, "SUCCESS"
end
return false, "FAILURE"
end
-- Table containing a server match and corresponding check function
local detectiontbl = {
{ name="^Asterisk PBX", func=checkAsteriskUsername }
}
action = function(host, port)
local accounts = {}
local status, usernames = unpwdb.usernames()
if ( not(status) ) then return false, "Failed to load usernames" end
local server
status, server = confirmServer( host, port )
if ( not(status) ) then
return "ERROR: Failed to determine server version"
end
local checkUsername
for _, item in ipairs( detectiontbl ) do
if ( server and server:match( item.name ) ) then
checkUsername = item.func
break
end
end
if ( not(checkUsername) ) then return ("ERROR: Unsupported server (%s)"):format((server or "")) end
for username in usernames do
local session = sip.Session:new( host, port )
local status = session:connect()
if ( not(status) ) then
return "ERROR: Failed to connect to the SIP server"
end
local status, err = checkUsername( session, username )
if ( status ) then table.insert( accounts, username ) end
session:close()
end
accounts.name = "Valid SIP accounts"
return stdnse.format_output(true, { accounts } )
end