1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00

Support RPCBIND 3 and 4, not only portmap 2. See #1469

This commit is contained in:
dmiller
2019-04-15 19:35:24 +00:00
parent ef132f2f24
commit 85ec647932
2 changed files with 109 additions and 47 deletions

View File

@@ -121,7 +121,7 @@ local mutex = nmap.mutex("rpc")
-- Supported protocol versions -- Supported protocol versions
RPC_version = { RPC_version = {
["rpcbind"] = { min=2, max=2 }, ["rpcbind"] = { min=2, max=4 },
["nfs"] = { min=1, max=3 }, ["nfs"] = { min=1, max=3 },
["mountd"] = { min=1, max=3 }, ["mountd"] = { min=1, max=3 },
} }
@@ -577,6 +577,16 @@ Portmap =
CALLIT = 5, CALLIT = 5,
}, },
[3] =
{
DUMP = 4,
},
[4] =
{
DUMP = 4,
},
}, },
State = State =
@@ -635,11 +645,13 @@ Portmap =
-- <code> -- <code>
-- table[program_id][protocol]["port"] = <port number> -- table[program_id][protocol]["port"] = <port number>
-- table[program_id][protocol]["version"] = <table of versions> -- table[program_id][protocol]["version"] = <table of versions>
-- table[program_id][protocol]["addr"] = <IP address, for RPCv3 and higher>
-- </code> -- </code>
-- --
-- Where -- Where
-- o program_id is the number associated with the program -- o program_id is the number associated with the program
-- o protocol is either "tcp" or "udp" -- o protocol is one of "tcp", "udp", "tcp6", or "udp6", or another netid
-- reported by the system.
-- --
Dump = function(self, comm) Dump = function(self, comm)
local status, data, packet, response, pos, header local status, data, packet, response, pos, header
@@ -701,16 +713,38 @@ Portmap =
break break
end end
program, version, protocol, port, pos = string.unpack(">I4 I4 I4 I4", data, pos) program, version, pos = string.unpack(">I4 I4", data, pos)
if ( protocol == Portmap.PROTOCOLS.tcp ) then local addr, owner
protocol = "tcp" if comm.version > 2 then
elseif ( protocol == Portmap.PROTOCOLS.udp ) then local len
protocol = "udp" len, pos = string.unpack(">I4", data, pos)
pos, protocol = Util.unmarshall_vopaque(len, data, pos)
len, pos = string.unpack(">I4", data, pos)
pos, addr = Util.unmarshall_vopaque(len, data, pos)
len, pos = string.unpack(">I4", data, pos)
pos, owner = Util.unmarshall_vopaque(len, data, pos)
if protocol:match("^[tu][cd]p6?$") then
-- RFC 5665
local upper, lower
addr, upper, lower = addr:match("^(.-)%.(%d+)%.(%d+)$")
if addr then
port = tonumber(upper) * 0x100 + tonumber(lower)
end
end
else
protocol, port, pos = string.unpack(">I4 I4", data, pos)
if ( protocol == Portmap.PROTOCOLS.tcp ) then
protocol = "tcp"
elseif ( protocol == Portmap.PROTOCOLS.udp ) then
protocol = "udp"
end
end end
program_table[program] = program_table[program] or {} program_table[program] = program_table[program] or {}
program_table[program][protocol] = program_table[program][protocol] or {} program_table[program][protocol] = program_table[program][protocol] or {}
program_table[program][protocol]["port"] = port program_table[program][protocol]["port"] = port
program_table[program][protocol]["addr"] = addr
program_table[program][protocol]["owner"] = owner
program_table[program][protocol]["version"] = program_table[program][protocol]["version"] or {} program_table[program][protocol]["version"] = program_table[program][protocol]["version"] or {}
table.insert( program_table[program][protocol]["version"], version ) table.insert( program_table[program][protocol]["version"], version )
-- parts of the code rely on versions being in order -- parts of the code rely on versions being in order
@@ -2761,7 +2795,8 @@ Helper = {
RpcInfo = function( host, port ) RpcInfo = function( host, port )
local status, result local status, result
local portmap = Portmap:new() local portmap = Portmap:new()
local comm = Comm:new('rpcbind', 2) local pversion = 4
local comm = Comm:new('rpcbind', pversion)
mutex "lock" mutex "lock"
@@ -2775,21 +2810,25 @@ Helper = {
return true, nmap.registry[host.ip]['portmapper'] return true, nmap.registry[host.ip]['portmapper']
end end
status, result = comm:Connect(host, port) while pversion >= 2 do
if (not(status)) then status, result = comm:Connect(host, port)
mutex "done" if (not(status)) then
stdnse.debug4("rpc.Helper.RpcInfo: %s", result) mutex "done"
return status, result stdnse.debug4("rpc.Helper.RpcInfo: %s", result)
end return status, result
end
status, result = portmap:Dump(comm) status, result = portmap:Dump(comm)
comm:Disconnect() comm:Disconnect()
if status then
break
end
stdnse.debug4("rpc.Helper.RpcInfo: %s", result)
pversion = pversion - 1
end
mutex "done" mutex "done"
if (not(status)) then
stdnse.debug4("rpc.Helper.RpcInfo: %s", result)
end
return status, result return status, result
end, end,
@@ -2837,40 +2876,60 @@ Helper = {
return status, portmap_table return status, portmap_table
end end
local info = {}
-- assume failure -- assume failure
status = false status = false
for _, p in ipairs( RPC_PROTOCOLS ) do local tmp = portmap_table[Util.ProgNameToNumber(program)]
local tmp = portmap_table[Util.ProgNameToNumber(program)] if not tmp then
return false, "Program not supported by target"
end
if ( tmp and tmp[p] ) then local info = {}
info = {} local proginfo
local ipv6 = nmap.address_family() == "inet6"
::AF_FALLBACK::
for _, p in ipairs( RPC_PROTOCOLS ) do
if ipv6 then
proginfo = tmp[p .. "6"]
else
proginfo = tmp[p]
end
if proginfo then
info.port = {} info.port = {}
info.port.number = tmp[p].port info.port.number = proginfo.port
info.port.protocol = p info.port.protocol = p
-- choose the highest version available break
if ( not(RPC_version[program]) ) then end
info.version = tmp[p].version[#tmp[p].version] end
status = true if ipv6 and not proginfo then
else -- Fall back to trying IPv4
for i=#tmp[p].version, 1, -1 do ipv6 = false
if ( RPC_version[program].max >= tmp[p].version[i] ) then goto AF_FALLBACK
if ( not(max_version) ) then end
info.version = tmp[p].version[i]
status = true if not proginfo then
break return false, "No transport protocol supported"
else end
if ( max_version >= tmp[p].version[i] ) then
info.version = tmp[p].version[i] -- choose the highest version available
status = true if ( not(RPC_version[program]) ) then
break info.version = proginfo.version[#proginfo.version]
end status = true
end else
for i=#proginfo.version, 1, -1 do
if ( RPC_version[program].max >= proginfo.version[i] ) then
if ( not(max_version) ) then
info.version = proginfo.version[i]
status = true
break
else
if ( max_version >= proginfo.version[i] ) then
info.version = proginfo.version[i]
status = true
break
end end
end end
end end
break
end end
end end

View File

@@ -117,14 +117,17 @@ action = function(host, port)
end end
end end
table.insert( result, ("%-7d %-10s %5d/%s %s"):format(progid, table.concat(v2.version, ","), v2.port, proto, rpc.Util.ProgNumberToName(progid) or "") ) if v2.port then
-- TODO: report other transports that don't have a port; e.g. "local"
table.insert( result, ("%-7d %-10s %5d/%-4s %s"):format(progid, table.concat(v2.version, ","), v2.port, proto, rpc.Util.ProgNumberToName(progid) or "") )
end
end end
end end
table.sort(result) table.sort(result)
if (#result > 0) then if (#result > 0) then
table.insert(result, 1, "program version port/proto service") table.insert(result, 1, "program version port/proto service")
end end
return xmlout, stdnse.format_output( true, result ) return xmlout, stdnse.format_output( true, result )