mirror of
https://github.com/nmap/nmap.git
synced 2026-01-20 13:19:01 +00:00
o Updated rpcinfo NSE script to use the new pack/unpack (binlib)
functions, use the new tab library, include better documentation, and fix some bugs. [Sven Klemm]
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
# Nmap Changelog ($Id$); -*-text-*-
|
||||
|
||||
o Updated rpcinfo NSE script to use the new pack/unpack (binlib)
|
||||
functions, use the new tab library, include better documentation, and
|
||||
fix some bugs. [Sven Klemm]
|
||||
|
||||
o Fix a bug in the NSE http library which would cause some scripts to
|
||||
give the error: SCRIPT ENGINE: C:\Program
|
||||
Files\Nmap\nselib/http.lua:77: attempt to call field 'parse' (a nil
|
||||
@@ -21,7 +25,7 @@ o Added new addrow() function to NSE tab library. It allows
|
||||
|
||||
o The NSE http library now supports chunked encoding. [Sven Klemm]
|
||||
|
||||
o Fix a number of NSE scripts which used print_debug()
|
||||
o Fixed a number of NSE scripts which used print_debug()
|
||||
incorrectly. See
|
||||
http://seclists.org/nmap-dev/2008/q3/0470.html. [Sven Klemm].
|
||||
|
||||
|
||||
@@ -1,94 +1,114 @@
|
||||
id = "rpcinfo"
|
||||
---
|
||||
-- Connects to portmapper and fetches a list of all registered programs
|
||||
--
|
||||
--@output
|
||||
-- 111/tcp open rpcbind
|
||||
-- | rpcinfo:
|
||||
-- | 100000 2 111/udp rpcbind
|
||||
-- | 100005 1,2,3 705/udp mountd
|
||||
-- | 100003 2,3,4 2049/udp nfs
|
||||
-- | 100024 1 32769/udp status
|
||||
-- | 100021 1,3,4 32769/udp nlockmgr
|
||||
-- | 100000 2 111/tcp rpcbind
|
||||
-- | 100005 1,2,3 706/tcp mountd
|
||||
-- | 100003 2,3,4 2049/tcp nfs
|
||||
-- | 100024 1 50468/tcp status
|
||||
-- |_ 100021 1,3,4 50468/tcp nlockmgr
|
||||
|
||||
description = "connects to portmapper and prints a list of all registered programs"
|
||||
|
||||
require "shortport"
|
||||
require "datafiles"
|
||||
require "bin"
|
||||
require "bit"
|
||||
require "tab"
|
||||
|
||||
id = "rpcinfo"
|
||||
description = "connects to portmapper and fetches a list of all registered programs"
|
||||
author = "Sven Klemm <sven@c3d2.de>"
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
categories = {"default","safe","discovery"}
|
||||
|
||||
require "comm"
|
||||
require "shortport"
|
||||
require "packet"
|
||||
require "datafiles"
|
||||
|
||||
portrule = shortport.port_or_service(111, "rpcbind")
|
||||
|
||||
--- format a table of version for output
|
||||
--@param version_table table containing the versions
|
||||
--@return string with the formatted versions
|
||||
local format_version = function( version_table )
|
||||
table.sort( version_table )
|
||||
return table.concat( version_table, ',' )
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
local try
|
||||
local transaction_id = "nmap"
|
||||
local result = " \n"
|
||||
local rpc_numbers
|
||||
local socket = nmap.new_socket()
|
||||
socket:set_timeout(1000)
|
||||
local catch = function() socket:close() end
|
||||
local try = nmap.new_try(catch)
|
||||
local rpc_numbers = try(datafiles.parse_rpc())
|
||||
|
||||
try = nmap.new_try()
|
||||
rpc_numbers = try(datafiles.parse_rpc())
|
||||
try(socket:connect(host.ip, port.number))
|
||||
|
||||
local request = string.char(0x80,0,0,40) -- fragment header
|
||||
request = request .. transaction_id -- transaction id
|
||||
request = request .. "\0\0\0\0\0\0\0\2" -- message type: call (0) and rpc version 2
|
||||
request = request .. string.char(0,1,134,160) -- programm portmap (100000)
|
||||
request = request .. "\0\0\0\2\0\0\0\4" -- programm version (2) procedure dump(4)
|
||||
request = request .. "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"-- Credentials and verifier
|
||||
-- build rpc dump call packet
|
||||
local transaction_id = math.random(0x7FFFFFFF)
|
||||
local request = bin.pack('>IIIIIIILL',0x80000028,transaction_id,0,2,100000,2,4,0,0)
|
||||
try(socket:send(request))
|
||||
|
||||
local answer = try(comm.exchange(host, port, request, {timeout=1000}))
|
||||
local answer_part
|
||||
local answer = try(socket:receive_bytes(1))
|
||||
|
||||
local fragment_length = answer:byte(4) + answer:byte(3) * 256 + answer:byte(2) * 65536
|
||||
if answer:sub(5,8) == transaction_id and answer:byte(12) == 1 and answer:byte(16) == 0 and answer:byte(28) == 0 then
|
||||
-- transaction_id matches, message type reply, reply state accepted and accept state executed successfully
|
||||
answer_part = answer
|
||||
answer = answer_part:sub( 28 + 1, fragment_length + 4 )
|
||||
answer_part = answer_part:sub( fragment_length + 4 + 1 )
|
||||
local _,offset,header,length,tx_id,msg_type,reply_state,accept_state,value,payload,last_fragment
|
||||
last_fragment = false; offset = 1; payload = ''
|
||||
|
||||
while answer_part:len() > 0 do -- defragment packet
|
||||
fragment_length = answer_part:byte(4) + answer_part:byte(3) * 256 + answer_part:byte(2) * 65536
|
||||
answer = answer .. answer_part:sub( 5, fragment_length + 4 )
|
||||
answer_part = answer_part:sub( fragment_length + 4 + 1 )
|
||||
-- extract payload from answer and try to receive more packets if header with
|
||||
-- last_fragment set has not been received
|
||||
while not last_fragment do
|
||||
if offset > #answer then
|
||||
answer = answer .. try(socket:receive_bytes(1))
|
||||
end
|
||||
offset,header = bin.unpack('>I',answer,offset)
|
||||
last_fragment = bit.band( header, 0x80000000 ) ~= 0
|
||||
length = bit.band( header, 0x7FFFFFFF )
|
||||
payload = payload .. answer:sub( offset, offset + length - 1 )
|
||||
offset = offset + length
|
||||
end
|
||||
socket:close()
|
||||
|
||||
offset,tx_id,msg_type,reply_state,_,_,accept_state = bin.unpack( '>IIIIII', payload )
|
||||
|
||||
-- transaction_id matches, message type reply, reply state accepted and accept state executed successfully
|
||||
if tx_id == transaction_id and msg_type == 1 and reply_state == 0 and accept_state == 0 then
|
||||
local dir = { udp = {}, tcp = {}}
|
||||
local protocols = {[6]='tcp',[17]='udp'}
|
||||
local rpc_prog, rpc_vers, rpc_proto, rpc_port
|
||||
while answer:byte(4) == 1 and answer:len() >= 20 do
|
||||
rpc_prog = packet.u32( answer, 4 )
|
||||
rpc_vers = packet.u32( answer, 8 )
|
||||
rpc_proto = packet.u32( answer, 12 )
|
||||
rpc_port = packet.u32( answer, 16 )
|
||||
answer = answer:sub(21)
|
||||
if rpc_proto == 6 then
|
||||
rpc_proto = "tcp"
|
||||
elseif rpc_proto == 17 then
|
||||
rpc_proto = "udp"
|
||||
end
|
||||
if not dir[rpc_proto][rpc_port] then dir[rpc_proto][rpc_port] = {} end
|
||||
if not dir[rpc_proto][rpc_port][rpc_prog] then dir[rpc_proto][rpc_port][rpc_prog] = {} end
|
||||
offset, value = bin.unpack('>I',payload,offset)
|
||||
while value == 1 and #payload - offset >= 19 do
|
||||
offset,rpc_prog,rpc_vers,rpc_proto,rpc_port,value = bin.unpack('>IIIII',payload,offset)
|
||||
rpc_proto = protocols[rpc_proto] or tostring( rpc_proto )
|
||||
-- collect data in a table
|
||||
dir[rpc_proto] = dir[rpc_proto] or {}
|
||||
dir[rpc_proto][rpc_port] = dir[rpc_proto][rpc_port] or {}
|
||||
dir[rpc_proto][rpc_port][rpc_prog] = dir[rpc_proto][rpc_port][rpc_prog] or {}
|
||||
table.insert( dir[rpc_proto][rpc_port][rpc_prog], rpc_vers )
|
||||
end
|
||||
|
||||
local format_version = function( version_table )
|
||||
if #version_table == 1 then return version_table[1] end
|
||||
table.sort( version_table )
|
||||
for i=2,#version_table do
|
||||
if version_table[i-1] ~= version_table[i] - 1 then
|
||||
return table.concat( version_table, ',' )
|
||||
end
|
||||
end
|
||||
return string.format('%d-%d',version_table[1],version_table[#version_table])
|
||||
end
|
||||
|
||||
-- format output
|
||||
local output = tab.new(4)
|
||||
for rpc_proto, o in pairs(dir) do
|
||||
-- get list of all used ports
|
||||
local ports = {}
|
||||
for rpc_port, i in pairs(o) do table.insert(ports, rpc_port) end
|
||||
table.sort(ports)
|
||||
|
||||
-- iterate over ports to produce output
|
||||
for i, rpc_port in ipairs(ports) do
|
||||
i = o[rpc_port]
|
||||
for rpc_prog, versions in pairs(o[rpc_port]) do
|
||||
versions = format_version( versions )
|
||||
local name = rpc_numbers[rpc_prog] or ''
|
||||
result = result .. string.format('%d %-5s %5d/%s %s\n',rpc_prog,versions,rpc_port,rpc_proto,name)
|
||||
tab.addrow(output,rpc_prog,format_version(versions),('%5d/%s'):format(rpc_port,rpc_proto),name)
|
||||
end
|
||||
end
|
||||
end
|
||||
return ' \n' .. tab.dump( output )
|
||||
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user