mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
145 lines
4.2 KiB
Lua
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 |