diff --git a/CHANGELOG b/CHANGELOG index 0bc9ad78a..f311a9bfc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ + # Nmap Changelog ($Id$); -*-text-*- +o Improved rpcinfo.nse to better sort and display available RPC + services. [Sven Klemm] + 4.52 o Fixed Nmap Winpcap installer to use CurrentVersion registry key on diff --git a/scripts/rpcinfo.nse b/scripts/rpcinfo.nse index 98892f0a7..4d6551688 100644 --- a/scripts/rpcinfo.nse +++ b/scripts/rpcinfo.nse @@ -16,7 +16,7 @@ local fillrpc = function() local path = nmap.fetchfile("nmap-rpc") if path == nil then - return false + return false, "Can't read from RPC file!" end local file = io.open(path, "r") @@ -52,16 +52,13 @@ action = function(host, port) local try, catch local transaction_id = "nmap" local socket = nmap.new_socket() - local result = "" - - if not fillrpc() then - stdnse.print_debug("rpcinfo: Can't read from RPC file!") - return - end + local result = " \n" catch = function() socket:close() end try = nmap.new_try( catch ) + try( fillrpc() ) + local ntohl = function( s ) return bit.lshift(s:byte(1),24) + bit.lshift(s:byte(2),16) + bit.lshift(s:byte(3),8) + s:byte(4) @@ -83,6 +80,7 @@ action = function(host, port) status, answer_part = socket:receive_bytes( 1 ) if status then answer = answer .. answer_part end end + socket:close() 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 @@ -97,9 +95,9 @@ action = function(host, port) answer_part = answer_part:sub( fragment_length + 4 + 1 ) end + local dir = { udp = {}, tcp = {}} + local rpc_prog, rpc_vers, rpc_proto, rpc_port while answer:byte(4) == 1 and answer:len() >= 20 do - local rpc_prog, rpc_vers, rpc_proto, rpc_port - if result:len() > 0 then result = result .. '\n' end rpc_prog = ntohl( answer:sub(5,8)) rpc_vers = ntohl( answer:sub(9,12)) rpc_proto = ntohl( answer:sub(13,16)) @@ -110,7 +108,34 @@ action = function(host, port) elseif rpc_proto == 17 then rpc_proto = "udp" end - result = result .. string.format("%s(%d) %d/%s",rpc_numbers[rpc_prog] or rpc_prog,rpc_vers,rpc_port,rpc_proto) + 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 + 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 + + for rpc_proto, o in pairs(dir) do + local ports = {} + for rpc_port, i in pairs(o) do table.insert(ports, rpc_port) end + table.sort(ports) + 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) + end + end end end