diff --git a/CHANGELOG b/CHANGELOG index c66826458..2e0b8fb72 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,8 @@ # Nmap Changelog ($Id$); -*-text-*- +o [NSE] Added snmpWalk function to SNMP library and updated scripts to use it + [Patrik] + o Updated IANA IP address space assignment list for random IP (-iR) generation. [Kris] diff --git a/nselib/snmp.lua b/nselib/snmp.lua index 31107b9cb..cee1b06cf 100644 --- a/nselib/snmp.lua +++ b/nselib/snmp.lua @@ -489,3 +489,60 @@ function fetchFirst(response) return nil end end + + +--- Walks the MIB Tree +-- +-- @param socket socket already connected to the server +-- @param base_oid string containing the base object ID to walk +-- @return status true on success, false on failure +-- @return table containing oid and value +function snmpWalk( socket, base_oid ) + + local snmp_table = {} + local oid = base_oid + local status, err, payload + + while ( true ) do + + local value, response, snmpdata, options, item = nil, nil, nil, {}, {} + options.reqId = 28428 -- unnecessary? + payload = snmp.encode( snmp.buildPacket( snmp.buildGetNextRequest(options, oid) ) ) + + status, err = socket:send(payload) + if ( not( status ) ) then + stdnse.print_debug("snmp.snmpWalk: Send failed") + return false, err + end + + status, response = socket:receive_bytes(1) + if ( not( status ) ) then + -- Unless we don't have a usefull error message, don't report it + if ( response ~= "ERROR" ) then + stdnse.print_debug("snmp.snmpWalk: Received no answer (%s)", response) + return false, response + end + return false, nil + end + + snmpdata = snmp.fetchResponseValues( response ) + + value = snmpdata[1][1] + oid = snmpdata[1][2] + + if not oid:match( base_oid ) or base_oid == oid then + break + end + + item.oid = oid + item.value = value + + table.insert( snmp_table, item ) + + end + + snmp_table.baseoid = base_oid + + return true, snmp_table + +end diff --git a/scripts/snmp-interfaces.nse b/scripts/snmp-interfaces.nse index 29c67b2b0..22130cbbc 100644 --- a/scripts/snmp-interfaces.nse +++ b/scripts/snmp-interfaces.nse @@ -19,7 +19,8 @@ dependencies = {"snmp-brute"} -- code borrowed heavily from Patrik Karlsson's excellent snmp scripts -- Created 03/03/2010 - v0.1 - created by Thomas Buchanan --- 03/05/2010 - v0.2 - Reworked output slighty, moved iana_types to script scope. Suggested by David Fifield +-- Revised 03/05/2010 - v0.2 - Reworked output slighty, moved iana_types to script scope. Suggested by David Fifield +-- Revised 04/11/2010 - v0.2 - moved snmp_walk to snmp library require "shortport" require "snmp" @@ -70,51 +71,6 @@ local iana_types = { "other", "regular1822", "hdh1822", "ddnX25", "rfc877x25", " "x86Laps", "wwanPP", "wwanPP2", "voiceEBS", "ifPwType", "ilan", "pip", "aluELP", "gpon", "vdsl2", "capwapDot11Profile", "capwapDot11Bss", "capwapWtpVirtualRadio" } ---- Walks the MIB Tree --- --- @param socket socket already connected to the server --- @param base_oid string containing the base object ID to walk --- @return table containing oid and value -function snmp_walk( socket, base_oid ) - - local catch = function() socket:close() end - local try = nmap.new_try(catch) - - local snmp_table = {} - local oid = base_oid - - while ( true ) do - - local value, response, snmpdata, options, item = nil, nil, nil, {}, {} - options.reqId = 28428 -- unnecessary? - payload = snmp.encode( snmp.buildPacket( snmp.buildGetNextRequest(options, oid) ) ) - - try(socket:send(payload)) - response = try( socket:receive_bytes(1) ) - - snmpdata = snmp.fetchResponseValues( response ) - - value = snmpdata[1][1] - oid = snmpdata[1][2] - - if not oid:match( base_oid ) or base_oid == oid then - break - end - - item.oid = oid - item.value = value - - table.insert( snmp_table, item ) - - end - - socket:close() - snmp_table.baseoid = base_oid - - return snmp_table - -end - --- Gets a value for the specified oid -- -- @param tbl table containing oid and value @@ -396,14 +352,16 @@ action = function(host, port) local ip_oid = "1.3.6.1.2.1.4.20" local interfaces = {} local ips = {} + local status socket:set_timeout(5000) try(socket:connect(host.ip, port.number, "udp")) -- retreive network interface information from IF-MIB - interfaces = snmp_walk( socket, if_oid ) - - if ( interfaces == nil ) or ( #interfaces == 0 ) then + status, interfaces = snmp.snmpWalk( socket, if_oid ) + socket:close() + + if (not(status)) or ( interfaces == nil ) or ( #interfaces == 0 ) then return end @@ -414,10 +372,10 @@ action = function(host, port) -- retreive IP address information from IP-MIB try(socket:connect(host.ip, port.number, "udp")) - ips = snmp_walk( socket, ip_oid ) + status, ips = snmp.snmpWalk( socket, ip_oid ) -- associate that IP address information with the correct interface - if ( ips ~= nil ) and ( #ips ~= 0 ) then + if (not(status)) or ( ips ~= nil ) and ( #ips ~= 0 ) then interfaces = process_ips( interfaces, ips ) end diff --git a/scripts/snmp-netstat.nse b/scripts/snmp-netstat.nse index 21235ca9d..231dbd0e9 100644 --- a/scripts/snmp-netstat.nse +++ b/scripts/snmp-netstat.nse @@ -22,49 +22,31 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"default", "discovery", "safe"} dependencies = {"snmp-brute"} --- Version 0.1 +-- Version 0.2 -- Created 01/19/2010 - v0.1 - created by Patrik Karlsson +-- Revised 04/11/2010 - v0.2 - moved snmp_walk to snmp library require "shortport" require "snmp" portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"}) ---- Walks the MIB Tree +--- Processes the table and creates the script output -- --- @param socket socket already connected to the server --- @param base_oid string containing the base object ID to walk --- @return table containing oid and value -function snmp_walk( socket, base_oid ) - - local catch = function() socket:close() end - local try = nmap.new_try(catch) +-- @param tbl table containing oid and value +-- @param prefix string containing either "UDP" or "TCP" +-- @param base_oid string containing the value of the base_oid of the walk +-- @return table suitable for stdnse.format_output +function process_answer( tbl, prefix, base_oid ) - local snmp_table = {} - local oid = base_oid - - while ( true ) do - - local value, response, snmpdata, options, item = nil, nil, nil, {}, {} - options.reqId = 28428 -- unnecessary? - payload = snmp.encode( snmp.buildPacket( snmp.buildGetNextRequest(options, oid) ) ) + local new_tab = {} - try(socket:send(payload)) - response = try( socket:receive_bytes(1) ) - - snmpdata = snmp.fetchResponseValues( response ) - - value = snmpdata[1][1] - oid = snmpdata[1][2] - - if not oid:match( base_oid ) or base_oid == oid then - break - end - - local lip = oid:match( "^" .. base_oid .. "%.(%d+%.%d+%.%d+%.%d+)") or "" - local lport = oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.(%d+)") - local fip = oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.%d+%.(%d+%.%d+%.%d+%.%d+)") or "*:*" - local fport = oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.(%d+)") + for _, v in ipairs( tbl ) do + local lip = v.oid:match( "^" .. base_oid .. "%.(%d+%.%d+%.%d+%.%d+)") or "" + local lport = v.oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.(%d+)") + local fip = v.oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.%d+%.(%d+%.%d+%.%d+%.%d+)") or "*:*" + local fport = v.oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.(%d+)") + local value if lport and lport ~= "0" then lip = lip .. ":" .. lport @@ -76,30 +58,7 @@ function snmp_walk( socket, base_oid ) value = string.format("%-20s %s", lip, fip ) - - item.oid = oid - item.value = value - - table.insert( snmp_table, item ) - - end - - snmp_table.baseoid = base_oid - - return snmp_table - -end - ---- Processes the table and creates the script output --- --- @param tbl table containing oid and value --- @return table suitable for stdnse.format_output -function process_answer( tbl, prefix ) - - local new_tab = {} - - for _, v in ipairs( tbl ) do - table.insert( new_tab, string.format( "%-4s %s", prefix, v.value ) ) + table.insert( new_tab, string.format( "%-4s %s", prefix, value ) ) end return new_tab @@ -122,19 +81,21 @@ action = function(host, port) local tcp_oid = "1.3.6.1.2.1.6.13.1.1" local udp_oid = "1.3.6.1.2.1.7.5.1.1" local netstat = {} + local status, tcp, udp socket:set_timeout(5000) try(socket:connect(host.ip, port.number, "udp")) - local tcp = snmp_walk( socket, tcp_oid ) - local udp = snmp_walk( socket, udp_oid ) - + status, tcp = snmp.snmpWalk( socket, tcp_oid ) + status, udp = snmp.snmpWalk( socket, udp_oid ) + socket:close() + if ( tcp == nil ) or ( #tcp == 0 ) or ( udp==nil ) or ( #udp == 0 ) then return end - tcp = process_answer(tcp, "TCP") - udp = process_answer(udp, "UDP") + tcp = process_answer(tcp, "TCP", tcp_oid) + udp = process_answer(udp, "UDP", udp_oid) netstat = table_merge( tcp, udp ) nmap.set_port_state(host, port, "open") diff --git a/scripts/snmp-processes.nse b/scripts/snmp-processes.nse index 731d22174..04df8e2cc 100644 --- a/scripts/snmp-processes.nse +++ b/scripts/snmp-processes.nse @@ -30,61 +30,17 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"default", "discovery", "safe"} dependencies = {"snmp-brute"} --- Version 0.3 +-- Version 0.4 -- Created 01/15/2010 - v0.1 - created by Patrik Karlsson -- Revised 01/19/2010 - v0.2 - fixed loop that would occure if a mib did not exist --- Revised 01/19/2010 - v0.2 - removed debugging output and renamed file +-- Revised 01/19/2010 - v0.3 - removed debugging output and renamed file +-- Revised 04/11/2010 - v0.4 - moved snmp_walk to snmp library require "shortport" require "snmp" portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"}) ---- Walks the MIB Tree --- --- @param socket socket already connected to the server --- @param base_oid string containing the base object ID to walk --- @return table containing oid and value -function snmp_walk( socket, base_oid ) - - local catch = function() socket:close() end - local try = nmap.new_try(catch) - - local snmp_table = {} - local oid = base_oid - - while ( true ) do - - local value, response, snmpdata, options, item = nil, nil, nil, {}, {} - options.reqId = 28428 -- unnecessary? - payload = snmp.encode( snmp.buildPacket( snmp.buildGetNextRequest(options, oid) ) ) - - try(socket:send(payload)) - response = try( socket:receive_bytes(1) ) - - snmpdata = snmp.fetchResponseValues( response ) - - value = snmpdata[1][1] - oid = snmpdata[1][2] - - if not oid:match( base_oid ) or base_oid == oid then - break - end - - item.oid = oid - item.value = value - - table.insert( snmp_table, item ) - - end - - socket:close() - snmp_table.baseoid = base_oid - - return snmp_table - -end - --- Gets a value for the specified oid -- -- @param tbl table containing oid and value @@ -157,13 +113,15 @@ action = function(host, port) local try = nmap.new_try(catch) local data, snmpoid = nil, "1.3.6.1.2.1.25.4.2" local shares = {} - + local status + socket:set_timeout(5000) try(socket:connect(host.ip, port.number, "udp")) - shares = snmp_walk( socket, snmpoid ) + status, shares = snmp.snmpWalk( socket, snmpoid ) + socket:close() - if ( shares == nil ) or ( #shares == 0 ) then + if (not(status)) or ( shares == nil ) or ( #shares == 0 ) then return end diff --git a/scripts/snmp-win32-services.nse b/scripts/snmp-win32-services.nse index 0a380fcf5..e34e7f7d7 100644 --- a/scripts/snmp-win32-services.nse +++ b/scripts/snmp-win32-services.nse @@ -24,59 +24,16 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"default", "discovery", "safe"} dependencies = {"snmp-brute"} --- Version 0.2 +-- Version 0.3 -- Created 01/15/2010 - v0.1 - created by Patrik Karlsson -- Revised 01/19/2010 - v0.2 - fixed loop that would occure if a mib did not exist +-- Revised 04/11/2010 - v0.3 - moved snmp_walk to snmp library require "shortport" require "snmp" portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"}) ---- Walks the MIB Tree --- --- @param socket socket already connected to the server --- @param base_oid string containing the base object ID to walk --- @return table containing oid and value -function snmp_walk( socket, base_oid ) - - local catch = function() socket:close() end - local try = nmap.new_try(catch) - - local snmp_table = {} - local oid = base_oid - - while ( true ) do - - local value, response, snmpdata, options, item = nil, nil, nil, {}, {} - options.reqId = 28428 -- unnecessary? - payload = snmp.encode( snmp.buildPacket( snmp.buildGetNextRequest(options, oid) ) ) - - try(socket:send(payload)) - response = try( socket:receive_bytes(1) ) - - snmpdata = snmp.fetchResponseValues( response ) - - value = snmpdata[1][1] - oid = snmpdata[1][2] - - if not oid:match( base_oid ) or base_oid == oid then - break - end - - item.oid = oid - item.value = value - - table.insert( snmp_table, item ) - - end - - socket:close() - snmp_table.baseoid = base_oid - - return snmp_table - -end --- Processes the table and creates the script output -- @@ -103,13 +60,15 @@ action = function(host, port) local try = nmap.new_try(catch) local snmpoid = "1.3.6.1.4.1.77.1.2.3.1.1" local services = {} + local status socket:set_timeout(5000) try(socket:connect(host.ip, port.number, "udp")) - services = snmp_walk( socket, snmpoid ) + status, services = snmp.snmpWalk( socket, snmpoid ) + socket:close() - if ( services == nil ) or ( #services == 0 ) then + if ( not(status) ) or ( services == nil ) or ( #services == 0 ) then return end diff --git a/scripts/snmp-win32-shares.nse b/scripts/snmp-win32-shares.nse index 389da10ba..5b3b41bdf 100644 --- a/scripts/snmp-win32-shares.nse +++ b/scripts/snmp-win32-shares.nse @@ -17,60 +17,16 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"default", "discovery", "safe"} dependencies = {"snmp-brute"} --- Version 0.2 +-- Version 0.3 -- Created 01/15/2010 - v0.1 - created by Patrik Karlsson -- Revised 01/19/2010 - v0.2 - fixed loop that would occure if a mib did not exist +-- Revised 04/11/2010 - v0.3 - moved snmp_walk to snmp library require "shortport" require "snmp" portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"}) ---- Walks the MIB Tree --- --- @param socket socket already connected to the server --- @param base_oid string containing the base object ID to walk --- @return table containing oid and value -function snmp_walk( socket, base_oid ) - - local catch = function() socket:close() end - local try = nmap.new_try(catch) - - local snmp_table = {} - local oid = base_oid - - while ( true ) do - - local value, response, snmpdata, options, item = nil, nil, nil, {}, {} - options.reqId = 28428 -- unnecessary? - payload = snmp.encode( snmp.buildPacket( snmp.buildGetNextRequest(options, oid) ) ) - - try(socket:send(payload)) - response = try( socket:receive_bytes(1) ) - - snmpdata = snmp.fetchResponseValues( response ) - - value = snmpdata[1][1] - oid = snmpdata[1][2] - - if not oid:match( base_oid ) or base_oid == oid then - break - end - - item.oid = oid - item.value = value - - table.insert( snmp_table, item ) - - end - - socket:close() - snmp_table.baseoid = base_oid - - return snmp_table - -end - --- Gets a value for the specified oid -- -- @param tbl table containing oid and value @@ -127,10 +83,11 @@ action = function(host, port) socket:set_timeout(5000) try(socket:connect(host.ip, port.number, "udp")) - shares = snmp_walk( socket, snmpoid ) + status, shares = snmp.snmpWalk( socket, snmpoid ) + socket:close() - if ( shares == nil ) or ( #shares == 0 ) then - return + if (not(status)) or ( shares == nil ) or ( #shares == 0 ) then + return shares end shares = process_answer( shares ) diff --git a/scripts/snmp-win32-software.nse b/scripts/snmp-win32-software.nse index 4f59d4a14..1d9da6200 100644 --- a/scripts/snmp-win32-software.nse +++ b/scripts/snmp-win32-software.nse @@ -18,61 +18,16 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"default", "discovery", "safe"} dependencies = {"snmp-brute"} --- Version 0.2 +-- Version 0.3 -- Created 01/15/2010 - v0.1 - created by Patrik Karlsson -- Revised 01/19/2010 - v0.2 - fixed loop that would occure if a mib did not exist +-- Revised 04/11/2010 - v0.3 - moved snmp_walk to snmp library require "shortport" require "snmp" portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"}) - ---- Walks the MIB Tree --- --- @param socket socket already connected to the server --- @param base_oid string containing the base object ID to walk --- @return table containing oid and value -function snmp_walk( socket, base_oid ) - - local catch = function() socket:close() end - local try = nmap.new_try(catch) - - local snmp_table = {} - local oid = base_oid - - while ( true ) do - - local value, response, snmpdata, options, item = nil, nil, nil, {}, {} - options.reqId = 28428 -- unnecessary? - payload = snmp.encode( snmp.buildPacket( snmp.buildGetNextRequest(options, oid) ) ) - - try(socket:send(payload)) - response = try( socket:receive_bytes(1) ) - - snmpdata = snmp.fetchResponseValues( response ) - - value = snmpdata[1][1] - oid = snmpdata[1][2] - - if not oid:match( base_oid ) or base_oid == oid then - break - end - - item.oid = oid - item.value = value - - table.insert( snmp_table, item ) - - end - - socket:close() - snmp_table.baseoid = base_oid - - return snmp_table - -end - --- Gets a value for the specified oid -- -- @param tbl table containing oid and value @@ -128,13 +83,15 @@ action = function(host, port) local try = nmap.new_try(catch) local data, snmpoid = nil, "1.3.6.1.2.1.25.6.3.1" local sw = {} + local status socket:set_timeout(5000) try(socket:connect(host.ip, port.number, "udp")) - sw = snmp_walk( socket, snmpoid ) + status, sw = snmp.snmpWalk( socket, snmpoid ) + socket:close() - if ( sw == nil ) or ( #sw == 0 ) then + if ( not(status) ) or ( sw == nil ) or ( #sw == 0 ) then return end diff --git a/scripts/snmp-win32-users.nse b/scripts/snmp-win32-users.nse index 5525507e7..adacdf0f6 100644 --- a/scripts/snmp-win32-users.nse +++ b/scripts/snmp-win32-users.nse @@ -21,60 +21,16 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"default", "discovery", "safe"} dependencies = {"snmp-brute"} --- Version 0.2 +-- Version 0.3 -- Created 01/15/2010 - v0.1 - created by Patrik Karlsson -- Revised 01/19/2010 - v0.2 - fixed loop that would occure if a mib did not exist +-- Revised 04/11/2010 - v0.3 - moved snmp_walk to snmp library require "shortport" require "snmp" portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"}) ---- Walks the MIB Tree --- --- @param socket socket already connected to the server --- @param base_oid string containing the base object ID to walk --- @return table containing oid and value -function snmp_walk( socket, base_oid ) - - local catch = function() socket:close() end - local try = nmap.new_try(catch) - - local snmp_table = {} - local oid = base_oid - - while ( true ) do - - local value, response, snmpdata, options, item = nil, nil, nil, {}, {} - options.reqId = 28428 -- unnecessary? - payload = snmp.encode( snmp.buildPacket( snmp.buildGetNextRequest(options, oid) ) ) - - try(socket:send(payload)) - response = try( socket:receive_bytes(1) ) - - snmpdata = snmp.fetchResponseValues( response ) - - value = snmpdata[1][1] - oid = snmpdata[1][2] - - if not oid:match( base_oid ) or base_oid == oid then - break - end - - item.oid = oid - item.value = value - - table.insert( snmp_table, item ) - - end - - socket:close() - snmp_table.baseoid = base_oid - - return snmp_table - -end - --- Processes the table and creates the script output -- -- @param tbl table containing oid and value @@ -100,11 +56,18 @@ action = function(host, port) local try = nmap.new_try(catch) local snmpoid = "1.3.6.1.4.1.77.1.2.25" local users = {} + local status socket:set_timeout(5000) try(socket:connect(host.ip, port.number, "udp")) - users = snmp_walk( socket, snmpoid ) + status, users = snmp.snmpWalk( socket, snmpoid ) + socket:close() + + if( not(status) ) then + return + end + users = process_answer( users ) if ( users == nil ) or ( #users == 0 ) then