From d309fecd122a7281b0607a33534314e27c1d4e80 Mon Sep 17 00:00:00 2001 From: dmiller Date: Sun, 2 Feb 2014 15:33:29 +0000 Subject: [PATCH] Re-indent some more scripts. Whitespace-only commit https://secwiki.org/w/Nmap/Code_Standards --- scripts/afp-path-vuln.nse | 212 +++++----- scripts/allseeingeye-info.nse | 216 +++++----- scripts/broadcast-dhcp-discover.nse | 232 +++++----- scripts/broadcast-pim-discovery.nse | 222 +++++----- scripts/broadcast-ping.nse | 320 +++++++------- scripts/broadcast-ripng-discover.nse | 292 ++++++------- scripts/broadcast-wpad-discover.nse | 260 ++++++------ scripts/dns-cache-snoop.nse | 100 ++--- scripts/duplicates.nse | 252 +++++------ scripts/eap-info.nse | 238 +++++------ scripts/firewall-bypass.nse | 400 +++++++++--------- scripts/flume-master-info.nse | 226 +++++----- scripts/ftp-bounce.nse | 330 +++++++-------- scripts/gkrellm-info.nse | 278 ++++++------ scripts/http-form-brute.nse | 288 ++++++------- scripts/http-iis-webdav-vuln.nse | 256 +++++------ scripts/http-passwd.nse | 168 ++++---- scripts/http-rfi-spider.nse | 38 +- scripts/http-sql-injection.nse | 8 +- scripts/http-stored-xss.nse | 322 +++++++------- scripts/http-virustotal.nse | 220 +++++----- scripts/ipidseq.nse | 274 ++++++------ scripts/ipv6-ra-flood.nse | 162 +++---- scripts/irc-unrealircd-backdoor.nse | 252 +++++------ scripts/llmnr-resolve.nse | 254 +++++------ scripts/ms-sql-info.nse | 204 ++++----- scripts/ms-sql-tables.nse | 284 ++++++------- scripts/mysql-info.nse | 190 ++++----- scripts/nbstat.nse | 258 +++++------ scripts/nrpe-enum.nse | 326 +++++++------- scripts/openlookup-info.nse | 344 +++++++-------- scripts/oracle-brute-stealth.nse | 222 +++++----- scripts/oracle-brute.nse | 238 +++++------ scripts/quake3-info.nse | 298 ++++++------- scripts/quake3-master-getservers.nse | 358 ++++++++-------- scripts/rdp-vuln-ms12-020.nse | 274 ++++++------ scripts/rmi-dumpregistry.nse | 92 ++-- scripts/rpc-grind.nse | 362 ++++++++-------- scripts/sip-enum-users.nse | 272 ++++++------ scripts/smb-enum-users.nse | 194 ++++----- scripts/smb-mbenum.nse | 288 ++++++------- scripts/smb-system-info.nse | 274 ++++++------ scripts/snmp-ios-config.nse | 212 +++++----- scripts/socks-open-proxy.nse | 4 +- scripts/ssh2-enum-algos.nse | 140 +++--- scripts/sslv2.nse | 276 ++++++------ scripts/svn-brute.nse | 350 +++++++-------- .../targets-ipv6-multicast-invalid-dst.nse | 270 ++++++------ scripts/targets-ipv6-multicast-slaac.nse | 314 +++++++------- scripts/wdb-version.nse | 288 ++++++------- 50 files changed, 6076 insertions(+), 6076 deletions(-) diff --git a/scripts/afp-path-vuln.nse b/scripts/afp-path-vuln.nse index 8804be8fe..1b00a43fe 100644 --- a/scripts/afp-path-vuln.nse +++ b/scripts/afp-path-vuln.nse @@ -82,26 +82,26 @@ portrule = shortport.portnumber(548, "tcp") -- @return table suitable for stdnse.format_output local function processResponse( tbl, max_count, out, count ) - local out = out or {} - local count = count or 0 + local out = out or {} + local count = count or 0 - for _, v in ipairs(tbl) do - if ( max_count and max_count > 0 and max_count <= count ) then - break - end - if ( v.name ) then - local sfx = ( v.type == 0x80 ) and "/" or "" - table.insert(out, v.name .. sfx ) - count = count + 1 - elseif( type(v) == 'table' ) then - local tmp = {} - table.insert( out, tmp ) - processResponse( v, max_count, tmp, count ) - end - end + for _, v in ipairs(tbl) do + if ( max_count and max_count > 0 and max_count <= count ) then + break + end + if ( v.name ) then + local sfx = ( v.type == 0x80 ) and "/" or "" + table.insert(out, v.name .. sfx ) + count = count + 1 + elseif( type(v) == 'table' ) then + local tmp = {} + table.insert( out, tmp ) + processResponse( v, max_count, tmp, count ) + end + end - -- strip the outer table - return out[1] + -- strip the outer table + return out[1] end --- This function simply checks if the table contains a Directory Id (DID) of 2 @@ -110,111 +110,111 @@ end -- @param tbl table containing the table as return from the Dir method -- @return true if host is vulnerable, false otherwise local function isVulnerable( tbl ) - for _, v in ipairs(tbl) do - -- if we got no v.id it's probably a container table - if ( not(v.id) ) then - if ( isVulnerable(v) ) then - return true - end - end - if ( v.id == 2 ) then - return true - end - end - return false + for _, v in ipairs(tbl) do + -- if we got no v.id it's probably a container table + if ( not(v.id) ) then + if ( isVulnerable(v) ) then + return true + end + end + if ( v.id == 2 ) then + return true + end + end + return false end action = function(host, port) - local status, response, shares - local afp_helper = afp.Helper:new() - local args = nmap.registry.args - local users = nmap.registry.afp or { ['nil'] = 'nil' } - local vulnerable = false + local status, response, shares + local afp_helper = afp.Helper:new() + local args = nmap.registry.args + local users = nmap.registry.afp or { ['nil'] = 'nil' } + local vulnerable = false - local MAX_FILES = 5 + local MAX_FILES = 5 - local afp_vuln = { - title = "Apple Mac OS X AFP server directory traversal", - IDS = {CVE = 'CVE-2010-0533'}, - risk_factor = "High", - scores = { - CVSSv2 = "7.5 (HIGH) (AV:N/AC:L/Au:N/C:P/I:P/A:P)", - }, - description = [[ + local afp_vuln = { + title = "Apple Mac OS X AFP server directory traversal", + IDS = {CVE = 'CVE-2010-0533'}, + risk_factor = "High", + scores = { + CVSSv2 = "7.5 (HIGH) (AV:N/AC:L/Au:N/C:P/I:P/A:P)", + }, + description = [[ Directory traversal vulnerability in AFP Server in Apple Mac OS X before 10.6.3 allows remote attackers to list a share root's parent directory.]], - references = { -'http://www.cqure.net/wp/2010/03/detecting-apple-mac-os-x-afp-vulnerability-cve-2010-0533-with-nmap', -'http://support.apple.com/kb/HT1222', - }, - dates = { - disclosure = {year = '2010', month = '03', day = '29'}, - }, - exploit_results = {}, - } + references = { + 'http://www.cqure.net/wp/2010/03/detecting-apple-mac-os-x-afp-vulnerability-cve-2010-0533-with-nmap', + 'http://support.apple.com/kb/HT1222', + }, + dates = { + disclosure = {year = '2010', month = '03', day = '29'}, + }, + exploit_results = {}, + } - local report = vulns.Report:new(SCRIPT_NAME, host, port) + local report = vulns.Report:new(SCRIPT_NAME, host, port) - if ( args['afp.username'] ) then - users = {} - users[args['afp.username']] = args['afp.password'] - end + if ( args['afp.username'] ) then + users = {} + users[args['afp.username']] = args['afp.password'] + end - for username, password in pairs(users) do + for username, password in pairs(users) do - status, response = afp_helper:OpenSession(host, port) - if ( not(status) ) then - stdnse.print_debug(response) - return - end + status, response = afp_helper:OpenSession(host, port) + if ( not(status) ) then + stdnse.print_debug(response) + return + end - -- Attempt to use No User Authentication? - if ( username ~= 'nil' ) then - status, response = afp_helper:Login(username, password) - else - status, response = afp_helper:Login(nil, nil) - end - if ( not(status) ) then - stdnse.print_debug("afp-path-vuln: Login failed", response) - stdnse.print_debug(3, "afp-path-vuln: Login error: %s", response) - return - end + -- Attempt to use No User Authentication? + if ( username ~= 'nil' ) then + status, response = afp_helper:Login(username, password) + else + status, response = afp_helper:Login(nil, nil) + end + if ( not(status) ) then + stdnse.print_debug("afp-path-vuln: Login failed", response) + stdnse.print_debug(3, "afp-path-vuln: Login error: %s", response) + return + end - status, shares = afp_helper:ListShares() + status, shares = afp_helper:ListShares() - for _, share in ipairs(shares) do + for _, share in ipairs(shares) do - local status, response = afp_helper:Dir( share .. "/../", { max_depth = 2 } ) + local status, response = afp_helper:Dir( share .. "/../", { max_depth = 2 } ) - if ( not(status) ) then - stdnse.print_debug(3, "afp-path-vuln: %s", response) - else - if ( isVulnerable( response ) ) then - vulnerable = true - if(nmap.verbosity() > 1) then - response = processResponse( response ) - local name = share .. "/../" - table.insert(afp_vuln.exploit_results, - name) - else - response = processResponse( response, MAX_FILES ) - local name = share .. ("/../ (%d first items)"):format(MAX_FILES) - table.insert(afp_vuln.exploit_results, - name) - end - table.insert(afp_vuln.exploit_results, - response) - end - end - end - end + if ( not(status) ) then + stdnse.print_debug(3, "afp-path-vuln: %s", response) + else + if ( isVulnerable( response ) ) then + vulnerable = true + if(nmap.verbosity() > 1) then + response = processResponse( response ) + local name = share .. "/../" + table.insert(afp_vuln.exploit_results, + name) + else + response = processResponse( response, MAX_FILES ) + local name = share .. ("/../ (%d first items)"):format(MAX_FILES) + table.insert(afp_vuln.exploit_results, + name) + end + table.insert(afp_vuln.exploit_results, + response) + end + end + end + end - if ( vulnerable ) then - afp_vuln.state = vulns.STATE.EXPLOIT - else - afp_vuln.state = vulns.STATE.NOT_VULN - end + if ( vulnerable ) then + afp_vuln.state = vulns.STATE.EXPLOIT + else + afp_vuln.state = vulns.STATE.NOT_VULN + end - return report:make_output(afp_vuln) + return report:make_output(afp_vuln) end diff --git a/scripts/allseeingeye-info.nse b/scripts/allseeingeye-info.nse index 671010bbd..b99b86a6a 100644 --- a/scripts/allseeingeye-info.nse +++ b/scripts/allseeingeye-info.nse @@ -90,41 +90,41 @@ http://sourceforge.net/projects/gameq/ -- 2 -- 16 -- --- No --- No --- 30 --- 200 min. --- unlimited --- 10 sec. --- No --- Yes --- No --- Yes --- unlimited --- 30 sec. --- 90 sec. --- Yes --- Off --- On --- Yes +-- No +-- No +-- 30 +-- 200 min. +-- unlimited +-- 10 sec. +-- No +-- Yes +-- No +-- Yes +-- unlimited +-- 30 sec. +-- 90 sec. +-- Yes +-- Off +-- On +-- Yes --
-- ---
--- NoVoDondo --- BLUE --- --- 71 --- 0 --- ---
--- --- HeroX --- RED --- --- 0 --- 11 --- ---
+-- +-- NoVoDondo +-- BLUE +-- +-- 71 +-- 0 +-- +--
+-- +-- HeroX +-- RED +-- +-- 0 +-- 11 +-- +--
-- author = "Marin Maržić" @@ -139,94 +139,94 @@ categories = { "discovery", "safe", "version" } -- @return ret_pos the position after the last unpacked byte -- @return string the unpacked string local unpack_str = function(str, pos) - local ret_pos = pos + str:byte(pos) - return ret_pos, string.sub(str, pos + 1, ret_pos - 1) + local ret_pos = pos + str:byte(pos) + return ret_pos, string.sub(str, pos + 1, ret_pos - 1) end portrule = shortport.version_port_or_service({1258,2126,3123,12444,13200,23196,26000,27138,27244,27777,28138}, "allseeingeye", "udp") action = function(host, port) - local status, data = comm.exchange(host, port.number, "s", { proto = "udp", timeout = 3000 }) - if not status then - return - end + local status, data = comm.exchange(host, port.number, "s", { proto = "udp", timeout = 3000 }) + if not status then + return + end - -- UDP port is open - nmap.set_port_state(host, port, "open") + -- UDP port is open + nmap.set_port_state(host, port, "open") - if not string.match(data, "^EYE1") then - return - end + if not string.match(data, "^EYE1") then + return + end - -- Detected; extract fields - local o = stdnse.output_table() - local pos = 5 + -- Detected; extract fields + local o = stdnse.output_table() + local pos = 5 - pos, o["game"] = unpack_str(data, pos) - pos, o["port"] = unpack_str(data, pos) - pos, o["server name"] = unpack_str(data, pos) - pos, o["game type"] = unpack_str(data, pos) - pos, o["map"] = unpack_str(data, pos) - pos, o["version"] = unpack_str(data, pos) - pos, o["passworded"] = unpack_str(data, pos) - pos, o["num players"] = unpack_str(data, pos) - pos, o["max players"] = unpack_str(data, pos) + pos, o["game"] = unpack_str(data, pos) + pos, o["port"] = unpack_str(data, pos) + pos, o["server name"] = unpack_str(data, pos) + pos, o["game type"] = unpack_str(data, pos) + pos, o["map"] = unpack_str(data, pos) + pos, o["version"] = unpack_str(data, pos) + pos, o["passworded"] = unpack_str(data, pos) + pos, o["num players"] = unpack_str(data, pos) + pos, o["max players"] = unpack_str(data, pos) - -- extract the key-value pairs - local kv = stdnse.output_table() - o["settings"] = kv - while data:byte(pos) ~= 1 do - local key, value - pos, key = unpack_str(data, pos) - pos, value = unpack_str(data, pos) - kv[key] = value - end - pos = pos + 1 + -- extract the key-value pairs + local kv = stdnse.output_table() + o["settings"] = kv + while data:byte(pos) ~= 1 do + local key, value + pos, key = unpack_str(data, pos) + pos, value = unpack_str(data, pos) + kv[key] = value + end + pos = pos + 1 - -- extract player info - local players = stdnse.output_table() - o["players"] = players - local playernum = 0 - while pos <= #data do - local flags = data:byte(pos) - pos = pos + 1 + -- extract player info + local players = stdnse.output_table() + o["players"] = players + local playernum = 0 + while pos <= #data do + local flags = data:byte(pos) + pos = pos + 1 - local player = stdnse.output_table() - if bit.band(flags, 1) ~= 0 then - pos, player.name = unpack_str(data, pos) - end - if bit.band(flags, 2) ~= 0 then - pos, player.team = unpack_str(data, pos) - end - if bit.band(flags, 4) ~= 0 then - pos, player.skin = unpack_str(data, pos) - end - if bit.band(flags, 8) ~= 0 then - pos, player.score = unpack_str(data, pos) - end - if bit.band(flags, 16) ~= 0 then - pos, player.ping = unpack_str(data, pos) - end - if bit.band(flags, 32) ~= 0 then - pos, player.time = unpack_str(data, pos) - end + local player = stdnse.output_table() + if bit.band(flags, 1) ~= 0 then + pos, player.name = unpack_str(data, pos) + end + if bit.band(flags, 2) ~= 0 then + pos, player.team = unpack_str(data, pos) + end + if bit.band(flags, 4) ~= 0 then + pos, player.skin = unpack_str(data, pos) + end + if bit.band(flags, 8) ~= 0 then + pos, player.score = unpack_str(data, pos) + end + if bit.band(flags, 16) ~= 0 then + pos, player.ping = unpack_str(data, pos) + end + if bit.band(flags, 32) ~= 0 then + pos, player.time = unpack_str(data, pos) + end - players["player " .. playernum] = player - playernum = playernum + 1 - end + players["player " .. playernum] = player + playernum = playernum + 1 + end - port.version.name = "ase" - port.version.name_confidence = 10 - port.version.product = "All-Seeing Eye" - local passworded_string - if o["passworded"] == "0" then - passworded_string = "; no password" - else - passworded_string = "; has password" - end - port.version.extrainfo = "game: " .. o["game"] .. " " .. o["version"] .. "; port: " .. o["port"] .. passworded_string + port.version.name = "ase" + port.version.name_confidence = 10 + port.version.product = "All-Seeing Eye" + local passworded_string + if o["passworded"] == "0" then + passworded_string = "; no password" + else + passworded_string = "; has password" + end + port.version.extrainfo = "game: " .. o["game"] .. " " .. o["version"] .. "; port: " .. o["port"] .. passworded_string - nmap.set_port_version(host, port, "hardmatched") + nmap.set_port_version(host, port, "hardmatched") - return o -end \ No newline at end of file + return o +end diff --git a/scripts/broadcast-dhcp-discover.nse b/scripts/broadcast-dhcp-discover.nse index 312534371..b6fe2c58c 100644 --- a/scripts/broadcast-dhcp-discover.nse +++ b/scripts/broadcast-dhcp-discover.nse @@ -51,27 +51,27 @@ categories = {"broadcast", "safe"} prerule = function() - if not nmap.is_privileged() then - stdnse.print_verbose("%s not running for lack of privileges.", SCRIPT_NAME) - return false - end + if not nmap.is_privileged() then + stdnse.print_verbose("%s not running for lack of privileges.", SCRIPT_NAME) + return false + end - if nmap.address_family() ~= 'inet' then - stdnse.print_debug("%s is IPv4 compatible only.", SCRIPT_NAME) - return false - end - return true + if nmap.address_family() ~= 'inet' then + stdnse.print_debug("%s is IPv4 compatible only.", SCRIPT_NAME) + return false + end + return true end -- Creates a random MAC address -- -- @return mac_addr string containing a random MAC local function randomizeMAC() - local mac_addr = "" - for j=1, 6 do - mac_addr = mac_addr .. string.char(math.random(1, 255)) - end - return mac_addr + local mac_addr = "" + for j=1, 6 do + mac_addr = mac_addr .. string.char(math.random(1, 255)) + end + return mac_addr end -- Gets a list of available interfaces based on link and up filters @@ -80,18 +80,18 @@ end -- @param up string containing the interface status to filter -- @return result table containing the matching interfaces local function getInterfaces(link, up) - if( not(nmap.list_interfaces) ) then return end - local interfaces, err = nmap.list_interfaces() - local result - if ( not(err) ) then - for _, iface in ipairs(interfaces) do - if ( iface.link == link and iface.up == up ) then - result = result or {} - result[iface.device] = true - end - end - end - return result + if( not(nmap.list_interfaces) ) then return end + local interfaces, err = nmap.list_interfaces() + local result + if ( not(err) ) then + for _, iface in ipairs(interfaces) do + if ( iface.link == link and iface.up == up ) then + result = result or {} + result[iface.device] = true + end + end + end + return result end -- Listens for an incoming dhcp response @@ -101,113 +101,113 @@ end -- @param xid the DHCP transaction id -- @param result a table to which the result is written local function dhcp_listener(sock, timeout, xid, result) - local condvar = nmap.condvar(result) + local condvar = nmap.condvar(result) - sock:set_timeout(100) + sock:set_timeout(100) - local start_time = nmap.clock_ms() - while( nmap.clock_ms() - start_time < timeout ) do - local status, _, _, data = sock:pcap_receive() - -- abort, once another thread has picked up our response - if ( #result > 0 ) then - sock:close() - condvar "signal" - return - end + local start_time = nmap.clock_ms() + while( nmap.clock_ms() - start_time < timeout ) do + local status, _, _, data = sock:pcap_receive() + -- abort, once another thread has picked up our response + if ( #result > 0 ) then + sock:close() + condvar "signal" + return + end - if ( status ) then - local p = packet.Packet:new( data, #data ) - if ( p and p.udp_dport ) then - local data = data:sub(p.udp_offset + 9) - local status, response = dhcp.dhcp_parse(data, xid) - if ( status ) then - table.insert( result, response ) - sock:close() - condvar "signal" - return - end - end - end - end - sock:close() - condvar "signal" + if ( status ) then + local p = packet.Packet:new( data, #data ) + if ( p and p.udp_dport ) then + local data = data:sub(p.udp_offset + 9) + local status, response = dhcp.dhcp_parse(data, xid) + if ( status ) then + table.insert( result, response ) + sock:close() + condvar "signal" + return + end + end + end + end + sock:close() + condvar "signal" end action = function() - local host, port = "255.255.255.255", 67 - local timeout = stdnse.parse_timespec(stdnse.get_script_args("broadcast-dhcp-discover.timeout")) - timeout = (timeout or 10) * 1000 + local host, port = "255.255.255.255", 67 + local timeout = stdnse.parse_timespec(stdnse.get_script_args("broadcast-dhcp-discover.timeout")) + timeout = (timeout or 10) * 1000 - -- randomizing the MAC could exhaust dhcp servers with small scopes - -- if ran multiple times, so we should probably refrain from doing - -- this? - local mac = string.char(0xDE,0xAD,0xC0,0xDE,0xCA,0xFE)--randomizeMAC() + -- randomizing the MAC could exhaust dhcp servers with small scopes + -- if ran multiple times, so we should probably refrain from doing + -- this? + local mac = string.char(0xDE,0xAD,0xC0,0xDE,0xCA,0xFE)--randomizeMAC() - local interfaces + local interfaces - -- first check if the user supplied an interface - if ( nmap.get_interface() ) then - interfaces = { [nmap.get_interface()] = true } - else - -- As the response will be sent to the "offered" ip address we need - -- to use pcap to pick it up. However, we don't know what interface - -- our packet went out on, so lets get a list of all interfaces and - -- run pcap on all of them, if they're a) up and b) ethernet. - interfaces = getInterfaces("ethernet", "up") - end + -- first check if the user supplied an interface + if ( nmap.get_interface() ) then + interfaces = { [nmap.get_interface()] = true } + else + -- As the response will be sent to the "offered" ip address we need + -- to use pcap to pick it up. However, we don't know what interface + -- our packet went out on, so lets get a list of all interfaces and + -- run pcap on all of them, if they're a) up and b) ethernet. + interfaces = getInterfaces("ethernet", "up") + end - if( not(interfaces) ) then return "\n ERROR: Failed to retrieve interfaces (try setting one explicitly using -e)" end + if( not(interfaces) ) then return "\n ERROR: Failed to retrieve interfaces (try setting one explicitly using -e)" end - local transaction_id = bin.pack("I", ipOps.todword("0.0.0.0")) + local transaction_id = bin.pack("I", ipOps.todword("0.0.0.0")) - -- we nead to set the flags to broadcast - local request_options, overrides, lease_time = nil, { flags = 0x8000 }, nil - local status, packet = dhcp.dhcp_build(request_type, ip_address, mac, nil, request_options, overrides, lease_time, transaction_id) - if (not(status)) then return "\n ERROR: Failed to build packet" end + -- we nead to set the flags to broadcast + local request_options, overrides, lease_time = nil, { flags = 0x8000 }, nil + local status, packet = dhcp.dhcp_build(request_type, ip_address, mac, nil, request_options, overrides, lease_time, transaction_id) + if (not(status)) then return "\n ERROR: Failed to build packet" end - local threads = {} - local result = {} - local condvar = nmap.condvar(result) + local threads = {} + local result = {} + local condvar = nmap.condvar(result) - -- start a listening thread for each interface - for iface, _ in pairs(interfaces) do - local sock, co - sock = nmap.new_socket() - sock:pcap_open(iface, 1500, false, "ip && udp && port 68") - co = stdnse.new_thread( dhcp_listener, sock, timeout, transaction_id, result ) - threads[co] = true - end + -- start a listening thread for each interface + for iface, _ in pairs(interfaces) do + local sock, co + sock = nmap.new_socket() + sock:pcap_open(iface, 1500, false, "ip && udp && port 68") + co = stdnse.new_thread( dhcp_listener, sock, timeout, transaction_id, result ) + threads[co] = true + end - local socket = nmap.new_socket("udp") - socket:bind(nil, 68) - socket:sendto( host, port, packet ) - socket:close() + local socket = nmap.new_socket("udp") + socket:bind(nil, 68) + socket:sendto( host, port, packet ) + socket:close() - -- wait until all threads are done - repeat - for thread in pairs(threads) do - if coroutine.status(thread) == "dead" then threads[thread] = nil end - end - if ( next(threads) ) then - condvar "wait" - end - until next(threads) == nil + -- wait until all threads are done + repeat + for thread in pairs(threads) do + if coroutine.status(thread) == "dead" then threads[thread] = nil end + end + if ( next(threads) ) then + condvar "wait" + end + until next(threads) == nil - local response = {} - -- Display the results - for i, r in ipairs(result) do - table.insert(response, string.format("IP Offered: %s", r.yiaddr_str)) - for _, v in ipairs(r.options) do - if(type(v['value']) == 'table') then - table.insert(response, string.format("%s: %s", v['name'], stdnse.strjoin(", ", v['value']))) - else - table.insert(response, string.format("%s: %s\n", v['name'], v['value'])) - end - end - end - return stdnse.format_output(true, response) + local response = {} + -- Display the results + for i, r in ipairs(result) do + table.insert(response, string.format("IP Offered: %s", r.yiaddr_str)) + for _, v in ipairs(r.options) do + if(type(v['value']) == 'table') then + table.insert(response, string.format("%s: %s", v['name'], stdnse.strjoin(", ", v['value']))) + else + table.insert(response, string.format("%s: %s\n", v['name'], v['value'])) + end + end + end + return stdnse.format_output(true, response) end diff --git a/scripts/broadcast-pim-discovery.nse b/scripts/broadcast-pim-discovery.nse index 3dab4e134..cc5abc9fc 100644 --- a/scripts/broadcast-pim-discovery.nse +++ b/scripts/broadcast-pim-discovery.nse @@ -41,61 +41,61 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"discovery", "safe", "broadcast"} prerule = function() - if nmap.address_family() ~= 'inet' then - stdnse.print_verbose("%s is IPv4 only.", SCRIPT_NAME) - return false - end - if not nmap.is_privileged() then - stdnse.print_verbose("%s not running for lack of privileges.", SCRIPT_NAME) - return false - end - return true + if nmap.address_family() ~= 'inet' then + stdnse.print_verbose("%s is IPv4 only.", SCRIPT_NAME) + return false + end + if not nmap.is_privileged() then + stdnse.print_verbose("%s not running for lack of privileges.", SCRIPT_NAME) + return false + end + return true end -- Generates a raw PIM Hello message. --@return hello Raw PIM Hello message local helloRaw = function() - -- Version: 2, Type: Hello (0) - local hello_raw = bin.pack(">C", 0x20) - -- Reserved - hello_raw = hello_raw.. bin.pack(">C", 0x00) - -- Checksum: Calculated later - hello_raw = hello_raw.. bin.pack(">S", 0x0000) - -- Options (TLVs) - -- Hold time 1 second - hello_raw = hello_raw.. bin.pack(">SSS", 0x01, 0x02, 0x01) - -- Generation ID: Random - hello_raw = hello_raw.. bin.pack(">SSI", 0x14, 0x04, math.random(23456)) - -- DR Priority: 1 - hello_raw = hello_raw.. bin.pack(">SSI", 0x13, 0x04, 0x01) - -- State fresh capable: Version = 1, interval = 0, Reserved - hello_raw = hello_raw.. bin.pack(">SSCCS", 0x15, 0x04, 0x01, 0x00, 0x00) - -- Calculate checksum - hello_raw = hello_raw:sub(1,2) .. bin.pack(">S", packet.in_cksum(hello_raw)) .. hello_raw:sub(5) + -- Version: 2, Type: Hello (0) + local hello_raw = bin.pack(">C", 0x20) + -- Reserved + hello_raw = hello_raw.. bin.pack(">C", 0x00) + -- Checksum: Calculated later + hello_raw = hello_raw.. bin.pack(">S", 0x0000) + -- Options (TLVs) + -- Hold time 1 second + hello_raw = hello_raw.. bin.pack(">SSS", 0x01, 0x02, 0x01) + -- Generation ID: Random + hello_raw = hello_raw.. bin.pack(">SSI", 0x14, 0x04, math.random(23456)) + -- DR Priority: 1 + hello_raw = hello_raw.. bin.pack(">SSI", 0x13, 0x04, 0x01) + -- State fresh capable: Version = 1, interval = 0, Reserved + hello_raw = hello_raw.. bin.pack(">SSCCS", 0x15, 0x04, 0x01, 0x00, 0x00) + -- Calculate checksum + hello_raw = hello_raw:sub(1,2) .. bin.pack(">S", packet.in_cksum(hello_raw)) .. hello_raw:sub(5) - return hello_raw + return hello_raw end -- Sends a PIM Hello message. --@param interface Network interface to use. --@param dstip Destination IP to which send the Hello. local helloQuery = function(interface, dstip) - local hello_packet, sock, eth_hdr - local srcip = interface.address + local hello_packet, sock, eth_hdr + local srcip = interface.address - local hello_raw = helloRaw() - local ip_raw = bin.pack("H", "45c00040ed780000016718bc0a00c8750a00c86b") .. hello_raw - hello_packet = packet.Packet:new(ip_raw, ip_raw:len()) - hello_packet:ip_set_bin_src(ipOps.ip_to_str(srcip)) - hello_packet:ip_set_bin_dst(ipOps.ip_to_str(dstip)) - hello_packet:ip_set_len(ip_raw:len()) hello_packet:ip_count_checksum() + local hello_raw = helloRaw() + local ip_raw = bin.pack("H", "45c00040ed780000016718bc0a00c8750a00c86b") .. hello_raw + hello_packet = packet.Packet:new(ip_raw, ip_raw:len()) + hello_packet:ip_set_bin_src(ipOps.ip_to_str(srcip)) + hello_packet:ip_set_bin_dst(ipOps.ip_to_str(dstip)) + hello_packet:ip_set_len(ip_raw:len()) hello_packet:ip_count_checksum() - sock = nmap.new_dnet() - sock:ethernet_open(interface.device) - -- Ethernet multicast for PIM, our ethernet address and packet type IP - eth_hdr = bin.pack(">HAS", "01 00 5e 00 00 0d", interface.mac, 0x0800) - sock:ethernet_send(eth_hdr .. hello_packet.buf) - sock:ethernet_close() + sock = nmap.new_dnet() + sock:ethernet_open(interface.device) + -- Ethernet multicast for PIM, our ethernet address and packet type IP + eth_hdr = bin.pack(">HAS", "01 00 5e 00 00 0d", interface.mac, 0x0800) + sock:ethernet_send(eth_hdr .. hello_packet.buf) + sock:ethernet_close() end -- Listens for PIM Hello messages. @@ -103,90 +103,90 @@ end --@param timeout Time to listen for a response. --@param responses table to insert responders' IPs into. local helloListen = function(interface, timeout, responses) - local condvar = nmap.condvar(responses) - local start = nmap.clock_ms() - local listener = nmap.new_socket() - local p, hello_raw, status, l3data, _ + local condvar = nmap.condvar(responses) + local start = nmap.clock_ms() + local listener = nmap.new_socket() + local p, hello_raw, status, l3data, _ - -- PIM packets that are sent to 224.0.0.13 and not coming from our host - local filter = 'ip proto 103 and dst host 224.0.0.13 and src host not ' .. interface.address - listener:set_timeout(100) - listener:pcap_open(interface.device, 1024, true, filter) + -- PIM packets that are sent to 224.0.0.13 and not coming from our host + local filter = 'ip proto 103 and dst host 224.0.0.13 and src host not ' .. interface.address + listener:set_timeout(100) + listener:pcap_open(interface.device, 1024, true, filter) - while (nmap.clock_ms() - start) < timeout do - status, _, _, l3data = listener:pcap_receive() - if status then - p = packet.Packet:new(l3data, #l3data) - hello_raw = string.sub(l3data, p.ip_hl*4 + 1) - -- Check that PIM Type is Hello - if p and hello_raw:byte(1) == 0x20 then - table.insert(responses, p.ip_src) - end - end + while (nmap.clock_ms() - start) < timeout do + status, _, _, l3data = listener:pcap_receive() + if status then + p = packet.Packet:new(l3data, #l3data) + hello_raw = string.sub(l3data, p.ip_hl*4 + 1) + -- Check that PIM Type is Hello + if p and hello_raw:byte(1) == 0x20 then + table.insert(responses, p.ip_src) + end end - condvar("signal") + end + condvar("signal") end --- Returns the network interface used to send packets to the destination host. --@param destination host to which the interface is used. --@return interface Network interface used for destination host. local getInterface = function(destination) - -- First, create dummy UDP connection to get interface - local sock = nmap.new_socket() - local status, err = sock:connect(destination, "12345", "udp") - if not status then - stdnse.print_verbose("%s: %s", SCRIPT_NAME, err) - return - end - local status, address, _, _, _ = sock:get_info() - if not status then - stdnse.print_verbose("%s: %s", SCRIPT_NAME, err) - return - end - for _, interface in pairs(nmap.list_interfaces()) do - if interface.address == address then - return interface - end + -- First, create dummy UDP connection to get interface + local sock = nmap.new_socket() + local status, err = sock:connect(destination, "12345", "udp") + if not status then + stdnse.print_verbose("%s: %s", SCRIPT_NAME, err) + return + end + local status, address, _, _, _ = sock:get_info() + if not status then + stdnse.print_verbose("%s: %s", SCRIPT_NAME, err) + return + end + for _, interface in pairs(nmap.list_interfaces()) do + if interface.address == address then + return interface end + end end action = function() - local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout")) - local responses = {} - timeout = (timeout or 5) * 1000 - local mcast = "224.0.0.13" + local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout")) + local responses = {} + timeout = (timeout or 5) * 1000 + local mcast = "224.0.0.13" - -- Get the network interface to use - local interface = nmap.get_interface() - if interface then - interface = nmap.get_interface_info(interface) + -- Get the network interface to use + local interface = nmap.get_interface() + if interface then + interface = nmap.get_interface_info(interface) + else + interface = getInterface(mcast) + end + if not interface then + return ("\n ERROR: Couldn't get interface for %s"):format(mcast) + end + + stdnse.print_debug("%s: will send via %s interface.", SCRIPT_NAME, interface.shortname) + + -- Launch listener + stdnse.new_thread(helloListen, interface, timeout, responses) + + -- Send Hello after small sleep so the listener doesn't miss any responses + stdnse.sleep(0.1) + helloQuery(interface, mcast) + local condvar = nmap.condvar(responses) + condvar("wait") + + if #responses > 0 then + table.sort(responses) + if target.ALLOW_NEW_TARGETS then + for _, response in pairs(responses) do + target.add(response) + end else - interface = getInterface(mcast) - end - if not interface then - return ("\n ERROR: Couldn't get interface for %s"):format(mcast) - end - - stdnse.print_debug("%s: will send via %s interface.", SCRIPT_NAME, interface.shortname) - - -- Launch listener - stdnse.new_thread(helloListen, interface, timeout, responses) - - -- Send Hello after small sleep so the listener doesn't miss any responses - stdnse.sleep(0.1) - helloQuery(interface, mcast) - local condvar = nmap.condvar(responses) - condvar("wait") - - if #responses > 0 then - table.sort(responses) - if target.ALLOW_NEW_TARGETS then - for _, response in pairs(responses) do - target.add(response) - end - else - table.insert(responses,"Use the newtargets script-arg to add the results as targets") - end - return stdnse.format_output(true, responses) + table.insert(responses,"Use the newtargets script-arg to add the results as targets") end + return stdnse.format_output(true, responses) + end end diff --git a/scripts/broadcast-ping.nse b/scripts/broadcast-ping.nse index f34aa6e20..d35f9254e 100644 --- a/scripts/broadcast-ping.nse +++ b/scripts/broadcast-ping.nse @@ -60,21 +60,21 @@ categories = {"discovery","safe","broadcast"} prerule = function() - if not nmap.is_privileged() then - nmap.registry[SCRIPT_NAME] = nmap.registry[SCRIPT_NAME] or {} - if not nmap.registry[SCRIPT_NAME].rootfail then - stdnse.print_verbose("%s not running for lack of privileges.", SCRIPT_NAME) - end - nmap.registry[SCRIPT_NAME].rootfail = true - return nil - end + if not nmap.is_privileged() then + nmap.registry[SCRIPT_NAME] = nmap.registry[SCRIPT_NAME] or {} + if not nmap.registry[SCRIPT_NAME].rootfail then + stdnse.print_verbose("%s not running for lack of privileges.", SCRIPT_NAME) + end + nmap.registry[SCRIPT_NAME].rootfail = true + return nil + end - if nmap.address_family() ~= 'inet' then - stdnse.print_debug("%s is IPv4 compatible only.", SCRIPT_NAME) - return false - end + if nmap.address_family() ~= 'inet' then + stdnse.print_debug("%s is IPv4 compatible only.", SCRIPT_NAME) + return false + end - return true + return true end @@ -85,195 +85,195 @@ end -- @param ttl number containing value for the TTL (time to live) field in IP header -- @param data_length number value of ICMP payload length local icmp_packet = function(srcIP, dstIP, ttl, data_length, mtu, seqNo, icmp_id) - -- A couple of checks first - assert((seqNo and seqNo>0 and seqNo<=0xffff),"ICMP Sequence number: Value out of range(1-65535).") - assert((ttl and ttl>0 and ttl<0xff),"TTL(time-to-live): Value out of range(1-256).") - -- MTU values should be considered here! - assert((data_length and data_length>=0 and data_length0 and seqNo<=0xffff),"ICMP Sequence number: Value out of range(1-65535).") + assert((ttl and ttl>0 and ttl<0xff),"TTL(time-to-live): Value out of range(1-256).") + -- MTU values should be considered here! + assert((data_length and data_length>=0 and data_length0 then - icmp_payload = openssl.rand_bytes(data_length) - else - icmp_payload = "" - end + -- ICMP Message + local icmp_payload = nil + if data_length and data_length>0 then + icmp_payload = openssl.rand_bytes(data_length) + else + icmp_payload = "" + end - local seqNo_hex = stdnse.tohex(seqNo) - local icmp_seqNo = bin.pack(">H", string.rep("0",(4-seqNo_hex))..seqNo_hex) + local seqNo_hex = stdnse.tohex(seqNo) + local icmp_seqNo = bin.pack(">H", string.rep("0",(4-seqNo_hex))..seqNo_hex) - -- Type=08; Code=00; Chksum=0000; ID=icmp_id; SeqNo=icmp_seqNo; Payload=icmp_payload(hex string); - local icmp_tmp = bin.pack(">HAAA", "0800 0000", icmp_id, icmp_seqNo, icmp_payload) + -- Type=08; Code=00; Chksum=0000; ID=icmp_id; SeqNo=icmp_seqNo; Payload=icmp_payload(hex string); + local icmp_tmp = bin.pack(">HAAA", "0800 0000", icmp_id, icmp_seqNo, icmp_payload) - local icmp_checksum = packet.in_cksum(icmp_tmp) + local icmp_checksum = packet.in_cksum(icmp_tmp) - local icmp_msg = bin.pack(">HHAAA", "0800", stdnse.tohex(icmp_checksum), icmp_id, icmp_seqNo, icmp_payload) + local icmp_msg = bin.pack(">HHAAA", "0800", stdnse.tohex(icmp_checksum), icmp_id, icmp_seqNo, icmp_payload) - --IP Total Length - local length_hex = stdnse.tohex(20 + #icmp_msg) - local ip_length = bin.pack(">H", string.rep("0",(4-#length_hex))..length_hex) + --IP Total Length + local length_hex = stdnse.tohex(20 + #icmp_msg) + local ip_length = bin.pack(">H", string.rep("0",(4-#length_hex))..length_hex) - --TTL - local ttl_hex = stdnse.tohex(ttl) - local ip_ttl = bin.pack(">H", string.rep("0",(2-ttl_hex))..ttl_hex) + --TTL + local ttl_hex = stdnse.tohex(ttl) + local ip_ttl = bin.pack(">H", string.rep("0",(2-ttl_hex))..ttl_hex) - --IP header - local ip_bin = bin.pack(">HAHAH","4500",ip_length, "0000 4000", ip_ttl, - "01 0000 0000 0000 0000 0000") + --IP header + local ip_bin = bin.pack(">HAHAH","4500",ip_length, "0000 4000", ip_ttl, + "01 0000 0000 0000 0000 0000") - -- IP+ICMP; Addresses and checksum need to be filled - local icmp_bin = bin.pack(">AA",ip_bin, icmp_msg) + -- IP+ICMP; Addresses and checksum need to be filled + local icmp_bin = bin.pack(">AA",ip_bin, icmp_msg) - --Packet - local icmp = packet.Packet:new(icmp_bin,#icmp_bin) - assert(icmp,"Mistake during ICMP packet parsing") + --Packet + local icmp = packet.Packet:new(icmp_bin,#icmp_bin) + assert(icmp,"Mistake during ICMP packet parsing") - icmp:ip_set_bin_src(packet.iptobin(srcIP)) - icmp:ip_set_bin_dst(packet.iptobin(dstIP)) - icmp:ip_count_checksum() + icmp:ip_set_bin_src(packet.iptobin(srcIP)) + icmp:ip_set_bin_dst(packet.iptobin(dstIP)) + icmp:ip_count_checksum() - return icmp + return icmp end local broadcast_if = function(if_table,icmp_responders) - local condvar = nmap.condvar(icmp_responders) + local condvar = nmap.condvar(icmp_responders) - local num_probes = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".num-probes")) or 1 + local num_probes = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".num-probes")) or 1 - local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout")) - timeout = (timeout or 3) * 1000 + local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout")) + timeout = (timeout or 3) * 1000 - local ttl = nmap.get_ttl() + local ttl = nmap.get_ttl() - local data_length = nmap.get_payload_length() - local sequence_number = 1 - local destination_IP = "255.255.255.255" + local data_length = nmap.get_payload_length() + local sequence_number = 1 + local destination_IP = "255.255.255.255" - -- raw IPv4 socket - local dnet = nmap.new_dnet() - local try = nmap.new_try() - try = nmap.new_try(function() dnet:ethernet_close() end) + -- raw IPv4 socket + local dnet = nmap.new_dnet() + local try = nmap.new_try() + try = nmap.new_try(function() dnet:ethernet_close() end) - -- raw sniffing socket (icmp echoreply style) - local pcap = nmap.new_socket() - pcap:set_timeout(timeout) + -- raw sniffing socket (icmp echoreply style) + local pcap = nmap.new_socket() + pcap:set_timeout(timeout) - local mtu = if_table.mtu or 256 -- 256 is minimal mtu + local mtu = if_table.mtu or 256 -- 256 is minimal mtu - pcap:pcap_open(if_table.device, 104, false, "dst host ".. if_table.address .. - " and icmp[icmptype]==icmp-echoreply") - try(dnet:ethernet_open(if_table.device)) + pcap:pcap_open(if_table.device, 104, false, "dst host ".. if_table.address .. + " and icmp[icmptype]==icmp-echoreply") + try(dnet:ethernet_open(if_table.device)) - local source_IP = if_table.address + local source_IP = if_table.address - local icmp_ids = {} + local icmp_ids = {} - for i = 1, num_probes do - -- ICMP packet - local icmp_id = openssl.rand_bytes(2) - icmp_ids[icmp_id]=true - local icmp = icmp_packet( source_IP, destination_IP, ttl, - data_length, mtu, sequence_number, icmp_id) + for i = 1, num_probes do + -- ICMP packet + local icmp_id = openssl.rand_bytes(2) + icmp_ids[icmp_id]=true + local icmp = icmp_packet( source_IP, destination_IP, ttl, + data_length, mtu, sequence_number, icmp_id) - local ethernet_icmp = bin.pack("HAHA", "FF FF FF FF FF FF", if_table.mac, "08 00", icmp.buf) + local ethernet_icmp = bin.pack("HAHA", "FF FF FF FF FF FF", if_table.mac, "08 00", icmp.buf) - try( dnet:ethernet_send(ethernet_icmp) ) - end + try( dnet:ethernet_send(ethernet_icmp) ) + end - while true do - local status, plen, l2, l3data, _ = pcap:pcap_receive() - if not status then break end + while true do + local status, plen, l2, l3data, _ = pcap:pcap_receive() + if not status then break end - -- Do stuff with packet - local icmpreply = packet.Packet:new(l3data,plen,false) - -- We check whether the packet is parsed ok, and whether the ICMP ID of the sent packet - -- is the same with the ICMP ID of the received packet. We don't want ping probes interfering - local icmp_id = icmpreply:raw(icmpreply.icmp_offset+4,2) - if icmpreply:ip_parse() and icmp_ids[icmp_id] then - if not icmp_responders[icmpreply.ip_src] then - -- [key = IP]=MAC - local mac_pretty = stdnse.format_mac(l2:sub(7,12)) - icmp_responders[icmpreply.ip_src] = mac_pretty - end - else - stdnse.print_debug("Erroneous ICMP packet received; Cannot parse IP header.") - end - end + -- Do stuff with packet + local icmpreply = packet.Packet:new(l3data,plen,false) + -- We check whether the packet is parsed ok, and whether the ICMP ID of the sent packet + -- is the same with the ICMP ID of the received packet. We don't want ping probes interfering + local icmp_id = icmpreply:raw(icmpreply.icmp_offset+4,2) + if icmpreply:ip_parse() and icmp_ids[icmp_id] then + if not icmp_responders[icmpreply.ip_src] then + -- [key = IP]=MAC + local mac_pretty = stdnse.format_mac(l2:sub(7,12)) + icmp_responders[icmpreply.ip_src] = mac_pretty + end + else + stdnse.print_debug("Erroneous ICMP packet received; Cannot parse IP header.") + end + end - pcap:close() - dnet:ethernet_close() + pcap:close() + dnet:ethernet_close() - condvar "signal" + condvar "signal" end action = function() - --get interface script-args, if any - local interface_arg = stdnse.get_script_args(SCRIPT_NAME .. ".interface") - local interface_opt = nmap.get_interface() + --get interface script-args, if any + local interface_arg = stdnse.get_script_args(SCRIPT_NAME .. ".interface") + local interface_opt = nmap.get_interface() - -- interfaces list (decide which interfaces to broadcast on) - local interfaces ={} - if interface_opt or interface_arg then - -- single interface defined - local interface = interface_opt or interface_arg - local if_table = nmap.get_interface_info(interface) - if not if_table or not if_table.address or not if_table.link=="ethernet" then - stdnse.print_debug("Interface not supported or not properly configured.") - return false - end - table.insert(interfaces, if_table) - else - local tmp_ifaces = nmap.list_interfaces() - for _, if_table in ipairs(tmp_ifaces) do - if if_table.address and - if_table.link=="ethernet" and - if_table.address:match("%d+%.%d+%.%d+%.%d+") then - table.insert(interfaces, if_table) - end - end - end + -- interfaces list (decide which interfaces to broadcast on) + local interfaces ={} + if interface_opt or interface_arg then + -- single interface defined + local interface = interface_opt or interface_arg + local if_table = nmap.get_interface_info(interface) + if not if_table or not if_table.address or not if_table.link=="ethernet" then + stdnse.print_debug("Interface not supported or not properly configured.") + return false + end + table.insert(interfaces, if_table) + else + local tmp_ifaces = nmap.list_interfaces() + for _, if_table in ipairs(tmp_ifaces) do + if if_table.address and + if_table.link=="ethernet" and + if_table.address:match("%d+%.%d+%.%d+%.%d+") then + table.insert(interfaces, if_table) + end + end + end - if #interfaces == 0 then - stdnse.print_debug("No interfaces found.") - return - end + if #interfaces == 0 then + stdnse.print_debug("No interfaces found.") + return + end - local icmp_responders={} - local threads ={} - local condvar = nmap.condvar(icmp_responders) + local icmp_responders={} + local threads ={} + local condvar = nmap.condvar(icmp_responders) - -- party time - for _, if_table in ipairs(interfaces) do - -- create a thread for each interface - local co = stdnse.new_thread(broadcast_if, if_table, icmp_responders) - threads[co]=true - end + -- party time + for _, if_table in ipairs(interfaces) do + -- create a thread for each interface + local co = stdnse.new_thread(broadcast_if, if_table, icmp_responders) + threads[co]=true + end - repeat - for thread in pairs(threads) do - if coroutine.status(thread) == "dead" then threads[thread] = nil end - end - if ( next(threads) ) then - condvar "wait" - end - until next(threads) == nil + repeat + for thread in pairs(threads) do + if coroutine.status(thread) == "dead" then threads[thread] = nil end + end + if ( next(threads) ) then + condvar "wait" + end + until next(threads) == nil - -- generate output - local output = tab.new() - for ip_addr, mac_addr in pairs(icmp_responders) do - if target.ALLOW_NEW_TARGETS then - target.add(ip_addr) - end - tab.addrow(output, "IP: " .. ip_addr, "MAC: " .. mac_addr) - end - if #output > 0 then - output = { tab.dump(output) } - if not target.ALLOW_NEW_TARGETS then - output[#output + 1] = "Use --script-args=newtargets to add the results as targets" - end - return stdnse.format_output(true, output) - end + -- generate output + local output = tab.new() + for ip_addr, mac_addr in pairs(icmp_responders) do + if target.ALLOW_NEW_TARGETS then + target.add(ip_addr) + end + tab.addrow(output, "IP: " .. ip_addr, "MAC: " .. mac_addr) + end + if #output > 0 then + output = { tab.dump(output) } + if not target.ALLOW_NEW_TARGETS then + output[#output + 1] = "Use --script-args=newtargets to add the results as targets" + end + return stdnse.format_output(true, output) + end end diff --git a/scripts/broadcast-ripng-discover.nse b/scripts/broadcast-ripng-discover.nse index 8d613d886..a1de3b9b2 100644 --- a/scripts/broadcast-ripng-discover.nse +++ b/scripts/broadcast-ripng-discover.nse @@ -34,117 +34,117 @@ prerule = function() return ( nmap.address_family() == "inet6" ) end RIPng = { - -- Supported RIPng commands - Command = { - Request = 1, - Response = 2, - }, + -- Supported RIPng commands + Command = { + Request = 1, + Response = 2, + }, - -- Route table entry - RTE = { + -- Route table entry + RTE = { - -- Creates a new Route Table Entry - -- @param prefix string containing the ipv6 route prefix - -- @param tag number containing the route tag - -- @param prefix_len number containing the length in bits of the - -- signifcant part of the prefix - -- @param metric number containing the current metric for the - -- destination - new = function(self, prefix, tag, prefix_len, metric) - local o = { - prefix = prefix, - tag = tag, - prefix_len = prefix_len, - metric = metric - } - setmetatable(o, self) - self.__index = self - return o - end, + -- Creates a new Route Table Entry + -- @param prefix string containing the ipv6 route prefix + -- @param tag number containing the route tag + -- @param prefix_len number containing the length in bits of the + -- signifcant part of the prefix + -- @param metric number containing the current metric for the + -- destination + new = function(self, prefix, tag, prefix_len, metric) + local o = { + prefix = prefix, + tag = tag, + prefix_len = prefix_len, + metric = metric + } + setmetatable(o, self) + self.__index = self + return o + end, - -- Parses a byte string and creates an instance of RTE - -- @param data string of bytes - -- @return rte instance of RTE - parse = function(data) - local rte = RIPng.RTE:new() - local pos, ip + -- Parses a byte string and creates an instance of RTE + -- @param data string of bytes + -- @return rte instance of RTE + parse = function(data) + local rte = RIPng.RTE:new() + local pos, ip - pos, ip, rte.tag, rte.prefix_len, rte.metric = bin.unpack(">A16SCC", data) - ip = select(2, bin.unpack("B" .. #ip, ip)) - rte.prefix = ipOps.bin_to_ip(ip) - return rte - end, + pos, ip, rte.tag, rte.prefix_len, rte.metric = bin.unpack(">A16SCC", data) + ip = select(2, bin.unpack("B" .. #ip, ip)) + rte.prefix = ipOps.bin_to_ip(ip) + return rte + end, - -- Converts a RTE instance to string - -- @return string of bytes to send to the server - __tostring = function(self) - local ipstr = ipOps.ip_to_str(self.prefix) - assert(16 == #ipstr, "Invalid IPv6 address encountered") - return bin.pack(">ASCC", ipstr, self.tag, self.prefix_len, self.metric) - end, + -- Converts a RTE instance to string + -- @return string of bytes to send to the server + __tostring = function(self) + local ipstr = ipOps.ip_to_str(self.prefix) + assert(16 == #ipstr, "Invalid IPv6 address encountered") + return bin.pack(">ASCC", ipstr, self.tag, self.prefix_len, self.metric) + end, - }, + }, - -- The Request class contains functions to build a RIPv2 Request - Request = { + -- The Request class contains functions to build a RIPv2 Request + Request = { - -- Creates a new Request instance - -- - -- @param command number containing the RIPv2 Command to use - -- @return o instance of request - new = function(self, entries) - local o = { - command = 1, - version = 1, - entries = entries, - } - setmetatable(o, self) - self.__index = self - return o - end, + -- Creates a new Request instance + -- + -- @param command number containing the RIPv2 Command to use + -- @return o instance of request + new = function(self, entries) + local o = { + command = 1, + version = 1, + entries = entries, + } + setmetatable(o, self) + self.__index = self + return o + end, - -- Converts the whole request to a string - __tostring = function(self) - local RESERVED = 0 - local str = bin.pack(">CCS", self.command, self.version, RESERVED) - for _, rte in ipairs(self.entries) do - str = str .. tostring(rte) - end - return str - end, + -- Converts the whole request to a string + __tostring = function(self) + local RESERVED = 0 + local str = bin.pack(">CCS", self.command, self.version, RESERVED) + for _, rte in ipairs(self.entries) do + str = str .. tostring(rte) + end + return str + end, - }, + }, - -- A RIPng Response - Response = { + -- A RIPng Response + Response = { - -- Creates a new Response instance - -- @return o new instance of Response - new = function(self) - local o = { } - setmetatable(o, self) - self.__index = self - return o - end, + -- Creates a new Response instance + -- @return o new instance of Response + new = function(self) + local o = { } + setmetatable(o, self) + self.__index = self + return o + end, - -- Creates a new Response instance based on a string of bytes - -- @return resp new instance of Response - parse = function(data) - local resp = RIPng.Response:new() - local pos, _ + -- Creates a new Response instance based on a string of bytes + -- @return resp new instance of Response + parse = function(data) + local resp = RIPng.Response:new() + local pos, _ - pos, resp.command, resp.version, _ = bin.unpack(">CCS", data) - resp.entries = {} - while( pos < #data ) do - local e = RIPng.RTE.parse(data:sub(pos)) - table.insert(resp.entries, e) - pos = pos + 20 - end + pos, resp.command, resp.version, _ = bin.unpack(">CCS", data) + resp.entries = {} + while( pos < #data ) do + local e = RIPng.RTE.parse(data:sub(pos)) + table.insert(resp.entries, e) + pos = pos + 20 + end - return resp - end, - } + return resp + end, + } } local function fail(err) return ("\n ERROR: %s"):format(err or "") end @@ -152,65 +152,65 @@ local function fail(err) return ("\n ERROR: %s"):format(err or "") end -- Parses a RIPng response -- @return ret string containing the routing table local function parse_response(resp) - local next_hop - local result = tab.new(3) - tab.addrow(result, "route", "metric", "next hop") - for _, rte in pairs(resp.entries or {}) do - -- next hop information is specified in a separate RTE according to - -- RFC 2080 section 2.1.1 - if ( 0xFF == rte.metric ) then - next_hop = rte.prefix - else - tab.addrow(result, ("%s/%d"):format(rte.prefix, rte.prefix_len), rte.metric, next_hop or "") - end - end - return tab.dump(result) + local next_hop + local result = tab.new(3) + tab.addrow(result, "route", "metric", "next hop") + for _, rte in pairs(resp.entries or {}) do + -- next hop information is specified in a separate RTE according to + -- RFC 2080 section 2.1.1 + if ( 0xFF == rte.metric ) then + next_hop = rte.prefix + else + tab.addrow(result, ("%s/%d"):format(rte.prefix, rte.prefix_len), rte.metric, next_hop or "") + end + end + return tab.dump(result) end action = function() - local req = RIPng.Request:new( { RIPng.RTE:new("0::", 0, 0, 16) } ) - local host, port = "FF02::9", { number = 521, protocol = "udp" } - local iface = nmap.get_interface() - local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME..".timeout")) - timeout = (timeout or 5) * 1000 + local req = RIPng.Request:new( { RIPng.RTE:new("0::", 0, 0, 16) } ) + local host, port = "FF02::9", { number = 521, protocol = "udp" } + local iface = nmap.get_interface() + local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME..".timeout")) + timeout = (timeout or 5) * 1000 - local sock = nmap.new_socket("udp") - sock:bind(nil, 521) - sock:set_timeout(timeout) + local sock = nmap.new_socket("udp") + sock:bind(nil, 521) + sock:set_timeout(timeout) - local status = sock:sendto(host, port, tostring(req)) + local status = sock:sendto(host, port, tostring(req)) - -- do we need to add the interface name to the address? - if ( not(status) ) then - if ( not(iface) ) then - return fail("Couldn't determine what interface to use, try supplying it with -e") - end - status = sock:sendto(host .. "%" .. iface, port, tostring(req)) - end + -- do we need to add the interface name to the address? + if ( not(status) ) then + if ( not(iface) ) then + return fail("Couldn't determine what interface to use, try supplying it with -e") + end + status = sock:sendto(host .. "%" .. iface, port, tostring(req)) + end - if ( not(status) ) then - return fail("Failed to send request to server") - end + if ( not(status) ) then + return fail("Failed to send request to server") + end - local responses = {} - while(true) do - local status, data = sock:receive() - if ( not(status) ) then - break - else - local status, _, _, rhost = sock:get_info() - if ( not(status) ) then - rhost = "unknown" - end - responses[rhost] = RIPng.Response.parse(data) - end - end + local responses = {} + while(true) do + local status, data = sock:receive() + if ( not(status) ) then + break + else + local status, _, _, rhost = sock:get_info() + if ( not(status) ) then + rhost = "unknown" + end + responses[rhost] = RIPng.Response.parse(data) + end + end - local result = {} - for ip, resp in pairs(responses) do - stdnse.print_debug(ip, resp) - table.insert(result, { name = ip, parse_response(resp) } ) - end - return stdnse.format_output(true, result) + local result = {} + for ip, resp in pairs(responses) do + stdnse.print_debug(ip, resp) + table.insert(result, { name = ip, parse_response(resp) } ) + end + return stdnse.format_output(true, result) end diff --git a/scripts/broadcast-wpad-discover.nse b/scripts/broadcast-wpad-discover.nse index fea088dbd..ed09a989f 100644 --- a/scripts/broadcast-wpad-discover.nse +++ b/scripts/broadcast-wpad-discover.nse @@ -44,11 +44,11 @@ local arg_nodhcp = stdnse.get_script_args(SCRIPT_NAME .. ".nodhcp") local arg_getwpad= stdnse.get_script_args(SCRIPT_NAME .. ".getwpad") local function createRequestList(req_list) - local output = "" - for _, v in ipairs(req_list) do - output = output .. string.char(v) - end - return output + local output = "" + for _, v in ipairs(req_list) do + output = output .. string.char(v) + end + return output end @@ -58,175 +58,175 @@ end -- @param up string containing the interface status to filter -- @return result table containing the matching interfaces local function getInterfaces(link, up) - if( not(nmap.list_interfaces) ) then return end - local interfaces, err = nmap.list_interfaces() - local result - if ( not(err) ) then - for _, iface in ipairs(interfaces) do - if ( iface.link == link and iface.up == up ) then - result = result or {} - result[iface.device] = true - end - end - end - return result + if( not(nmap.list_interfaces) ) then return end + local interfaces, err = nmap.list_interfaces() + local result + if ( not(err) ) then + for _, iface in ipairs(interfaces) do + if ( iface.link == link and iface.up == up ) then + result = result or {} + result[iface.device] = true + end + end + end + return result end local function parseDHCPResponse(response) - for _, v in ipairs(response.options) do - if ( "WPAD" == v.name ) then - return true, v.value - end - end + for _, v in ipairs(response.options) do + if ( "WPAD" == v.name ) then + return true, v.value + end + end end local function getWPAD(u) - local u_parsed = url.parse(u) + local u_parsed = url.parse(u) - if ( not(u_parsed) ) then - return false, ("Failed to parse url: %s"):format(u) - end + if ( not(u_parsed) ) then + return false, ("Failed to parse url: %s"):format(u) + end - local response = http.get(u_parsed.host, u_parsed.port or 80, u_parsed.path) - if ( response and response.status == 200 ) then - return true, response.body - end + local response = http.get(u_parsed.host, u_parsed.port or 80, u_parsed.path) + if ( response and response.status == 200 ) then + return true, response.body + end - return false, ("Failed to retrieve wpad.dat (%s) from server"):format(u) + return false, ("Failed to retrieve wpad.dat (%s) from server"):format(u) end local function parseWPAD(wpad) - local proxies = {} - for proxy in wpad:gmatch("PROXY%s*([^\";%s]*)") do - table.insert(proxies, proxy) - end - return proxies + local proxies = {} + for proxy in wpad:gmatch("PROXY%s*([^\";%s]*)") do + table.insert(proxies, proxy) + end + return proxies end local function dnsDiscover() - -- tries to discover WPAD for all domains and sub-domains - local function enumWPADNames(domain) - local d = domain - -- reduce domain until we only have a single dot left - -- there is a security problem in querying for wpad.tld like eg - -- wpad.com as this could be a rougue domain. This loop does not - -- account for domains with tld's containing two parts e.g. co.uk. - -- However, as the script just attempts to download and parse the - -- proxy values in the WPAD there should be no real harm here. - repeat - local name = ("wpad.%s"):format(d) - d = d:match("^[^%.]-%.(.*)$") - local status, response = dns.query(name, { dtype = 'A', retAll = true }) + -- tries to discover WPAD for all domains and sub-domains + local function enumWPADNames(domain) + local d = domain + -- reduce domain until we only have a single dot left + -- there is a security problem in querying for wpad.tld like eg + -- wpad.com as this could be a rougue domain. This loop does not + -- account for domains with tld's containing two parts e.g. co.uk. + -- However, as the script just attempts to download and parse the + -- proxy values in the WPAD there should be no real harm here. + repeat + local name = ("wpad.%s"):format(d) + d = d:match("^[^%.]-%.(.*)$") + local status, response = dns.query(name, { dtype = 'A', retAll = true }) - -- get the first entry and return - if ( status and response[1] ) then - return true, { name = name, ip = response[1] } - end - until( not(d) or not(d:match("%.")) ) + -- get the first entry and return + if ( status and response[1] ) then + return true, { name = name, ip = response[1] } + end + until( not(d) or not(d:match("%.")) ) - end + end - -- first try a domain if it was supplied - if ( arg_domain ) then - local status, response = enumWPADNames(arg_domain) - if ( status ) then - return status, response - end - end + -- first try a domain if it was supplied + if ( arg_domain ) then + local status, response = enumWPADNames(arg_domain) + if ( status ) then + return status, response + end + end - -- if no domain was supplied, attempt to reverse lookup every ip on each - -- interface to find our FQDN hostname, once we do, try to query for WPAD - for i in pairs(getInterfaces("ethernet", "up") or {}) do - local iface, err = nmap.get_interface_info(i) - if ( iface ) then - local status, response = dns.query( dns.reverse(iface.address), { dtype = 'PTR', retAll = true } ) + -- if no domain was supplied, attempt to reverse lookup every ip on each + -- interface to find our FQDN hostname, once we do, try to query for WPAD + for i in pairs(getInterfaces("ethernet", "up") or {}) do + local iface, err = nmap.get_interface_info(i) + if ( iface ) then + local status, response = dns.query( dns.reverse(iface.address), { dtype = 'PTR', retAll = true } ) - -- did we get a name back from dns? - if ( status ) then - local domains = {} - for _, name in ipairs(response) do - -- first get all unique domain names - if ( not(name:match("in%-addr.arpa$")) ) then - local domain = name:match("^[^%.]-%.(.*)$") - domains[domain] = true - end - end + -- did we get a name back from dns? + if ( status ) then + local domains = {} + for _, name in ipairs(response) do + -- first get all unique domain names + if ( not(name:match("in%-addr.arpa$")) ) then + local domain = name:match("^[^%.]-%.(.*)$") + domains[domain] = true + end + end - -- attempt to discover the ip for WPAD in all domains - -- each domain is processed and reduced and ones the first - -- match is received it returns an IP - for domain in pairs(domains) do - status, response = enumWPADNames(domain) - if ( status ) then - return true, response - end - end + -- attempt to discover the ip for WPAD in all domains + -- each domain is processed and reduced and ones the first + -- match is received it returns an IP + for domain in pairs(domains) do + status, response = enumWPADNames(domain) + if ( status ) then + return true, response + end + end - end + end - end - end + end + end - return false, "Failed to find WPAD using DNS" + return false, "Failed to find WPAD using DNS" end local function dhcpDiscover() - -- send a DHCP discover on all ethernet interfaces that are up - for i in pairs(getInterfaces("ethernet", "up") or {}) do - local iface, err = nmap.get_interface_info(i) - if ( iface ) then - local req_list = createRequestList( { 1, 15, 3, 6, 44, 46, 47, 31, 33, 249, 43, 252 } ) - local status, response = dhcp.make_request("255.255.255.255", dhcp.request_types["DHCPDISCOVER"], "0.0.0.0", iface.mac, nil, req_list, { flags = 0x8000 } ) + -- send a DHCP discover on all ethernet interfaces that are up + for i in pairs(getInterfaces("ethernet", "up") or {}) do + local iface, err = nmap.get_interface_info(i) + if ( iface ) then + local req_list = createRequestList( { 1, 15, 3, 6, 44, 46, 47, 31, 33, 249, 43, 252 } ) + local status, response = dhcp.make_request("255.255.255.255", dhcp.request_types["DHCPDISCOVER"], "0.0.0.0", iface.mac, nil, req_list, { flags = 0x8000 } ) - -- if we got a response, we're happy and don't need to continue - if (status) then - return status, response - end - end - end + -- if we got a response, we're happy and don't need to continue + if (status) then + return status, response + end + end + end end action = function() - local status, response, wpad + local status, response, wpad - if ( arg_nodhcp and arg_nodns ) then - return "\n ERROR: Both nodns and nodhcp arguments were supplied" - end + if ( arg_nodhcp and arg_nodns ) then + return "\n ERROR: Both nodns and nodhcp arguments were supplied" + end - if ( nmap.is_privileged() and not(arg_nodhcp) ) then - status, response = dhcpDiscover() - if ( status ) then - status, wpad = parseDHCPResponse(response) - end - end + if ( nmap.is_privileged() and not(arg_nodhcp) ) then + status, response = dhcpDiscover() + if ( status ) then + status, wpad = parseDHCPResponse(response) + end + end - -- if the DHCP did not get a result, fallback to DNS - if (not(status) and not(arg_nodns) ) then - status, response = dnsDiscover() - if ( not(status) ) then - local services = "DNS" .. ( nmap.is_privileged() and "/DHCP" or "" ) - return ("\n ERROR: Could not find WPAD using %s"):format(services) - end - wpad = ("http://%s/wpad.dat"):format( response.name ) - end + -- if the DHCP did not get a result, fallback to DNS + if (not(status) and not(arg_nodns) ) then + status, response = dnsDiscover() + if ( not(status) ) then + local services = "DNS" .. ( nmap.is_privileged() and "/DHCP" or "" ) + return ("\n ERROR: Could not find WPAD using %s"):format(services) + end + wpad = ("http://%s/wpad.dat"):format( response.name ) + end - if ( status ) then - status, response = getWPAD(wpad) - end + if ( status ) then + status, response = getWPAD(wpad) + end - if ( not(status) ) then - return status, response - end + if ( not(status) ) then + return status, response + end - local output = ( arg_getwpad and response or parseWPAD(response) ) + local output = ( arg_getwpad and response or parseWPAD(response) ) - return stdnse.format_output(true, output) + return stdnse.format_output(true, output) end diff --git a/scripts/dns-cache-snoop.nse b/scripts/dns-cache-snoop.nse index 43dc4c396..d57b3c8df 100644 --- a/scripts/dns-cache-snoop.nse +++ b/scripts/dns-cache-snoop.nse @@ -78,56 +78,56 @@ local TIMED_MULTIPLIER = 1.0 -- This list is the first 50 entries of -- http://s3.amazonaws.com/alexa-static/top-1m.csv.zip on 2013-08-08. local ALEXA_DOMAINS = { - "google.com", - "facebook.com", - "youtube.com", - "yahoo.com", - "baidu.com", - "wikipedia.org", - "amazon.com", - "qq.com", - "live.com", - "linkedin.com", - "twitter.com", - "blogspot.com", - "taobao.com", - "google.co.in", - "bing.com", - "yahoo.co.jp", - "yandex.ru", - "wordpress.com", - "sina.com.cn", - "vk.com", - "ebay.com", - "google.de", - "tumblr.com", - "msn.com", - "google.co.uk", - "googleusercontent.com", - "ask.com", - "mail.ru", - "google.com.br", - "163.com", - "google.fr", - "pinterest.com", - "google.com.hk", - "hao123.com", - "microsoft.com", - "google.co.jp", - "xvideos.com", - "google.ru", - "weibo.com", - "craigslist.org", - "paypal.com", - "instagram.com", - "amazon.co.jp", - "google.it", - "imdb.com", - "blogger.com", - "google.es", - "apple.com", - "conduit.com", - "sohu.com", + "google.com", + "facebook.com", + "youtube.com", + "yahoo.com", + "baidu.com", + "wikipedia.org", + "amazon.com", + "qq.com", + "live.com", + "linkedin.com", + "twitter.com", + "blogspot.com", + "taobao.com", + "google.co.in", + "bing.com", + "yahoo.co.jp", + "yandex.ru", + "wordpress.com", + "sina.com.cn", + "vk.com", + "ebay.com", + "google.de", + "tumblr.com", + "msn.com", + "google.co.uk", + "googleusercontent.com", + "ask.com", + "mail.ru", + "google.com.br", + "163.com", + "google.fr", + "pinterest.com", + "google.com.hk", + "hao123.com", + "microsoft.com", + "google.co.jp", + "xvideos.com", + "google.ru", + "weibo.com", + "craigslist.org", + "paypal.com", + "instagram.com", + "amazon.co.jp", + "google.it", + "imdb.com", + "blogger.com", + "google.es", + "apple.com", + "conduit.com", + "sohu.com", } -- Construct the default list of domains. diff --git a/scripts/duplicates.nse b/scripts/duplicates.nse index 2dcc22e8c..bd15fa21b 100644 --- a/scripts/duplicates.nse +++ b/scripts/duplicates.nse @@ -63,149 +63,149 @@ postrule = function() return true end local function processSSLCerts(tab) - -- Handle SSL-certificates - -- We create a new table using the SHA1 digest as index - local ssl_certs = {} - for host, v in pairs(tab) do - for port, sha1 in pairs(v) do - ssl_certs[sha1] = ssl_certs[sha1] or {} - if ( not stdnse.contains(ssl_certs[sha1], host.ip) ) then - table.insert(ssl_certs[sha1], host.ip) - end - end - end + -- Handle SSL-certificates + -- We create a new table using the SHA1 digest as index + local ssl_certs = {} + for host, v in pairs(tab) do + for port, sha1 in pairs(v) do + ssl_certs[sha1] = ssl_certs[sha1] or {} + if ( not stdnse.contains(ssl_certs[sha1], host.ip) ) then + table.insert(ssl_certs[sha1], host.ip) + end + end + end - local results = {} - for sha1, hosts in pairs(ssl_certs) do - table.sort(hosts, function(a, b) return ipOps.compare_ip(a, "lt", b) end) - if ( #hosts > 1 ) then - table.insert(results, { name = ("Certficate (%s)"):format(sha1), hosts } ) - end - end + local results = {} + for sha1, hosts in pairs(ssl_certs) do + table.sort(hosts, function(a, b) return ipOps.compare_ip(a, "lt", b) end) + if ( #hosts > 1 ) then + table.insert(results, { name = ("Certficate (%s)"):format(sha1), hosts } ) + end + end - return results + return results end local function processSSHKeys(tab) - local hostkeys = {} + local hostkeys = {} - -- create a reverse mapping key_fingerprint -> host(s) - for ip, keys in pairs(tab) do - for _, key in ipairs(keys) do - local fp = ssh1.fingerprint_hex(key.fingerprint, key.algorithm, key.bits) - if not hostkeys[fp] then - hostkeys[fp] = {} - end - -- discard duplicate IPs - if not stdnse.contains(hostkeys[fp], ip) then - table.insert(hostkeys[fp], ip) - end - end - end + -- create a reverse mapping key_fingerprint -> host(s) + for ip, keys in pairs(tab) do + for _, key in ipairs(keys) do + local fp = ssh1.fingerprint_hex(key.fingerprint, key.algorithm, key.bits) + if not hostkeys[fp] then + hostkeys[fp] = {} + end + -- discard duplicate IPs + if not stdnse.contains(hostkeys[fp], ip) then + table.insert(hostkeys[fp], ip) + end + end + end - -- look for hosts using the same hostkey - local results = {} - for key, hosts in pairs(hostkeys) do - if #hostkeys[key] > 1 then - table.sort(hostkeys[key], function(a, b) return ipOps.compare_ip(a, "lt", b) end) - local str = 'Key ' .. key .. ':' - table.insert( results, { name = str, hostkeys[key] } ) - end - end + -- look for hosts using the same hostkey + local results = {} + for key, hosts in pairs(hostkeys) do + if #hostkeys[key] > 1 then + table.sort(hostkeys[key], function(a, b) return ipOps.compare_ip(a, "lt", b) end) + local str = 'Key ' .. key .. ':' + table.insert( results, { name = str, hostkeys[key] } ) + end + end - return results + return results end local function processNBStat(tab) - local results, mac_table, name_table = {}, {}, {} - for host, v in pairs(tab) do - mac_table[v.mac] = mac_table[v.mac] or {} - if ( not(stdnse.contains(mac_table[v.mac], host.ip)) ) then - table.insert(mac_table[v.mac], host.ip) - end + local results, mac_table, name_table = {}, {}, {} + for host, v in pairs(tab) do + mac_table[v.mac] = mac_table[v.mac] or {} + if ( not(stdnse.contains(mac_table[v.mac], host.ip)) ) then + table.insert(mac_table[v.mac], host.ip) + end - name_table[v.server_name] = name_table[v.server_name] or {} - if ( not(stdnse.contains(name_table[v.server_name], host.ip)) ) then - table.insert(name_table[v.server_name], host.ip) - end - end + name_table[v.server_name] = name_table[v.server_name] or {} + if ( not(stdnse.contains(name_table[v.server_name], host.ip)) ) then + table.insert(name_table[v.server_name], host.ip) + end + end - for mac, hosts in pairs(mac_table) do - if ( #hosts > 1 ) then - table.sort(hosts, function(a, b) return ipOps.compare_ip(a, "lt", b) end) - table.insert(results, { name = ("MAC: %s"):format(mac), hosts }) - end - end + for mac, hosts in pairs(mac_table) do + if ( #hosts > 1 ) then + table.sort(hosts, function(a, b) return ipOps.compare_ip(a, "lt", b) end) + table.insert(results, { name = ("MAC: %s"):format(mac), hosts }) + end + end - for srvname, hosts in pairs(name_table) do - if ( #hosts > 1 ) then - table.sort(hosts, function(a, b) return ipOps.compare_ip(a, "lt", b) end) - table.insert(results, { name = ("Server Name: %s"):format(srvname), hosts }) - end - end + for srvname, hosts in pairs(name_table) do + if ( #hosts > 1 ) then + table.sort(hosts, function(a, b) return ipOps.compare_ip(a, "lt", b) end) + table.insert(results, { name = ("Server Name: %s"):format(srvname), hosts }) + end + end - return results + return results end local function processMAC(tab) - local mac - local mac_table = {} + local mac + local mac_table = {} - for host in pairs(tab) do - if ( host.mac_addr ) then - mac = stdnse.format_mac(host.mac_addr) - mac_table[mac] = mac_table[mac] or {} - if ( not(stdnse.contains(mac_table[mac], host.ip)) ) then - table.insert(mac_table[mac], host.ip) - end - end - end + for host in pairs(tab) do + if ( host.mac_addr ) then + mac = stdnse.format_mac(host.mac_addr) + mac_table[mac] = mac_table[mac] or {} + if ( not(stdnse.contains(mac_table[mac], host.ip)) ) then + table.insert(mac_table[mac], host.ip) + end + end + end - local results = {} - for mac, hosts in pairs(mac_table) do - if ( #hosts > 1 ) then - table.sort(hosts, function(a, b) return ipOps.compare_ip(a, "lt", b) end) - table.insert(results, { name = ("MAC: %s"):format(mac), hosts }) - end - end + local results = {} + for mac, hosts in pairs(mac_table) do + if ( #hosts > 1 ) then + table.sort(hosts, function(a, b) return ipOps.compare_ip(a, "lt", b) end) + table.insert(results, { name = ("MAC: %s"):format(mac), hosts }) + end + end - return results + return results end postaction = function() - local handlers = { - ['ssl-cert'] = { func = processSSLCerts, name = "SSL" }, - ['sshhostkey'] = { func = processSSHKeys, name = "SSH" }, - ['nbstat'] = { func = processNBStat, name = "Netbios" }, - ['mac'] = { func = processMAC, name = "ARP" } - } + local handlers = { + ['ssl-cert'] = { func = processSSLCerts, name = "SSL" }, + ['sshhostkey'] = { func = processSSHKeys, name = "SSH" }, + ['nbstat'] = { func = processNBStat, name = "Netbios" }, + ['mac'] = { func = processMAC, name = "ARP" } + } - -- temporary re-allocation code for SSH keys - for k, v in pairs(nmap.registry.sshhostkey or {}) do - nmap.registry['duplicates'] = nmap.registry['duplicates'] or {} - nmap.registry['duplicates']['sshhostkey'] = nmap.registry['duplicates']['sshhostkey'] or {} - nmap.registry['duplicates']['sshhostkey'][k] = v - end + -- temporary re-allocation code for SSH keys + for k, v in pairs(nmap.registry.sshhostkey or {}) do + nmap.registry['duplicates'] = nmap.registry['duplicates'] or {} + nmap.registry['duplicates']['sshhostkey'] = nmap.registry['duplicates']['sshhostkey'] or {} + nmap.registry['duplicates']['sshhostkey'][k] = v + end - if ( not(nmap.registry['duplicates']) ) then - return - end + if ( not(nmap.registry['duplicates']) ) then + return + end - local results = {} - for key, handler in pairs(handlers) do - if ( nmap.registry['duplicates'][key] ) then - local result_part = handler.func( nmap.registry['duplicates'][key] ) - if ( result_part and #result_part > 0 ) then - table.insert(results, { name = handler.name, result_part } ) - end - end - end + local results = {} + for key, handler in pairs(handlers) do + if ( nmap.registry['duplicates'][key] ) then + local result_part = handler.func( nmap.registry['duplicates'][key] ) + if ( result_part and #result_part > 0 ) then + table.insert(results, { name = handler.name, result_part } ) + end + end + end - return stdnse.format_output(true, results) + return stdnse.format_output(true, results) end -- we have no real action in here. In essence we move information from the @@ -213,25 +213,25 @@ end -- it when we need it. hostaction = function(host) - nmap.registry['duplicates'] = nmap.registry['duplicates'] or {} + nmap.registry['duplicates'] = nmap.registry['duplicates'] or {} - for port, cert in pairs(host.registry["ssl-cert"] or {}) do - nmap.registry['duplicates']['ssl-cert'] = nmap.registry['duplicates']['ssl-cert'] or {} - nmap.registry['duplicates']['ssl-cert'][host] = nmap.registry['duplicates']['ssl-cert'][host] or {} - nmap.registry['duplicates']['ssl-cert'][host][port] = stdnse.tohex(cert:digest("sha1"), { separator = " ", group = 4 }) - end + for port, cert in pairs(host.registry["ssl-cert"] or {}) do + nmap.registry['duplicates']['ssl-cert'] = nmap.registry['duplicates']['ssl-cert'] or {} + nmap.registry['duplicates']['ssl-cert'][host] = nmap.registry['duplicates']['ssl-cert'][host] or {} + nmap.registry['duplicates']['ssl-cert'][host][port] = stdnse.tohex(cert:digest("sha1"), { separator = " ", group = 4 }) + end - if ( host.registry['nbstat'] ) then - nmap.registry['duplicates']['nbstat'] = nmap.registry['duplicates']['nbstat'] or {} - nmap.registry['duplicates']['nbstat'][host] = host.registry['nbstat'] - end + if ( host.registry['nbstat'] ) then + nmap.registry['duplicates']['nbstat'] = nmap.registry['duplicates']['nbstat'] or {} + nmap.registry['duplicates']['nbstat'][host] = host.registry['nbstat'] + end - if ( host.mac_addr_src ) then - nmap.registry['duplicates']['mac'] = nmap.registry['duplicates']['mac'] or {} - nmap.registry['duplicates']['mac'][host] = true - end + if ( host.mac_addr_src ) then + nmap.registry['duplicates']['mac'] = nmap.registry['duplicates']['mac'] or {} + nmap.registry['duplicates']['mac'][host] = true + end - return + return end local Actions = { diff --git a/scripts/eap-info.nse b/scripts/eap-info.nse index 157c82ce3..3fd03ffa6 100644 --- a/scripts/eap-info.nse +++ b/scripts/eap-info.nse @@ -36,159 +36,159 @@ categories = { "broadcast", "safe" } prerule = function() - return nmap.is_privileged() + return nmap.is_privileged() end local default_scan = { - eap.eap_t.TLS, - eap.eap_t.TTLS, - eap.eap_t.PEAP, - eap.eap_t.MSCHAP, + eap.eap_t.TLS, + eap.eap_t.TTLS, + eap.eap_t.PEAP, + eap.eap_t.MSCHAP, } local UNKNOWN = "unknown" action = function() - local arg_interface = stdnse.get_script_args(SCRIPT_NAME .. ".interface") - local arg_identity = stdnse.get_script_args(SCRIPT_NAME .. ".identity") - local arg_scan = stdnse.get_script_args(SCRIPT_NAME .. ".scan") - local arg_timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout")) - local iface + local arg_interface = stdnse.get_script_args(SCRIPT_NAME .. ".interface") + local arg_identity = stdnse.get_script_args(SCRIPT_NAME .. ".identity") + local arg_scan = stdnse.get_script_args(SCRIPT_NAME .. ".scan") + local arg_timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout")) + local iface - -- trying with provided interface name - if arg_interface then - iface = nmap.get_interface_info(arg_interface) - end + -- trying with provided interface name + if arg_interface then + iface = nmap.get_interface_info(arg_interface) + end - -- trying with default nmap interface - if not iface then - local iname = nmap.get_interface() - if iname then - iface = nmap.get_interface_info(iname) - end - end + -- trying with default nmap interface + if not iface then + local iname = nmap.get_interface() + if iname then + iface = nmap.get_interface_info(iname) + end + end - -- failed - if not iface then - return "please specify an interface with -e" - end - stdnse.print_debug(1, "iface: %s", iface.device) + -- failed + if not iface then + return "please specify an interface with -e" + end + stdnse.print_debug(1, "iface: %s", iface.device) - local timeout = (arg_timeout or 10) * 1000 + local timeout = (arg_timeout or 10) * 1000 - stdnse.print_debug(2, "timeout: %s", timeout) + stdnse.print_debug(2, "timeout: %s", timeout) - local pcap = nmap.new_socket() - pcap:pcap_open(iface.device, 512, true, "ether proto 0x888e") + local pcap = nmap.new_socket() + pcap:pcap_open(iface.device, 512, true, "ether proto 0x888e") - local identity = { name="anonymous", auth = {}, probe = -1 } + local identity = { name="anonymous", auth = {}, probe = -1 } - if arg_identity then - identity.name = tostring(arg_identity) - end + if arg_identity then + identity.name = tostring(arg_identity) + end - local scan - if arg_scan == nil or type(arg_scan) ~= "table" or #arg_scan == 0 then - scan = default_scan - else - scan = arg_scan - end + local scan + if arg_scan == nil or type(arg_scan) ~= "table" or #arg_scan == 0 then + scan = default_scan + else + scan = arg_scan + end - local valid = false - for i,v in ipairs(scan) do - v = tonumber(v) - if v ~= nil and v < 256 and v > 3 then - stdnse.print_debug(1, "selected: %s", eap.eap_str[v] or "unassigned" ) - identity.auth[v] = UNKNOWN - valid = true - end - end + local valid = false + for i,v in ipairs(scan) do + v = tonumber(v) + if v ~= nil and v < 256 and v > 3 then + stdnse.print_debug(1, "selected: %s", eap.eap_str[v] or "unassigned" ) + identity.auth[v] = UNKNOWN + valid = true + end + end - if not valid then - return "no valid scan methods provided" - end + if not valid then + return "no valid scan methods provided" + end - local tried_all = false + local tried_all = false - local start_time = nmap.clock_ms() - eap.send_start(iface) + local start_time = nmap.clock_ms() + eap.send_start(iface) - while(nmap.clock_ms() - start_time < timeout) and not tried_all do - local status, plen, l2_data, l3_data, time = pcap:pcap_receive() - if (status) then - stdnse.print_debug(2, "packet size: 0x%x", plen ) - local packet = eap.parse(l2_data .. l3_data) + while(nmap.clock_ms() - start_time < timeout) and not tried_all do + local status, plen, l2_data, l3_data, time = pcap:pcap_receive() + if (status) then + stdnse.print_debug(2, "packet size: 0x%x", plen ) + local packet = eap.parse(l2_data .. l3_data) - if packet then - stdnse.print_debug(2, "packet valid") + if packet then + stdnse.print_debug(2, "packet valid") - -- respond to identity requests, using the same session id - if packet.eap.type == eap.eap_t.IDENTITY and packet.eap.code == eap.code_t.REQUEST then - stdnse.print_debug(1, "server identity: %s",packet.eap.body.identity) - eap.send_identity_response(iface, packet.eap.id, identity.name) - end + -- respond to identity requests, using the same session id + if packet.eap.type == eap.eap_t.IDENTITY and packet.eap.code == eap.code_t.REQUEST then + stdnse.print_debug(1, "server identity: %s",packet.eap.body.identity) + eap.send_identity_response(iface, packet.eap.id, identity.name) + end - -- respond with NAK to every auth request to enumerate them until we get a failure - if packet.eap.type ~= eap.eap_t.IDENTITY and packet.eap.code == eap.code_t.REQUEST then - stdnse.print_debug(1, "auth request: %s",eap.eap_str[packet.eap.type]) - identity.auth[packet.eap.type] = true + -- respond with NAK to every auth request to enumerate them until we get a failure + if packet.eap.type ~= eap.eap_t.IDENTITY and packet.eap.code == eap.code_t.REQUEST then + stdnse.print_debug(1, "auth request: %s",eap.eap_str[packet.eap.type]) + identity.auth[packet.eap.type] = true - identity.probe = -1 - for i,v in pairs(identity.auth) do - stdnse.print_debug(1, "identity.auth: %d %s",i,tostring(v)) - if v == UNKNOWN then - identity.probe = i - eap.send_nak_response(iface, packet.eap.id, i) - break - end - end - if identity.probe == -1 then tried_all = true end - end + identity.probe = -1 + for i,v in pairs(identity.auth) do + stdnse.print_debug(1, "identity.auth: %d %s",i,tostring(v)) + if v == UNKNOWN then + identity.probe = i + eap.send_nak_response(iface, packet.eap.id, i) + break + end + end + if identity.probe == -1 then tried_all = true end + end - -- retry on failure - if packet.eap.code == eap.code_t.FAILURE then - stdnse.print_debug(1, "auth failure") - identity.auth[identity.probe] = false + -- retry on failure + if packet.eap.code == eap.code_t.FAILURE then + stdnse.print_debug(1, "auth failure") + identity.auth[identity.probe] = false - -- don't give up at the first failure! - -- mac spoofing to avoid to wait too much - local d = string.byte(iface.mac,6) - d = (d + 1) % 256 - iface.mac = iface.mac:sub(1,5) .. bin.pack("C",d) + -- don't give up at the first failure! + -- mac spoofing to avoid to wait too much + local d = string.byte(iface.mac,6) + d = (d + 1) % 256 + iface.mac = iface.mac:sub(1,5) .. bin.pack("C",d) - tried_all = true - for i,v in pairs(identity.auth) do - if v == UNKNOWN then - tried_all = false - break - end - end - if not tried_all then - eap.send_start(iface) - end - end + tried_all = true + for i,v in pairs(identity.auth) do + if v == UNKNOWN then + tried_all = false + break + end + end + if not tried_all then + eap.send_start(iface) + end + end - else - stdnse.print_debug(1, "packet invalid! wrong filter?") - end - end - end + else + stdnse.print_debug(1, "packet invalid! wrong filter?") + end + end + end - local results = { ["name"] = ("Available authentication methods with identity=\"%s\" on interface %s"):format(identity.name, iface.device) } - for i,v in pairs(identity.auth) do - if v== true then - table.insert(results, 1, ("%-8s %s"):format(tostring(v), eap.eap_str[i] or "unassigned" )) - else - table.insert(results, ("%-8s %s"):format(tostring(v), eap.eap_str[i] or "unassigned" )) - end - end + local results = { ["name"] = ("Available authentication methods with identity=\"%s\" on interface %s"):format(identity.name, iface.device) } + for i,v in pairs(identity.auth) do + if v== true then + table.insert(results, 1, ("%-8s %s"):format(tostring(v), eap.eap_str[i] or "unassigned" )) + else + table.insert(results, ("%-8s %s"):format(tostring(v), eap.eap_str[i] or "unassigned" )) + end + end - for i,v in ipairs(results) do - stdnse.print_debug(1, "%s", tostring(v)) - end + for i,v in ipairs(results) do + stdnse.print_debug(1, "%s", tostring(v)) + end - return stdnse.format_output(true, results) + return stdnse.format_output(true, results) end diff --git a/scripts/firewall-bypass.nse b/scripts/firewall-bypass.nse index 90593ee5d..7ee7a9266 100644 --- a/scripts/firewall-bypass.nse +++ b/scripts/firewall-bypass.nse @@ -43,234 +43,234 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"vuln", "intrusive"} ftp_helper = { - should_run = function(host, helperport) - local helperport = helperport or 21 - -- IPv4 and IPv6 are supported - if nmap.address_family() ~= 'inet' and nmap.address_family() ~= 'inet6' then - return false + should_run = function(host, helperport) + local helperport = helperport or 21 + -- IPv4 and IPv6 are supported + if nmap.address_family() ~= 'inet' and nmap.address_family() ~= 'inet6' then + return false + end + + -- Test if helper port is open + local testsock = nmap.new_socket() + testsock:set_timeout(1000) + local status, _ = testsock:connect(host.ip, helperport) + testsock:close() + if not status then + stdnse.print_debug("%s Unable to connect to %s helper port.", SCRIPT_NAME, helperport) + return false + end + return true + end, + + attack = function(host, helperport, targetport) + local ethertype, payload + local isIp4 = nmap.address_family() == 'inet' -- True if we are using IPv4. Otherwise, it is IPv6 + + if isIp4 then + -- IPv4 payload + payload = "227 Entering Passive Mode (" .. + string.gsub(host.ip,"%.",",") .. "," .. + bit.band(bit.rshift(targetport, 8), 0xff) .. + "," .. bit.band(targetport, 0xff) .. + ")\r\n" + ethertype = string.char(0x08, 0x00) -- Ethernet Type: IPv4 + + else + -- IPv6 payload + payload = "229 Extended Passive Mode OK (|||" .. targetport .. "|)\r\n" + ethertype = string.char(0x86, 0xdd) -- Ethernet Type: IPv6 + end + + helperport = helperport or 21 + local function spoof_ftp_packet(host, helperport, targetport) + -- Sniffs the network for src host host.ip and src port helperport + local filter = "src host " .. host.ip .. " and tcp src port " .. helperport + local status, l2data, l3data + local timeout = 1000 + local start = nmap.clock_ms() + + -- Start sniffing + local sniffer = nmap.new_socket() + sniffer:set_timeout(100) + sniffer:pcap_open(host.interface, 256, true, filter) + + -- Until we get adequate packet + while (nmap.clock_ms() - start) < timeout do + local _ + status, _, l2data, l3data = sniffer:pcap_receive() + if status and string.find(l3data, "220 ") then + break end + end - -- Test if helper port is open - local testsock = nmap.new_socket() - testsock:set_timeout(1000) - local status, _ = testsock:connect(host.ip, helperport) - testsock:close() - if not status then - stdnse.print_debug("%s Unable to connect to %s helper port.", SCRIPT_NAME, helperport) - return false + -- Get ethernet values + local f = packet.Frame:new(l2data) + f:ether_parse() + + local p = packet.Packet:new(l3data, #l3data) + if isIp4 then + if not p:ip_parse() then + -- An error happened + stdnse.print_debug("%s Couldn't parse IPv4 sniffed packet.", SCRIPT_NAME) + sniffer:pcap_close() + return false end - return true - end, - - attack = function(host, helperport, targetport) - local ethertype, payload - local isIp4 = nmap.address_family() == 'inet' -- True if we are using IPv4. Otherwise, it is IPv6 - - if isIp4 then - -- IPv4 payload - payload = "227 Entering Passive Mode (" .. - string.gsub(host.ip,"%.",",") .. "," .. - bit.band(bit.rshift(targetport, 8), 0xff) .. - "," .. bit.band(targetport, 0xff) .. - ")\r\n" - ethertype = string.char(0x08, 0x00) -- Ethernet Type: IPv4 - - else - -- IPv6 payload - payload = "229 Extended Passive Mode OK (|||" .. targetport .. "|)\r\n" - ethertype = string.char(0x86, 0xdd) -- Ethernet Type: IPv6 - end - - helperport = helperport or 21 - local function spoof_ftp_packet(host, helperport, targetport) - -- Sniffs the network for src host host.ip and src port helperport - local filter = "src host " .. host.ip .. " and tcp src port " .. helperport - local status, l2data, l3data - local timeout = 1000 - local start = nmap.clock_ms() - - -- Start sniffing - local sniffer = nmap.new_socket() - sniffer:set_timeout(100) - sniffer:pcap_open(host.interface, 256, true, filter) - - -- Until we get adequate packet - while (nmap.clock_ms() - start) < timeout do - local _ - status, _, l2data, l3data = sniffer:pcap_receive() - if status and string.find(l3data, "220 ") then - break - end - end - - -- Get ethernet values - local f = packet.Frame:new(l2data) - f:ether_parse() - - local p = packet.Packet:new(l3data, #l3data) - if isIp4 then - if not p:ip_parse() then - -- An error happened - stdnse.print_debug("%s Couldn't parse IPv4 sniffed packet.", SCRIPT_NAME) - sniffer:pcap_close() - return false - end - else - if not p:ip6_parse() then - -- An error happened - stdnse.print_debug("%s Couldn't parse IPv6 sniffed packet.", SCRIPT_NAME) - sniffer:pcap_close() - return false - end - end - - -- Spoof packet - -- 1. Invert ethernet addresses - f.frame_buf = f.mac_src .. f.mac_dst .. ethertype - - -- 2. Modify packet payload - p.buf = string.sub(p.buf, 1, p.tcp_data_offset) .. payload - -- 3. Increment IP ID field (IPv4 packets) - if isIp4 then - p:ip_set_id(p.ip_id + 1) - end - - -- 4. Set TCP sequence number correctly using traffic data - p:tcp_set_seq(p.tcp_seq + p.tcp_data_length) - - -- 5. Update all checksums and lengths - if isIp4 then - -- Packet length field - p:ip_set_len(#p.buf) - p:ip_count_checksum() - else - -- Payload length field - p:ip6_set_plen(#p.buf - p.tcp_offset) - end - p:tcp_count_checksum() - - -- and finally, we send it. - local dnet = nmap.new_dnet() - dnet:ethernet_open(host.interface) - dnet:ethernet_send(f.frame_buf .. p.buf) - status = sniffer:pcap_receive() - dnet:ethernet_close() - return true + else + if not p:ip6_parse() then + -- An error happened + stdnse.print_debug("%s Couldn't parse IPv6 sniffed packet.", SCRIPT_NAME) + sniffer:pcap_close() + return false end + end - local co = stdnse.new_thread(spoof_ftp_packet, host, helperport, targetport) + -- Spoof packet + -- 1. Invert ethernet addresses + f.frame_buf = f.mac_src .. f.mac_dst .. ethertype - -- Wait for packet spoofing thread - stdnse.sleep(1) - -- Make connection to the target while packet the spoofing thread is sniffing for packets - local socket = nmap.new_socket() - socket:set_timeout(3000) - local status, _ = socket:connect(host.ip, helperport) - if not status then - -- Problem connecting to helper port - stdnse.print_debug("%s Problem connecting to helper port %s.", SCRIPT_NAME, tostring(helperport)) - return - end + -- 2. Modify packet payload + p.buf = string.sub(p.buf, 1, p.tcp_data_offset) .. payload + -- 3. Increment IP ID field (IPv4 packets) + if isIp4 then + p:ip_set_id(p.ip_id + 1) + end - -- wait packet spoofing thread to finish - stdnse.sleep(1.5) - socket:close() - return - end, + -- 4. Set TCP sequence number correctly using traffic data + p:tcp_set_seq(p.tcp_seq + p.tcp_data_length) + + -- 5. Update all checksums and lengths + if isIp4 then + -- Packet length field + p:ip_set_len(#p.buf) + p:ip_count_checksum() + else + -- Payload length field + p:ip6_set_plen(#p.buf - p.tcp_offset) + end + p:tcp_count_checksum() + + -- and finally, we send it. + local dnet = nmap.new_dnet() + dnet:ethernet_open(host.interface) + dnet:ethernet_send(f.frame_buf .. p.buf) + status = sniffer:pcap_receive() + dnet:ethernet_close() + return true + end + + local co = stdnse.new_thread(spoof_ftp_packet, host, helperport, targetport) + + -- Wait for packet spoofing thread + stdnse.sleep(1) + -- Make connection to the target while packet the spoofing thread is sniffing for packets + local socket = nmap.new_socket() + socket:set_timeout(3000) + local status, _ = socket:connect(host.ip, helperport) + if not status then + -- Problem connecting to helper port + stdnse.print_debug("%s Problem connecting to helper port %s.", SCRIPT_NAME, tostring(helperport)) + return + end + + -- wait packet spoofing thread to finish + stdnse.sleep(1.5) + socket:close() + return + end, } -- List of helpers local helpers = { - ftp = ftp_helper, -- FTP (IPv4 and IPv6) + ftp = ftp_helper, -- FTP (IPv4 and IPv6) } local helper hostrule = function(host) - helper = stdnse.get_script_args(SCRIPT_NAME .. ".helper") + helper = stdnse.get_script_args(SCRIPT_NAME .. ".helper") - if not nmap.is_privileged() then - nmap.registry[SCRIPT_NAME] = nmap.registry[SCRIPT_NAME] or {} - if not nmap.registry[SCRIPT_NAME].rootfail then - stdnse.print_verbose("%s lacks privileges.", SCRIPT_NAME ) - nmap.registry[SCRIPT_NAME].rootfail = true - end - return false + if not nmap.is_privileged() then + nmap.registry[SCRIPT_NAME] = nmap.registry[SCRIPT_NAME] or {} + if not nmap.registry[SCRIPT_NAME].rootfail then + stdnse.print_verbose("%s lacks privileges.", SCRIPT_NAME ) + nmap.registry[SCRIPT_NAME].rootfail = true end + return false + end - if not host.interface then - return false - end + if not host.interface then + return false + end - if helper and not helpers[helper] then - stdnse.print_debug("%s %s helper not supported at the moment.", SCRIPT_NAME, helper) - return false - end + if helper and not helpers[helper] then + stdnse.print_debug("%s %s helper not supported at the moment.", SCRIPT_NAME, helper) + return false + end - return true + return true end action = function(host, port) - local helperport = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".helperport")) - local targetport = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".targetport")) - local helpername + local helperport = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".helperport")) + local targetport = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".targetport")) + local helpername - if targetport then - -- We should check if target port is not already open - local testsock = nmap.new_socket() - testsock:set_timeout(1000) - local status, _ = testsock:connect(host.ip, targetport) - if status then - stdnse.print_debug("%s %s target port already open.", SCRIPT_NAME, targetport) - return nil - end - testsock:close() - else - -- If not target port specified, we try to get a filtered port, - -- which would be more likely blocked by a firewall before looking for a closed one. - local port = nmap.get_ports(host, nil, "tcp", "filtered") or nmap.get_ports(host, nil, "tcp", "closed") - if port then - targetport = port.number - stdnse.print_debug("%s %s chosen as target port.", SCRIPT_NAME, targetport) - else - -- No closed or filtered ports to check on. - stdnse.print_debug("%s Target port not specified and no closed or filtered port found.", SCRIPT_NAME) - return - end - end - -- If helper chosen by user - if helper then - if helpers[helper].should_run(host, helperport) then - helpers[helper].attack(host, helperport, targetport) - else - return - end - -- If no helper chosen manually, we iterate over table to find a suitable one. - else - for i, helper in pairs(helpers) do - if helper.should_run(host, helperport) then - helpername = i - stdnse.print_debug("%s %s chosen as helper.", SCRIPT_NAME, helpername) - helper.attack(host, helperport, targetport) - break - end - end - if not helpername then - stdnse.print_debug("%s no suitable helper found.", SCRIPT_NAME) - return nil - end - end - - -- Then we check if target port is now open. + if targetport then + -- We should check if target port is not already open local testsock = nmap.new_socket() testsock:set_timeout(1000) local status, _ = testsock:connect(host.ip, targetport) - testsock:close() if status then - -- If we could connect, then port is open and firewall is vulnerable. - local vulnstring = "Firewall vulnerable to bypass through " .. (helper or helpername) .. " helper. " - .. (nmap.address_family() == 'inet' and "(IPv4)" or "(IPv6)") - - return stdnse.format_output(true, vulnstring) + stdnse.print_debug("%s %s target port already open.", SCRIPT_NAME, targetport) + return nil end + testsock:close() + else + -- If not target port specified, we try to get a filtered port, + -- which would be more likely blocked by a firewall before looking for a closed one. + local port = nmap.get_ports(host, nil, "tcp", "filtered") or nmap.get_ports(host, nil, "tcp", "closed") + if port then + targetport = port.number + stdnse.print_debug("%s %s chosen as target port.", SCRIPT_NAME, targetport) + else + -- No closed or filtered ports to check on. + stdnse.print_debug("%s Target port not specified and no closed or filtered port found.", SCRIPT_NAME) + return + end + end + -- If helper chosen by user + if helper then + if helpers[helper].should_run(host, helperport) then + helpers[helper].attack(host, helperport, targetport) + else + return + end + -- If no helper chosen manually, we iterate over table to find a suitable one. + else + for i, helper in pairs(helpers) do + if helper.should_run(host, helperport) then + helpername = i + stdnse.print_debug("%s %s chosen as helper.", SCRIPT_NAME, helpername) + helper.attack(host, helperport, targetport) + break + end + end + if not helpername then + stdnse.print_debug("%s no suitable helper found.", SCRIPT_NAME) + return nil + end + end + + -- Then we check if target port is now open. + local testsock = nmap.new_socket() + testsock:set_timeout(1000) + local status, _ = testsock:connect(host.ip, targetport) + testsock:close() + if status then + -- If we could connect, then port is open and firewall is vulnerable. + local vulnstring = "Firewall vulnerable to bypass through " .. (helper or helpername) .. " helper. " + .. (nmap.address_family() == 'inet' and "(IPv4)" or "(IPv6)") + + return stdnse.format_output(true, vulnstring) + end end diff --git a/scripts/flume-master-info.nse b/scripts/flume-master-info.nse index c361b0af7..8d9636fe9 100644 --- a/scripts/flume-master-info.nse +++ b/scripts/flume-master-info.nse @@ -86,131 +86,131 @@ categories = {"default", "discovery", "safe"} portrule = function(host, port) - -- Run for the special port number, or for any HTTP-like service that is - -- not on a usual HTTP port. - return shortport.port_or_service ({35871}, "flume-master")(host, port) - or (shortport.service(shortport.LIKELY_HTTP_SERVICES)(host, port) and not shortport.portnumber(shortport.LIKELY_HTTP_PORTS)(host, port)) + -- Run for the special port number, or for any HTTP-like service that is + -- not on a usual HTTP port. + return shortport.port_or_service ({35871}, "flume-master")(host, port) + or (shortport.service(shortport.LIKELY_HTTP_SERVICES)(host, port) and not shortport.portnumber(shortport.LIKELY_HTTP_PORTS)(host, port)) end function add_target(hostname) - if target.ALLOW_NEW_TARGETS then - stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, hostname)) - local status,err = target.add(hostname) - end + if target.ALLOW_NEW_TARGETS then + stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, hostname)) + local status,err = target.add(hostname) + end end -- ref: http://lua-users.org/wiki/TableUtils function table_count(tt, item) - local count - count = 0 - for ii,xx in pairs(tt) do - if item == xx then count = count + 1 end - end - return count + local count + count = 0 + for ii,xx in pairs(tt) do + if item == xx then count = count + 1 end + end + return count end parse_page = function( host, port, uri, intresting_keys ) - local result = {} - local response = http.get( host, port, uri ) - stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response" )) - if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then - local body = response['body']:gsub("%%","%%%%") - for name,value in string.gmatch(body,"([^][<]+)%s*]+>([^][<]+)") do - stdnse.print_debug(1, ("%s: %s=%s "):format(SCRIPT_NAME,name,value:gsub("^%s*(.-)%s*$", "%1"))) - if nmap.verbosity() > 1 then - result[#result+1] = ("%s: %s"):format(name,value:gsub("^%s*(.-)%s*$", "%1")) - else - for i,v in ipairs(intresting_keys) do - if name:match(("^%s"):format(v)) then - result[#result+1] = ("%s: %s"):format(name,value:gsub("^%s*(.-)%s*$", "%1")) - end - end - end - end - end - return result + local result = {} + local response = http.get( host, port, uri ) + stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response" )) + if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then + local body = response['body']:gsub("%%","%%%%") + for name,value in string.gmatch(body,"([^][<]+)%s*]+>([^][<]+)") do + stdnse.print_debug(1, ("%s: %s=%s "):format(SCRIPT_NAME,name,value:gsub("^%s*(.-)%s*$", "%1"))) + if nmap.verbosity() > 1 then + result[#result+1] = ("%s: %s"):format(name,value:gsub("^%s*(.-)%s*$", "%1")) + else + for i,v in ipairs(intresting_keys) do + if name:match(("^%s"):format(v)) then + result[#result+1] = ("%s: %s"):format(name,value:gsub("^%s*(.-)%s*$", "%1")) + end + end + end + end + end + return result end action = function( host, port ) - local result = {} - local uri = "/flumemaster.jsp" - local env_uri = "/masterenv.jsp" - local config_uri = "/masterstaticconfig.jsp" - local env_keys = {"java.runtime","java.version","java.vm.name","java.vm.vendor","java.vm.version","os","user.name","user.country","user.language,user.timezone"} - local config_keys = {"dfs.datanode.address","dfs.datanode.http.address","dfs.datanode.https.address","dfs.datanode.ipc.address","dfs.http.address","dfs.https.address","dfs.secondary.http.address","flume.collector.dfs.dir","flume.collector.event.host","flume.master.servers","fs.default.name","mapred.job.tracker","mapred.job.tracker.http.address","mapred.task.tracker.http.address","mapred.task.tracker.report.address"} - local nodes = { } - local zookeepers = { } - local hbasemasters = { } - stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) - local response = http.get( host, port, uri ) - stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response")) - if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then - local body = response['body']:gsub("%%","%%%%") - local capacity = {} - stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body)) - if body:match("Version:%s*([^][,]+)") then - local version = body:match("Version:%s*([^][,]+)") - stdnse.print_debug(1, ("%s: Version %s"):format(SCRIPT_NAME,version)) - result[#result+1] = ("Version: %s"):format(version) - port.version.version = version - end - if body:match("Compiled:%s*([^][<]+)") then - local compiled = body:match("Compiled:%s*([^][<]+)") - stdnse.print_debug(1, ("%s: Compiled %s"):format(SCRIPT_NAME,compiled)) - result[#result+1] = ("Compiled: %s"):format(compiled) - end - if body:match("ServerID:%s*([^][<]+)") then - local upgrades = body:match("ServerID:%s*([^][<]+)") - stdnse.print_debug(1, ("%s: ServerID %s"):format(SCRIPT_NAME,upgrades)) - result[#result] = ("ServerID: %s"):format(upgrades) - end - for logical,physical,hostname in string.gmatch(body,"([%w%.-_:]+)([%w%.]+)([%w%.]+)") do - stdnse.print_debug(2, ("%s: %s (%s) %s"):format(SCRIPT_NAME,physical,logical,hostname)) - if (table_count(nodes, hostname) == 0) then - nodes[#nodes+1] = hostname - add_target(hostname) - end - end - if next(nodes) ~= nil then - table.insert(result, "Flume nodes:") - result[#result+1] = nodes - end - for zookeeper in string.gmatch(body,"Dhbase.zookeeper.quorum=([^][\"]+)") do - if (table_count(zookeepers, zookeeper) == 0) then - zookeepers[#zookeepers+1] = zookeeper - add_target(zookeeper) - end - end - if next(zookeepers) ~= nil then - result[#result+1] = "Zookeeper Master:" - result[#result+1] = zookeepers - end - for hbasemaster in string.gmatch(body,"Dhbase.rootdir=([^][\"]+)") do - if (table_count(hbasemasters, hbasemaster) == 0) then - hbasemasters[#hbasemasters+1] = hbasemaster - add_target(hbasemaster) - end - end - if next(hbasemasters) ~= nil then - result[#result+1] = "Hbase Master Master:" - result[#result+1] = hbasemasters - end - local vars = parse_page(host, port, env_uri, env_keys ) - if next(vars) ~= nil then - result[#result+1] = "Enviroment: " - result[#result+1] = vars - end - local vars = parse_page(host, port, config_uri, config_keys ) - if next(vars) ~= nil then - result[#result+1] = "Config: " - result[#result+1] = vars - end - if #result > 0 then - port.version.name = "flume-master" - port.version.product = "Apache Flume" - nmap.set_port_version(host, port) - end - return stdnse.format_output(true, result) - end + local result = {} + local uri = "/flumemaster.jsp" + local env_uri = "/masterenv.jsp" + local config_uri = "/masterstaticconfig.jsp" + local env_keys = {"java.runtime","java.version","java.vm.name","java.vm.vendor","java.vm.version","os","user.name","user.country","user.language,user.timezone"} + local config_keys = {"dfs.datanode.address","dfs.datanode.http.address","dfs.datanode.https.address","dfs.datanode.ipc.address","dfs.http.address","dfs.https.address","dfs.secondary.http.address","flume.collector.dfs.dir","flume.collector.event.host","flume.master.servers","fs.default.name","mapred.job.tracker","mapred.job.tracker.http.address","mapred.task.tracker.http.address","mapred.task.tracker.report.address"} + local nodes = { } + local zookeepers = { } + local hbasemasters = { } + stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) + local response = http.get( host, port, uri ) + stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response")) + if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then + local body = response['body']:gsub("%%","%%%%") + local capacity = {} + stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body)) + if body:match("Version:%s*([^][,]+)") then + local version = body:match("Version:%s*([^][,]+)") + stdnse.print_debug(1, ("%s: Version %s"):format(SCRIPT_NAME,version)) + result[#result+1] = ("Version: %s"):format(version) + port.version.version = version + end + if body:match("Compiled:%s*([^][<]+)") then + local compiled = body:match("Compiled:%s*([^][<]+)") + stdnse.print_debug(1, ("%s: Compiled %s"):format(SCRIPT_NAME,compiled)) + result[#result+1] = ("Compiled: %s"):format(compiled) + end + if body:match("ServerID:%s*([^][<]+)") then + local upgrades = body:match("ServerID:%s*([^][<]+)") + stdnse.print_debug(1, ("%s: ServerID %s"):format(SCRIPT_NAME,upgrades)) + result[#result] = ("ServerID: %s"):format(upgrades) + end + for logical,physical,hostname in string.gmatch(body,"([%w%.-_:]+)([%w%.]+)([%w%.]+)") do + stdnse.print_debug(2, ("%s: %s (%s) %s"):format(SCRIPT_NAME,physical,logical,hostname)) + if (table_count(nodes, hostname) == 0) then + nodes[#nodes+1] = hostname + add_target(hostname) + end + end + if next(nodes) ~= nil then + table.insert(result, "Flume nodes:") + result[#result+1] = nodes + end + for zookeeper in string.gmatch(body,"Dhbase.zookeeper.quorum=([^][\"]+)") do + if (table_count(zookeepers, zookeeper) == 0) then + zookeepers[#zookeepers+1] = zookeeper + add_target(zookeeper) + end + end + if next(zookeepers) ~= nil then + result[#result+1] = "Zookeeper Master:" + result[#result+1] = zookeepers + end + for hbasemaster in string.gmatch(body,"Dhbase.rootdir=([^][\"]+)") do + if (table_count(hbasemasters, hbasemaster) == 0) then + hbasemasters[#hbasemasters+1] = hbasemaster + add_target(hbasemaster) + end + end + if next(hbasemasters) ~= nil then + result[#result+1] = "Hbase Master Master:" + result[#result+1] = hbasemasters + end + local vars = parse_page(host, port, env_uri, env_keys ) + if next(vars) ~= nil then + result[#result+1] = "Enviroment: " + result[#result+1] = vars + end + local vars = parse_page(host, port, config_uri, config_keys ) + if next(vars) ~= nil then + result[#result+1] = "Config: " + result[#result+1] = vars + end + if #result > 0 then + port.version.name = "flume-master" + port.version.product = "Apache Flume" + nmap.set_port_version(host, port) + end + return stdnse.format_output(true, result) + end end diff --git a/scripts/ftp-bounce.nse b/scripts/ftp-bounce.nse index 4193200d0..c513c3b3b 100644 --- a/scripts/ftp-bounce.nse +++ b/scripts/ftp-bounce.nse @@ -34,191 +34,191 @@ categories = {"default", "safe"} portrule = shortport.service("ftp") line_iterate = function(s) - local line - for line in string.gmatch(s, "([^\n$]*)") do - if #line > 0 then - coroutine.yield(line) - end - end + local line + for line in string.gmatch(s, "([^\n$]*)") do + if #line > 0 then + coroutine.yield(line) + end + end end -- returns last ftp code read, or 000 on timeout get_ftp_code = function(socket) - local fcode = 000 - local code = 0 - local status - local result - local co - local line - local err + local fcode = 000 + local code = 0 + local status + local result + local co + local line + local err - while true do - status, result = socket:receive() - if not status then - break - end - -- read okay! - co = coroutine.create(line_iterate) - while coroutine.status(co) ~= 'dead' do - err, line = coroutine.resume(co, result) - if line then - code = string.match(line, "^(%d%d%d) ") - if not code then - code = "-1" - end - -- io.write(">" .. code .. ":".. line .. "<\n") - if tonumber(code) > 0 then - fcode = tonumber(code) - end - end - end - -- not received good ftp code, try again - if fcode ~= 0 then - break - end - end - -- io.write("## " .. fcode .. "\n"); - return fcode + while true do + status, result = socket:receive() + if not status then + break + end + -- read okay! + co = coroutine.create(line_iterate) + while coroutine.status(co) ~= 'dead' do + err, line = coroutine.resume(co, result) + if line then + code = string.match(line, "^(%d%d%d) ") + if not code then + code = "-1" + end + -- io.write(">" .. code .. ":".. line .. "<\n") + if tonumber(code) > 0 then + fcode = tonumber(code) + end + end + end + -- not received good ftp code, try again + if fcode ~= 0 then + break + end + end + -- io.write("## " .. fcode .. "\n"); + return fcode end local get_login = function() - local user, pass - local k + local user, pass + local k - for _, k in ipairs({"ftp-bounce.username", "username"}) do - if nmap.registry.args[k] then - user = nmap.registry.args[k] - break - end - end + for _, k in ipairs({"ftp-bounce.username", "username"}) do + if nmap.registry.args[k] then + user = nmap.registry.args[k] + break + end + end - for _, k in ipairs({"ftp-bounce.password", "password"}) do - if nmap.registry.args[k] then - pass = nmap.registry.args[k] - break - end - end + for _, k in ipairs({"ftp-bounce.password", "password"}) do + if nmap.registry.args[k] then + pass = nmap.registry.args[k] + break + end + end - return user or "anonymous", pass or "IEUser@" + return user or "anonymous", pass or "IEUser@" end action = function(host, port) - local socket = nmap.new_socket() - local result; - local status = true - local isAnon = false - local isOk = false - local sendPass = true - local user, pass = get_login() - local fc + local socket = nmap.new_socket() + local result; + local status = true + local isAnon = false + local isOk = false + local sendPass = true + local user, pass = get_login() + local fc - socket:set_timeout(10000) - socket:connect(host, port) + socket:set_timeout(10000) + socket:connect(host, port) - -- BANNER - fc = get_ftp_code(socket) - if fc == 0 then - socket:close() - -- no banner - return "no banner" - end - if fc == 421 or (fc >= 500 and fc <= 599) then - socket:close() - -- return "server says you are not allowed to create connection" - return - end - if fc < 200 or fc > 299 then - socket:close() - -- bad code - -- return "bad banner (code " .. fc .. ")" - return - end + -- BANNER + fc = get_ftp_code(socket) + if fc == 0 then + socket:close() + -- no banner + return "no banner" + end + if fc == 421 or (fc >= 500 and fc <= 599) then + socket:close() + -- return "server says you are not allowed to create connection" + return + end + if fc < 200 or fc > 299 then + socket:close() + -- bad code + -- return "bad banner (code " .. fc .. ")" + return + end - socket:set_timeout(5000) - -- USER - socket:send("USER " .. user .. "\r\n") - fc = get_ftp_code(socket) - if (fc >= 400 and fc <= 499) or (fc >= 500 and fc <= 599) then - socket:close() - -- bad code - --return "anonymous user not allowed" - return - end - if fc == 0 then - socket:close() - -- return "anonymous user timeouted" - return - end - if fc ~= 230 and fc ~= 331 then - socket:close() - -- bad code - -- return "bad response for anonymous user (code " .. fc .. ")" - return - end - if fc == 230 then - sendPass = false - end + socket:set_timeout(5000) + -- USER + socket:send("USER " .. user .. "\r\n") + fc = get_ftp_code(socket) + if (fc >= 400 and fc <= 499) or (fc >= 500 and fc <= 599) then + socket:close() + -- bad code + --return "anonymous user not allowed" + return + end + if fc == 0 then + socket:close() + -- return "anonymous user timeouted" + return + end + if fc ~= 230 and fc ~= 331 then + socket:close() + -- bad code + -- return "bad response for anonymous user (code " .. fc .. ")" + return + end + if fc == 230 then + sendPass = false + end - -- PASS - if sendPass then - socket:send("PASS " .. pass .. "\r\n") - fc = get_ftp_code(socket) - if (fc >= 500 and fc <= 599) or (fc >= 400 and fc <= 499) then - socket:close() - -- bad code - -- return "anonymous user/pass rejected" - return - end - if fc == 0 then - socket:close() - -- return "anonymous pass timeouted" - return - end - if fc ~= 230 and fc ~= 200 then - socket:close() - -- return "answer to PASS not understood (code " .. fc .. ")" - return - end - end + -- PASS + if sendPass then + socket:send("PASS " .. pass .. "\r\n") + fc = get_ftp_code(socket) + if (fc >= 500 and fc <= 599) or (fc >= 400 and fc <= 499) then + socket:close() + -- bad code + -- return "anonymous user/pass rejected" + return + end + if fc == 0 then + socket:close() + -- return "anonymous pass timeouted" + return + end + if fc ~= 230 and fc ~= 200 then + socket:close() + -- return "answer to PASS not understood (code " .. fc .. ")" + return + end + end - -- PORT scanme.nmap.com:highport - socket:send("PORT 205,217,153,62,80,80\r\n") - fc = get_ftp_code(socket) - if (fc >= 500 and fc <= 599) then - socket:close() - -- return "server forbids bouncing" - return - end - if fc == 0 then - socket:close() - -- return "PORT command timeouted" - return - end - if not (fc >= 200 and fc<=299) then - socket:close() - -- return "PORT response not understood (code " .. fc .. ")" - return - end + -- PORT scanme.nmap.com:highport + socket:send("PORT 205,217,153,62,80,80\r\n") + fc = get_ftp_code(socket) + if (fc >= 500 and fc <= 599) then + socket:close() + -- return "server forbids bouncing" + return + end + if fc == 0 then + socket:close() + -- return "PORT command timeouted" + return + end + if not (fc >= 200 and fc<=299) then + socket:close() + -- return "PORT response not understood (code " .. fc .. ")" + return + end - -- PORT scanme.nmap.com:lowport - socket:send("PORT 205,217,153,62,0,80\r\n") - fc = get_ftp_code(socket) - if (fc >= 500 and fc <= 599) then - socket:close() - return "server forbids bouncing to low ports <1025" - end - if fc == 0 then - socket:close() - -- return "PORT command timeouted for low port" - return - end - if not (fc >= 200 and fc<=299) then - socket:close() - -- return "PORT response not understood for low port (code " .. fc .. ")" - return - end + -- PORT scanme.nmap.com:lowport + socket:send("PORT 205,217,153,62,0,80\r\n") + fc = get_ftp_code(socket) + if (fc >= 500 and fc <= 599) then + socket:close() + return "server forbids bouncing to low ports <1025" + end + if fc == 0 then + socket:close() + -- return "PORT command timeouted for low port" + return + end + if not (fc >= 200 and fc<=299) then + socket:close() + -- return "PORT response not understood for low port (code " .. fc .. ")" + return + end - socket:close() - return "bounce working!" + socket:close() + return "bounce working!" end diff --git a/scripts/gkrellm-info.nse b/scripts/gkrellm-info.nse index 45fbd0a33..f9c4773b2 100644 --- a/scripts/gkrellm-info.nse +++ b/scripts/gkrellm-info.nse @@ -55,167 +55,167 @@ portrule = shortport.port_or_service(19150, "gkrellm", "tcp") local function fail(err) return ("\n ERROR: %s"):format(err or "") end local long_names = { - ["fs_mounts"] = "Mounts", - ["net"] = "Network", - ["hostname"] = "Hostname", - ["sysname"] = "System", - ["version"] = "Version", - ["uptime"] = "Uptime", - ["mem"] = "Memory", - ["proc"] = "Processes", + ["fs_mounts"] = "Mounts", + ["net"] = "Network", + ["hostname"] = "Hostname", + ["sysname"] = "System", + ["version"] = "Version", + ["uptime"] = "Uptime", + ["mem"] = "Memory", + ["proc"] = "Processes", } local order = { - "Hostname", "System", "Version", "Uptime", "Processes", "Memory", "Network", "Mounts" + "Hostname", "System", "Version", "Uptime", "Processes", "Memory", "Network", "Mounts" } local function getOrderPos(tag) - for i=1, #order do - if ( tag.name == order[i] ) then - return i - elseif ( "string" == type(tag) and tag:match("^([^:]*)") == order[i] ) then - return i - end - end - return 1 + for i=1, #order do + if ( tag.name == order[i] ) then + return i + elseif ( "string" == type(tag) and tag:match("^([^:]*)") == order[i] ) then + return i + end + end + return 1 end local function minutesToUptime(value) - local days = math.floor(value / (60 * 24)) - local htime = math.fmod(value, (60 * 24)) - local hours = math.floor(htime / 60) - local mtime = math.fmod(htime, 60) - local minutes = math.floor(mtime) - local output = "" - if ( days > 0 ) then - output = output .. ("%d days, "):format(days) - end - if ( hours > 0 ) then - output = output .. ("%d hours, "):format(hours) - end - if ( minutes > 0 ) then - output = output .. ("%d minutes"):format(minutes) - end - return output + local days = math.floor(value / (60 * 24)) + local htime = math.fmod(value, (60 * 24)) + local hours = math.floor(htime / 60) + local mtime = math.fmod(htime, 60) + local minutes = math.floor(mtime) + local output = "" + if ( days > 0 ) then + output = output .. ("%d days, "):format(days) + end + if ( hours > 0 ) then + output = output .. ("%d hours, "):format(hours) + end + if ( minutes > 0 ) then + output = output .. ("%d minutes"):format(minutes) + end + return output end local function decodeTag(tag, lines) - local result = { name = long_names[tag] } - local order + local result = { name = long_names[tag] } + local order - if ( "fs_mounts" == tag ) then - local fs_tab = tab.new(4) - tab.addrow(fs_tab, "Mount point", "Fs type", "Size", "Available") - for _, line in ipairs(lines) do - if ( ".clear" ~= line ) then - local mount, prefix, fstype, size, free, used, bs = table.unpack(stdnse.strsplit("%s", line)) - if ( size and free and mount and fstype ) then - size = ("%dM"):format(math.ceil(tonumber(size) * tonumber(bs) / 1048576)) - free = ("%dM"):format(math.ceil(tonumber(free) * tonumber(bs) / 1048576)) - tab.addrow(fs_tab, mount, fstype, size, free) - end - end - end - table.insert(result, tab.dump(fs_tab)) - elseif ( "net" == tag ) then - local net_tab = tab.new(3) - tab.addrow(net_tab, "Interface", "Received", "Transmitted") - for _, line in ipairs(lines) do - local name, rx, tx = line:match("^([^%s]*)%s([^%s]*)%s([^%s]*)$") - rx = ("%dM"):format(math.ceil(tonumber(rx) / 1048576)) - tx = ("%dM"):format(math.ceil(tonumber(tx) / 1048576)) - tab.addrow(net_tab, name, rx, tx) - end - table.insert(result, tab.dump(net_tab)) - elseif ( "hostname" == tag or "sysname" == tag or - "version" == tag ) then - return ("%s: %s"):format(long_names[tag], lines[1]) - elseif ( "uptime" == tag ) then - return ("%s: %s"):format(long_names[tag], minutesToUptime(lines[1])) - elseif ( "mem" == tag ) then - local total, used = table.unpack(stdnse.strsplit("%s", lines[1])) - if ( not(total) or not(used) ) then - return - end - local free = math.ceil((total - used)/1048576) - total = math.ceil(tonumber(total)/1048576) - return ("%s: Total %dM, Free %dM"):format(long_names[tag], total, free) - elseif ( "proc" == tag ) then - local procs, _, forks, load, users = table.unpack(stdnse.strsplit("%s", lines[1])) - if ( not(procs) or not(forks) or not(load) or not(users) ) then - return - end - return ("%s: Processes %d, Load %.2f, Users %d"):format(long_names[tag], procs, load, users) - end - return ( #result > 0 and result or nil ) + if ( "fs_mounts" == tag ) then + local fs_tab = tab.new(4) + tab.addrow(fs_tab, "Mount point", "Fs type", "Size", "Available") + for _, line in ipairs(lines) do + if ( ".clear" ~= line ) then + local mount, prefix, fstype, size, free, used, bs = table.unpack(stdnse.strsplit("%s", line)) + if ( size and free and mount and fstype ) then + size = ("%dM"):format(math.ceil(tonumber(size) * tonumber(bs) / 1048576)) + free = ("%dM"):format(math.ceil(tonumber(free) * tonumber(bs) / 1048576)) + tab.addrow(fs_tab, mount, fstype, size, free) + end + end + end + table.insert(result, tab.dump(fs_tab)) + elseif ( "net" == tag ) then + local net_tab = tab.new(3) + tab.addrow(net_tab, "Interface", "Received", "Transmitted") + for _, line in ipairs(lines) do + local name, rx, tx = line:match("^([^%s]*)%s([^%s]*)%s([^%s]*)$") + rx = ("%dM"):format(math.ceil(tonumber(rx) / 1048576)) + tx = ("%dM"):format(math.ceil(tonumber(tx) / 1048576)) + tab.addrow(net_tab, name, rx, tx) + end + table.insert(result, tab.dump(net_tab)) + elseif ( "hostname" == tag or "sysname" == tag or + "version" == tag ) then + return ("%s: %s"):format(long_names[tag], lines[1]) + elseif ( "uptime" == tag ) then + return ("%s: %s"):format(long_names[tag], minutesToUptime(lines[1])) + elseif ( "mem" == tag ) then + local total, used = table.unpack(stdnse.strsplit("%s", lines[1])) + if ( not(total) or not(used) ) then + return + end + local free = math.ceil((total - used)/1048576) + total = math.ceil(tonumber(total)/1048576) + return ("%s: Total %dM, Free %dM"):format(long_names[tag], total, free) + elseif ( "proc" == tag ) then + local procs, _, forks, load, users = table.unpack(stdnse.strsplit("%s", lines[1])) + if ( not(procs) or not(forks) or not(load) or not(users) ) then + return + end + return ("%s: Processes %d, Load %.2f, Users %d"):format(long_names[tag], procs, load, users) + end + return ( #result > 0 and result or nil ) end action = function(host, port) - local socket = nmap.new_socket() - socket:set_timeout(5000) + local socket = nmap.new_socket() + socket:set_timeout(5000) - if ( not(socket:connect(host, port)) ) then - return fail("Failed to connect to the server") - end + if ( not(socket:connect(host, port)) ) then + return fail("Failed to connect to the server") + end - -- If there's an error we get a response back, and only then - local status, data = socket:receive_buf("\n", false) - if( status and data ~= "" ) then - return fail("An unknown error occured, aborting ...") - elseif ( status ) then - status, data = socket:receive_buf("\n", false) - if ( status ) then - return fail(data) - else - return fail("Failed to receive error message from server") - end - end + -- If there's an error we get a response back, and only then + local status, data = socket:receive_buf("\n", false) + if( status and data ~= "" ) then + return fail("An unknown error occured, aborting ...") + elseif ( status ) then + status, data = socket:receive_buf("\n", false) + if ( status ) then + return fail(data) + else + return fail("Failed to receive error message from server") + end + end - if ( not(socket:send("gkrellm 2.3.4\n")) ) then - return fail("Failed to send data to the server") - end + if ( not(socket:send("gkrellm 2.3.4\n")) ) then + return fail("Failed to send data to the server") + end - local tags = {} - local status, tag = socket:receive_buf("\n", false) - while(true) do - if ( not(status) ) then - break - end - if ( not(tag:match("^<.*>$")) ) then - stdnse.print_debug(2, "Expected tag, got: %s", tag) - break - else - tag = tag:match("^<(.*)>$") - end + local tags = {} + local status, tag = socket:receive_buf("\n", false) + while(true) do + if ( not(status) ) then + break + end + if ( not(tag:match("^<.*>$")) ) then + stdnse.print_debug(2, "Expected tag, got: %s", tag) + break + else + tag = tag:match("^<(.*)>$") + end - if ( tags[tag] ) then - break - end + if ( tags[tag] ) then + break + end - while(true) do - local data - status, data = socket:receive_buf("\n", false) - if ( not(status) ) then - break - end - if ( status and data:match("^<.*>$") ) then - tag = data - break - end - tags[tag] = tags[tag] or {} - table.insert(tags[tag], data) - end - end - socket:close() + while(true) do + local data + status, data = socket:receive_buf("\n", false) + if ( not(status) ) then + break + end + if ( status and data:match("^<.*>$") ) then + tag = data + break + end + tags[tag] = tags[tag] or {} + table.insert(tags[tag], data) + end + end + socket:close() - local output = {} - for tag in pairs(tags) do - local result, order = decodeTag(tag, tags[tag]) - if ( result ) then - table.insert(output, result) - end - end + local output = {} + for tag in pairs(tags) do + local result, order = decodeTag(tag, tags[tag]) + if ( result ) then + table.insert(output, result) + end + end - table.sort(output, function(a,b) return getOrderPos(a) < getOrderPos(b) end) - return stdnse.format_output(true, output) + table.sort(output, function(a,b) return getOrderPos(a) < getOrderPos(b) end) + return stdnse.format_output(true, output) end diff --git a/scripts/http-form-brute.nse b/scripts/http-form-brute.nse index af8f855dc..fd0e245e7 100644 --- a/scripts/http-form-brute.nse +++ b/scripts/http-form-brute.nse @@ -27,16 +27,16 @@ Performs brute force password auditing against http form-based authentication. -- analyzes the response and attempt to determine whether authentication was -- successful or not. The script analyzes this by checking the response using -- the following rules: --- 1. If the response was empty the authentication was successful --- 2. If the response contains the message passed in the onsuccess --- argument the authentication was successful --- 3. If no onsuccess argument was passed, and if the response --- does not contain the message passed in the onfailure argument the --- authentication was successful --- 4. If neither the onsuccess or onfailure argument was passed and the --- response does not contain a password form field authentication --- was successful --- 5. Authentication failed +-- 1. If the response was empty the authentication was successful +-- 2. If the response contains the message passed in the onsuccess +-- argument the authentication was successful +-- 3. If no onsuccess argument was passed, and if the response +-- does not contain the message passed in the onfailure argument the +-- authentication was successful +-- 4. If neither the onsuccess or onfailure argument was passed and the +-- response does not contain a password form field authentication +-- was successful +-- 5. Authentication failed -- -- @output -- PORT STATE SERVICE REASON @@ -59,19 +59,19 @@ Performs brute force password auditing against http form-based authentication. -- holds the username used to authenticate. A simple autodetection of -- this variable is attempted. -- @args http-form-brute.passvar sets the http-variable name that holds the --- password used to authenticate. A simple autodetection of this variable +-- password used to authenticate. A simple autodetection of this variable -- is attempted. -- @args http-form-brute.onsuccess (optional) sets the message to expect on --- successful authentication +-- successful authentication -- @args http-form-brute.onfailure (optional) sets the message to expect on --- unsuccessful authentication +-- unsuccessful authentication -- -- Version 0.3 -- Created 07/30/2010 - v0.1 - created by Patrik Karlsson -- Revised 05/23/2011 - v0.2 - changed so that uservar is optional -- Revised 06/05/2011 - v0.3 - major re-write, added onsucces, onfailure and --- support for redirects +-- support for redirects -- author = "Patrik Karlsson" @@ -85,166 +85,166 @@ local form_params = {} Driver = { - new = function(self, host, port, options) - local o = {} - setmetatable(o, self) - self.__index = self - o.host = nmap.registry.args['http-form-brute.hostname'] or host - o.port = port - o.options = options - return o - end, + new = function(self, host, port, options) + local o = {} + setmetatable(o, self) + self.__index = self + o.host = nmap.registry.args['http-form-brute.hostname'] or host + o.port = port + o.options = options + return o + end, - connect = function( self ) - -- This will cause problems, as ther is no way for us to "reserve" - -- a socket. We may end up here early with a set of credentials - -- which won't be guessed until the end, due to socket exhaustion. - return true - end, + connect = function( self ) + -- This will cause problems, as ther is no way for us to "reserve" + -- a socket. We may end up here early with a set of credentials + -- which won't be guessed until the end, due to socket exhaustion. + return true + end, - login = function( self, username, password ) - -- we need to supply the no_cache directive, or else the http library - -- incorrectly tells us that the authentication was successfull - local postparams = { [self.options.passvar] = password } - if ( self.options.uservar ) then postparams[self.options.uservar] = username end + login = function( self, username, password ) + -- we need to supply the no_cache directive, or else the http library + -- incorrectly tells us that the authentication was successfull + local postparams = { [self.options.passvar] = password } + if ( self.options.uservar ) then postparams[self.options.uservar] = username end - local response = Driver.postRequest(self.host, self.port, self.options.path, postparams) - local success = false + local response = Driver.postRequest(self.host, self.port, self.options.path, postparams) + local success = false - -- if we have no response, we were successful - if ( not(response.body) ) then - success = true - -- if we have a response and it matches our onsuccess match, login was successful - elseif ( response.body and - self.options.onsuccess and - response.body:match(self.options.onsuccess) ) then - success = true - -- if we have a response and it does not match our onfailure, login was successful - elseif ( response.body and - not(self.options.onsuccess) and - self.options.onfailure and - not(response.body:match(self.options.onfailure))) then - success = true - -- if we have a response and no onfailure or onsuccess match defined - -- and can't find a password field, login was successful - elseif ( response.body and - not(self.options.onfailure) and - not(self.options.onsuccess) and - not(response.body:match("input.-type=[\"]*[Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd][\"]*")) - ) then - success = true - end + -- if we have no response, we were successful + if ( not(response.body) ) then + success = true + -- if we have a response and it matches our onsuccess match, login was successful + elseif ( response.body and + self.options.onsuccess and + response.body:match(self.options.onsuccess) ) then + success = true + -- if we have a response and it does not match our onfailure, login was successful + elseif ( response.body and + not(self.options.onsuccess) and + self.options.onfailure and + not(response.body:match(self.options.onfailure))) then + success = true + -- if we have a response and no onfailure or onsuccess match defined + -- and can't find a password field, login was successful + elseif ( response.body and + not(self.options.onfailure) and + not(self.options.onsuccess) and + not(response.body:match("input.-type=[\"]*[Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd][\"]*")) + ) then + success = true + end - -- We check whether the body was empty or that we have a body without our user- and pass-var - if ( success ) then - nmap.registry['credentials'] = nmap.registry['credentials'] or {} - nmap.registry.credentials['http'] = nmap.registry.credentials['http'] or {} - table.insert( nmap.registry.credentials.http, { username = username, password = password } ) - return true, brute.Account:new( username, password, creds.State.VALID) - end + -- We check whether the body was empty or that we have a body without our user- and pass-var + if ( success ) then + nmap.registry['credentials'] = nmap.registry['credentials'] or {} + nmap.registry.credentials['http'] = nmap.registry.credentials['http'] or {} + table.insert( nmap.registry.credentials.http, { username = username, password = password } ) + return true, brute.Account:new( username, password, creds.State.VALID) + end - return false, brute.Error:new( "Incorrect password" ) - end, + return false, brute.Error:new( "Incorrect password" ) + end, - disconnect = function( self ) - return true - end, + disconnect = function( self ) + return true + end, - check = function( self ) - return true - end, + check = function( self ) + return true + end, - postRequest = function( host, port, path, options ) - local response = http.post( host, port, path, { no_cache = true }, nil, options ) - local status = ( response and tonumber(response.status) ) or 0 - if ( status > 300 and status < 400 ) then - local new_path = url.absolute(path, response.header.location) - response = http.get( host, port, new_path, { no_cache = true } ) - end - return response - end, + postRequest = function( host, port, path, options ) + local response = http.post( host, port, path, { no_cache = true }, nil, options ) + local status = ( response and tonumber(response.status) ) or 0 + if ( status > 300 and status < 400 ) then + local new_path = url.absolute(path, response.header.location) + response = http.get( host, port, new_path, { no_cache = true } ) + end + return response + end, } --- Attempts to auto-detect known form-fields -- local function detectFormFields( host, port, path ) - local response = http.get( host, port, path ) - local user_field, pass_field + local response = http.get( host, port, path ) + local user_field, pass_field - if ( response.status == 200 ) then - user_field = response.body:match("<[Ii][Nn][Pp][Uu][Tt].-name=[\"]*([^\"]-[Uu][Ss][Ee][Rr].-)[\"]*.->") - pass_field = response.body:match("<[Ii][Nn][Pp][Uu][Tt].-name=[\"]*([Pp][Aa][Ss][Ss].-)[\"]*.->") + if ( response.status == 200 ) then + user_field = response.body:match("<[Ii][Nn][Pp][Uu][Tt].-name=[\"]*([^\"]-[Uu][Ss][Ee][Rr].-)[\"]*.->") + pass_field = response.body:match("<[Ii][Nn][Pp][Uu][Tt].-name=[\"]*([Pp][Aa][Ss][Ss].-)[\"]*.->") - if ( not(pass_field) ) then - pass_field = response.body:match("<[Ii][Nn][Pp][Uu][Tt].-name=[\"]-([^\"]-[Kk][Ee][Yy].-)[\"].->") - end - end + if ( not(pass_field) ) then + pass_field = response.body:match("<[Ii][Nn][Pp][Uu][Tt].-name=[\"]-([^\"]-[Kk][Ee][Yy].-)[\"].->") + end + end - return user_field, pass_field + return user_field, pass_field end action = function( host, port ) - local uservar = stdnse.get_script_args('http-form-brute.uservar') - local passvar = stdnse.get_script_args('http-form-brute.passvar') - local path = stdnse.get_script_args('http-form-brute.path') or "/" - local onsuccess = stdnse.get_script_args("http-form-brute.onsuccess") - local onfailure = stdnse.get_script_args("http-form-brute.onfailure") + local uservar = stdnse.get_script_args('http-form-brute.uservar') + local passvar = stdnse.get_script_args('http-form-brute.passvar') + local path = stdnse.get_script_args('http-form-brute.path') or "/" + local onsuccess = stdnse.get_script_args("http-form-brute.onsuccess") + local onfailure = stdnse.get_script_args("http-form-brute.onfailure") - local _ + local _ - -- if now fields were given attempt to autodetect - if ( not(uservar) and not(passvar) ) then - uservar, passvar = detectFormFields( host, port, path ) - -- if now passvar was detected attempt to autodetect - elseif ( not(passvar) ) then - _, passvar = detectFormFields( host, port, path ) - end + -- if now fields were given attempt to autodetect + if ( not(uservar) and not(passvar) ) then + uservar, passvar = detectFormFields( host, port, path ) + -- if now passvar was detected attempt to autodetect + elseif ( not(passvar) ) then + _, passvar = detectFormFields( host, port, path ) + end - -- uservar is optional, so only make sure we have a passvar - if ( not( passvar ) ) then - return "\n ERROR: No passvar was specified (see http-form-brute.passvar)" - end + -- uservar is optional, so only make sure we have a passvar + if ( not( passvar ) ) then + return "\n ERROR: No passvar was specified (see http-form-brute.passvar)" + end - if ( not(path) ) then - return "\n ERROR: No path was specified (see http-form-brute.path)" - end + if ( not(path) ) then + return "\n ERROR: No path was specified (see http-form-brute.path)" + end - if ( onsuccess and onfailure ) then - return "\n ERROR: Either the onsuccess or onfailure argument should be passed, not both." - end + if ( onsuccess and onfailure ) then + return "\n ERROR: Either the onsuccess or onfailure argument should be passed, not both." + end - local options = { [passvar] = "this_is_not_a_valid_password" } - if ( uservar ) then options[uservar] = "this_is_not_a_valid_user" end + local options = { [passvar] = "this_is_not_a_valid_password" } + if ( uservar ) then options[uservar] = "this_is_not_a_valid_user" end - local response = Driver.postRequest( host, port, path, options ) - if ( not(response) or not(response.body) or response.status ~= 200 ) then - return ("\n ERROR: Failed to retrieve path (%s) from server"):format(path) - end + local response = Driver.postRequest( host, port, path, options ) + if ( not(response) or not(response.body) or response.status ~= 200 ) then + return ("\n ERROR: Failed to retrieve path (%s) from server"):format(path) + end - -- try to detect onfailure match - if ( onfailure and not(response.body:match(onfailure)) ) then - return ("\n ERROR: Failed to match password failure message (%s)"):format(onfailure) - elseif ( not(onfailure) and - not(onsuccess) and - not(response.body:match("input.-type=[\"]*[Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd][\"]*")) ) then - return ("\n ERROR: Failed to detect password form field see (http-form-brute.onsuccess or http-form-brute.onfailure)") - end + -- try to detect onfailure match + if ( onfailure and not(response.body:match(onfailure)) ) then + return ("\n ERROR: Failed to match password failure message (%s)"):format(onfailure) + elseif ( not(onfailure) and + not(onsuccess) and + not(response.body:match("input.-type=[\"]*[Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd][\"]*")) ) then + return ("\n ERROR: Failed to detect password form field see (http-form-brute.onsuccess or http-form-brute.onfailure)") + end - local engine = brute.Engine:new( Driver, host, port, { - uservar = uservar, passvar = passvar, - path = path, onsuccess = onsuccess, onfailure = onfailure - } - ) - -- there's a bug in http.lua that does not allow it to be called by - -- multiple threads - engine:setMaxThreads(1) - engine.options.script_name = SCRIPT_NAME + local engine = brute.Engine:new( Driver, host, port, { + uservar = uservar, passvar = passvar, + path = path, onsuccess = onsuccess, onfailure = onfailure + } + ) + -- there's a bug in http.lua that does not allow it to be called by + -- multiple threads + engine:setMaxThreads(1) + engine.options.script_name = SCRIPT_NAME - if ( not(uservar) ) then - engine.options:setOption( "passonly", true ) - end - local status, result = engine:start() + if ( not(uservar) ) then + engine.options:setOption( "passonly", true ) + end + local status, result = engine:start() - return result + return result end diff --git a/scripts/http-iis-webdav-vuln.nse b/scripts/http-iis-webdav-vuln.nse index 696cda4d1..2cca54d55 100644 --- a/scripts/http-iis-webdav-vuln.nse +++ b/scripts/http-iis-webdav-vuln.nse @@ -43,170 +43,170 @@ portrule = shortport.http ---Enumeration for results local enum_results = { - VULNERABLE = 1, - NOT_VULNERABLE = 2, - UNKNOWN = 3 + VULNERABLE = 1, + NOT_VULNERABLE = 2, + UNKNOWN = 3 } ---Sends a PROPFIND request to the given host, and for the given folder. Returns a table reprenting a response. local function get_response(host, port, folder) - local webdav_req = '' + local webdav_req = '' - local options = { - header = { - Host = host.ip, - Connection = "close", - ["User-Agent"] = "Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html)", - ["Content-Type"] = "application/xml", - }, - content = webdav_req - } + local options = { + header = { + Host = host.ip, + Connection = "close", + ["User-Agent"] = "Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html)", + ["Content-Type"] = "application/xml", + }, + content = webdav_req + } - return http.generic_request(host, port, "PROPFIND", folder, options) + return http.generic_request(host, port, "PROPFIND", folder, options) end ---Check a single folder on a single host for the vulnerability. Returns one of the enum_results codes. local function go_single(host, port, folder) - local response + local response - response = get_response(host, port, folder) - if(response.status == 401) then - local vuln_response - local check_folder + response = get_response(host, port, folder) + if(response.status == 401) then + local vuln_response + local check_folder - stdnse.print_debug(1, "http-iis-webdav-vuln: Found protected folder (401): %s", folder) + stdnse.print_debug(1, "http-iis-webdav-vuln: Found protected folder (401): %s", folder) - -- check for IIS 6.0 and 5.1 - -- doesn't appear to work on 5.0 - -- /secret/ becomes /s%c0%afecret/ - check_folder = string.sub(folder, 1, 2) .. "%c0%af" .. string.sub(folder, 3) - vuln_response = get_response(host, port, check_folder) - if(vuln_response.status == 207) then - stdnse.print_debug(1, "http-iis-webdav-vuln: Folder seems vulnerable: %s", folder) - return enum_results.VULNERABLE - else - stdnse.print_debug(1, "http-iis-webdav-vuln: Folder does not seem vulnerable: %s", folder) - return enum_results.NOT_VULNERABLE - end - else - if(response['status-line'] ~= nil) then - stdnse.print_debug(3, "http-iis-webdav-vuln: Not a protected folder (%s): %s", response['status-line'], folder) - elseif(response['status'] ~= nil) then - stdnse.print_debug(3, "http-iis-webdav-vuln: Not a protected folder (%s): %s", response['status'], folder) - else - stdnse.print_debug(3, "http-iis-webdav-vuln: Not a protected folder: %s",folder) - end - return enum_results.UNKNOWN - end + -- check for IIS 6.0 and 5.1 + -- doesn't appear to work on 5.0 + -- /secret/ becomes /s%c0%afecret/ + check_folder = string.sub(folder, 1, 2) .. "%c0%af" .. string.sub(folder, 3) + vuln_response = get_response(host, port, check_folder) + if(vuln_response.status == 207) then + stdnse.print_debug(1, "http-iis-webdav-vuln: Folder seems vulnerable: %s", folder) + return enum_results.VULNERABLE + else + stdnse.print_debug(1, "http-iis-webdav-vuln: Folder does not seem vulnerable: %s", folder) + return enum_results.NOT_VULNERABLE + end + else + if(response['status-line'] ~= nil) then + stdnse.print_debug(3, "http-iis-webdav-vuln: Not a protected folder (%s): %s", response['status-line'], folder) + elseif(response['status'] ~= nil) then + stdnse.print_debug(3, "http-iis-webdav-vuln: Not a protected folder (%s): %s", response['status'], folder) + else + stdnse.print_debug(3, "http-iis-webdav-vuln: Not a protected folder: %s",folder) + end + return enum_results.UNKNOWN + end end ---Checks a list of possible folders for the vulnerability. Returns a list of vulnerable folders. local function go(host, port) - local status, folder - local results = {} - local is_vulnerable = true + local status, folder + local results = {} + local is_vulnerable = true - local folder_file + local folder_file local farg = nmap.registry.args.folderdb folder_file = farg and (nmap.fetchfile(farg) or farg) or nmap.fetchfile('nselib/data/http-folders.txt') - if(folder_file == nil) then - return false, "Couldn't find http-folders.txt (should be in nselib/data)" - end + if(folder_file == nil) then + return false, "Couldn't find http-folders.txt (should be in nselib/data)" + end - local file = io.open(folder_file, "r") - if not file then - return false, ("Couldn't find or open %s"):format(folder_file) - end + local file = io.open(folder_file, "r") + if not file then + return false, ("Couldn't find or open %s"):format(folder_file) + end - while true do - local result - local line = file:read() - if not line then - break - end + while true do + local result + local line = file:read() + if not line then + break + end - if(nmap.registry.args.basefolder ~= nil) then - line = "/" .. nmap.registry.args.basefolder .. "/" .. line - else - line = "/" .. line - end + if(nmap.registry.args.basefolder ~= nil) then + line = "/" .. nmap.registry.args.basefolder .. "/" .. line + else + line = "/" .. line + end - result = go_single(host, port, line) - if(result == enum_results.VULNERABLE) then - results[#results + 1] = line - elseif(result == enum_results.NOT_VULNERABLE) then - is_vulnerable = false - else - end - end + result = go_single(host, port, line) + if(result == enum_results.VULNERABLE) then + results[#results + 1] = line + elseif(result == enum_results.NOT_VULNERABLE) then + is_vulnerable = false + else + end + end - file:close() + file:close() - return true, results, is_vulnerable + return true, results, is_vulnerable end action = function(host, port) - -- Start by checking if '/' is protected -- if it is, we can't do the tests - local result = go_single(host, port, "/") - if(result == enum_results.NOT_VULNERABLE) then - stdnse.print_debug(1, "http-iis-webdav-vuln: Root folder is password protected, aborting.") - return nmap.verbosity() > 0 and "Could not determine vulnerability, since root folder is password protected" or nil - end + -- Start by checking if '/' is protected -- if it is, we can't do the tests + local result = go_single(host, port, "/") + if(result == enum_results.NOT_VULNERABLE) then + stdnse.print_debug(1, "http-iis-webdav-vuln: Root folder is password protected, aborting.") + return nmap.verbosity() > 0 and "Could not determine vulnerability, since root folder is password protected" or nil + end - stdnse.print_debug(1, "http-iis-webdav-vuln: Root folder is not password protected, continuing...") + stdnse.print_debug(1, "http-iis-webdav-vuln: Root folder is not password protected, continuing...") - local response = get_response(host, port, "/") - if(response.status == 501) then - -- WebDAV is disabled - stdnse.print_debug(1, "http-iis-webdav-vuln: WebDAV is DISABLED (PROPFIND failed).") - return nmap.verbosity() > 0 and "WebDAV is DISABLED. Server is not currently vulnerable." or nil - else - if(response.status == 207) then - -- PROPFIND works, WebDAV is enabled - stdnse.print_debug(1, "http-iis-webdav-vuln: WebDAV is ENABLED (PROPFIND was successful).") - else - -- probably not running IIS 5.0/5.1/6.0 - if(response['status-line'] ~= nil) then - stdnse.print_debug(1, "http-iis-webdav-vuln: PROPFIND request failed with \"%s\".", response['status-line']) - elseif(response['status'] ~= nil) then - stdnse.print_debug(1, "http-iis-webdav-vuln: PROPFIND request failed with \"%s\".", response['status']) - else - stdnse.print_debug(1, "http-iis-webdav-vuln: PROPFIND request failed.") - end - return nmap.verbosity() > 0 and "ERROR: This web server is not supported." or nil - end - end + local response = get_response(host, port, "/") + if(response.status == 501) then + -- WebDAV is disabled + stdnse.print_debug(1, "http-iis-webdav-vuln: WebDAV is DISABLED (PROPFIND failed).") + return nmap.verbosity() > 0 and "WebDAV is DISABLED. Server is not currently vulnerable." or nil + else + if(response.status == 207) then + -- PROPFIND works, WebDAV is enabled + stdnse.print_debug(1, "http-iis-webdav-vuln: WebDAV is ENABLED (PROPFIND was successful).") + else + -- probably not running IIS 5.0/5.1/6.0 + if(response['status-line'] ~= nil) then + stdnse.print_debug(1, "http-iis-webdav-vuln: PROPFIND request failed with \"%s\".", response['status-line']) + elseif(response['status'] ~= nil) then + stdnse.print_debug(1, "http-iis-webdav-vuln: PROPFIND request failed with \"%s\".", response['status']) + else + stdnse.print_debug(1, "http-iis-webdav-vuln: PROPFIND request failed.") + end + return nmap.verbosity() > 0 and "ERROR: This web server is not supported." or nil + end + end - if(nmap.registry.args.webdavfolder ~= nil) then - local folder = nmap.registry.args.webdavfolder - local result = go_single(host, port, "/" .. folder) + if(nmap.registry.args.webdavfolder ~= nil) then + local folder = nmap.registry.args.webdavfolder + local result = go_single(host, port, "/" .. folder) - if(result == enum_results.VULNERABLE) then - return string.format("WebDAV is ENABLED. Folder is vulnerable: %s", folder) - elseif(result == enum_results.NOT_VULNERABLE) then - return nmap.verbosity() > 0 and string.format("WebDAV is ENABLED. Folder is NOT vulnerable: %s", folder) or nil - else - return nmap.verbosity() > 0 and string.format("WebDAV is ENABLED. Could not determine vulnerability of folder: %s", folder) or nil - end + if(result == enum_results.VULNERABLE) then + return string.format("WebDAV is ENABLED. Folder is vulnerable: %s", folder) + elseif(result == enum_results.NOT_VULNERABLE) then + return nmap.verbosity() > 0 and string.format("WebDAV is ENABLED. Folder is NOT vulnerable: %s", folder) or nil + else + return nmap.verbosity() > 0 and string.format("WebDAV is ENABLED. Could not determine vulnerability of folder: %s", folder) or nil + end - else - local status, results, is_vulnerable = go(host, port) + else + local status, results, is_vulnerable = go(host, port) - if(status == false) then - return nmap.verbosity() > 0 and "ERROR: " .. results or nil - else - if(#results == 0) then - if(is_vulnerable == false) then - return nmap.verbosity() > 0 and "WebDAV is ENABLED. Protected folder found but could not be exploited. Server does not appear to be vulnerable." or nil - else - return nmap.verbosity() > 0 and "WebDAV is ENABLED. No protected folder found; check not run. If you know a protected folder, add --script-args=webdavfolder=" or nil - end - else - return "WebDAV is ENABLED. Vulnerable folders discovered: " .. stdnse.strjoin(", ", results) - end - end - end + if(status == false) then + return nmap.verbosity() > 0 and "ERROR: " .. results or nil + else + if(#results == 0) then + if(is_vulnerable == false) then + return nmap.verbosity() > 0 and "WebDAV is ENABLED. Protected folder found but could not be exploited. Server does not appear to be vulnerable." or nil + else + return nmap.verbosity() > 0 and "WebDAV is ENABLED. No protected folder found; check not run. If you know a protected folder, add --script-args=webdavfolder=" or nil + end + else + return "WebDAV is ENABLED. Vulnerable folders discovered: " .. stdnse.strjoin(", ", results) + end + end + end end diff --git a/scripts/http-passwd.nse b/scripts/http-passwd.nse index fa9c75fae..e9dbd5b32 100644 --- a/scripts/http-passwd.nse +++ b/scripts/http-passwd.nse @@ -72,19 +72,19 @@ categories = {"intrusive", "vuln"} --@param response The HTTP response from the server. --@return The body of the HTTP response. local validate = function(response) - if not response.status then - return nil - end + if not response.status then + return nil + end - if response.status ~= 200 then - return nil - end + if response.status ~= 200 then + return nil + end - if response.body:match("^[^:]+:[^:]*:[0-9]+:[0-9]+:") or response.body:match("%[boot loader%]") then - return response.body - end + if response.body:match("^[^:]+:[^:]*:[0-9]+:[0-9]+:") or response.body:match("%[boot loader%]") then + return response.body + end - return nil + return nil end --- Transforms a string with ".", "/" and "\" converted to their URL-formatted @@ -92,19 +92,19 @@ end --@param str String to hexify. --@return Transformed string. local hexify = function(str) - local ret - ret = str:gsub("%.", "%%2E") - ret = ret:gsub("/", "%%2F") - ret = ret:gsub("\\", "%%5C") - return ret + local ret + ret = str:gsub("%.", "%%2E") + ret = ret:gsub("/", "%%2F") + ret = ret:gsub("\\", "%%5C") + return ret end --- Truncates the passwd or boot.ini file. --@param passwd passwd or boot.inifile. --@return Truncated passwd file and truncated length. local truncatePasswd = function(passwd) - local len = 250 - return passwd:sub(1, len), len + local len = 250 + return passwd:sub(1, len), len end --- Formats output. @@ -112,83 +112,83 @@ end --@param dir Formatted request which elicited the good reponse. --@return String description for output local output = function(passwd, dir) - local trunc, len = truncatePasswd(passwd) - local out = "" - out = out .. "Directory traversal found.\nPayload: \"" .. dir .. "\"\n" - out = out .. "Printing first " .. len .. " bytes:\n" - out = out .. trunc - return out + local trunc, len = truncatePasswd(passwd) + local out = "" + out = out .. "Directory traversal found.\nPayload: \"" .. dir .. "\"\n" + out = out .. "Printing first " .. len .. " bytes:\n" + out = out .. trunc + return out end portrule = shortport.http action = function(host, port) - local dirs = { - hexify("//etc/passwd"), - hexify(string.rep("../", 10) .. "etc/passwd"), - hexify(string.rep("../", 10) .. "boot.ini"), - hexify(string.rep("..\\", 10) .. "boot.ini"), - hexify("." .. string.rep("../", 10) .. "etc/passwd"), - hexify(string.rep("..\\/", 10) .. "etc\\/passwd"), - hexify(string.rep("..\\", 10) .. "etc\\passwd"), + local dirs = { + hexify("//etc/passwd"), + hexify(string.rep("../", 10) .. "etc/passwd"), + hexify(string.rep("../", 10) .. "boot.ini"), + hexify(string.rep("..\\", 10) .. "boot.ini"), + hexify("." .. string.rep("../", 10) .. "etc/passwd"), + hexify(string.rep("..\\/", 10) .. "etc\\/passwd"), + hexify(string.rep("..\\", 10) .. "etc\\passwd"), - -- These don't get hexified because they are targeted at - -- specific known vulnerabilities. - '..\\\\..\\\\..\\..\\\\..\\..\\\\..\\..\\\\\\boot.ini', - --miniwebsvr - '%c0.%c0./%c0.%c0./%c0.%c0./%c0.%c0./%c0.%c0./boot.ini', - '%c0%2e%c0%2e/%c0%2e%c0%2e/%c0%2e%c0%2e/%c0%2e%c0%2e/boot.ini', - --Acritum Femitter Server - '\\\\..%2f..%2f..%2f..%2fboot.ini% ../', - --zervit Web Server and several others - 'index.html?../../../../../boot.ini', - 'index.html?..\\..\\..\\..\\..\\boot.ini', - --Mongoose Web Server - '///..%2f..%2f..%2f..%2fboot.ini', - '/..%5C..%5C%5C..%5C..%5C%5C..%5C..%5C%5C..%5C..%5Cboot.ini', - '/%c0%2e%c0%2e\\%c0%2e%c0%2e\\%c0%2e%c0%2e\\boot.ini', - -- Yaws 1.89 - '/..\\/..\\/..\\/boot.ini', - '/..\\/\\..\\/\\..\\/\\boot.ini', - '/\\../\\../\\../boot.ini', - '////..\\..\\..\\boot.ini', - --MultiThreaded HTTP Server v1.1 - '/..\\..\\..\\..\\\\..\\..\\\\..\\..\\\\\\boot.ini', - --uHttp Server - '/../../../../../../../etc/passwd', - --Java Mini Web Server - '/%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5cboot.ini', - '/%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5cetc%2fpasswd', - } + -- These don't get hexified because they are targeted at + -- specific known vulnerabilities. + '..\\\\..\\\\..\\..\\\\..\\..\\\\..\\..\\\\\\boot.ini', + --miniwebsvr + '%c0.%c0./%c0.%c0./%c0.%c0./%c0.%c0./%c0.%c0./boot.ini', + '%c0%2e%c0%2e/%c0%2e%c0%2e/%c0%2e%c0%2e/%c0%2e%c0%2e/boot.ini', + --Acritum Femitter Server + '\\\\..%2f..%2f..%2f..%2fboot.ini% ../', + --zervit Web Server and several others + 'index.html?../../../../../boot.ini', + 'index.html?..\\..\\..\\..\\..\\boot.ini', + --Mongoose Web Server + '///..%2f..%2f..%2f..%2fboot.ini', + '/..%5C..%5C%5C..%5C..%5C%5C..%5C..%5C%5C..%5C..%5Cboot.ini', + '/%c0%2e%c0%2e\\%c0%2e%c0%2e\\%c0%2e%c0%2e\\boot.ini', + -- Yaws 1.89 + '/..\\/..\\/..\\/boot.ini', + '/..\\/\\..\\/\\..\\/\\boot.ini', + '/\\../\\../\\../boot.ini', + '////..\\..\\..\\boot.ini', + --MultiThreaded HTTP Server v1.1 + '/..\\..\\..\\..\\\\..\\..\\\\..\\..\\\\\\boot.ini', + --uHttp Server + '/../../../../../../../etc/passwd', + --Java Mini Web Server + '/%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5cboot.ini', + '/%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5cetc%2fpasswd', + } - for _, dir in ipairs(dirs) do - local response = http.get(host, port, dir) + for _, dir in ipairs(dirs) do + local response = http.get(host, port, dir) - if validate(response) then - return output(response.body, dir) - end - end + if validate(response) then + return output(response.body, dir) + end + end - local root = stdnse.get_script_args("http-passwd.root") or "/" + local root = stdnse.get_script_args("http-passwd.root") or "/" - -- Check for something that looks like a query referring to a file name, like - -- "index.php?page=next.php". Replace the query value with each of the test - -- vectors. Add an encoded null byte at the end to bypass some checks; see - -- http://insecure.org/news/P55-01.txt. - local response = http.get(host, port, root) - if response.body then - local page_var = response.body:match ("[%?%&](%a-)=%a-%.%a") - if page_var then - local query_base = root .. "?" .. page_var .. "=" - stdnse.print_debug(1, "%s: testing with query %s.", SCRIPT_NAME, query_base .. "...") + -- Check for something that looks like a query referring to a file name, like + -- "index.php?page=next.php". Replace the query value with each of the test + -- vectors. Add an encoded null byte at the end to bypass some checks; see + -- http://insecure.org/news/P55-01.txt. + local response = http.get(host, port, root) + if response.body then + local page_var = response.body:match ("[%?%&](%a-)=%a-%.%a") + if page_var then + local query_base = root .. "?" .. page_var .. "=" + stdnse.print_debug(1, "%s: testing with query %s.", SCRIPT_NAME, query_base .. "...") - for _, dir in ipairs(dirs) do - local response = http.get(host, port, query_base .. dir .. "%00") + for _, dir in ipairs(dirs) do + local response = http.get(host, port, query_base .. dir .. "%00") - if validate(response) then - return output(response.body, dir) - end - end - end - end + if validate(response) then + return output(response.body, dir) + end + end + end + end end diff --git a/scripts/http-rfi-spider.nse b/scripts/http-rfi-spider.nse index 51789908b..a6c72460f 100644 --- a/scripts/http-rfi-spider.nse +++ b/scripts/http-rfi-spider.nse @@ -173,27 +173,27 @@ function action(host, port) check_response = function(body) return string.find(body, pattern_to_search) end -- create a new crawler instance - local crawler = httpspider.Crawler:new( host, port, nil, { scriptname = SCRIPT_NAME} ) + local crawler = httpspider.Crawler:new( host, port, nil, { scriptname = SCRIPT_NAME} ) - if ( not(crawler) ) then - return - end + if ( not(crawler) ) then + return + end - local return_table = {} + local return_table = {} - while(true) do - local status, r = crawler:crawl() + while(true) do + local status, r = crawler:crawl() - if ( not(status) ) then - if ( r.err ) then - return stdnse.format_output(true, ("ERROR: %s"):format(r.reason)) - else - break - end - end + if ( not(status) ) then + if ( r.err ) then + return stdnse.format_output(true, ("ERROR: %s"):format(r.reason)) + else + break + end + end - -- first we try rfi on forms - if r.response and r.response.body and r.response.status==200 then + -- first we try rfi on forms + if r.response and r.response.body and r.response.status==200 then local all_forms = http.grab_forms(r.response.body) for _,form_plain in ipairs(all_forms) do local form = http.parse_form(form_plain) @@ -206,7 +206,7 @@ function action(host, port) end end end --for - end --if + end --if -- now try inclusion by parameters local injectable = {} @@ -232,7 +232,7 @@ function action(host, port) end end end - end - return stdnse.format_output(true, return_table) + end + return stdnse.format_output(true, return_table) end diff --git a/scripts/http-sql-injection.nse b/scripts/http-sql-injection.nse index 58a707c80..27246c727 100644 --- a/scripts/http-sql-injection.nse +++ b/scripts/http-sql-injection.nse @@ -108,8 +108,8 @@ local function build_injection_vector(urls) urlstr = url.build(utab) table.insert(all, urlstr) - qtab[k] = old_qtab - utab.query = url.build_query(qtab) + qtab[k] = old_qtab + utab.query = url.build_query(qtab) end end end @@ -242,7 +242,7 @@ action = function(host, port) end -- first we try sqli on forms - if r.response and r.response.body and r.response.status==200 then + if r.response and r.response.body and r.response.status==200 then local all_forms = http.grab_forms(r.response.body) for _,form_plain in ipairs(all_forms) do local form = http.parse_form(form_plain) @@ -255,7 +255,7 @@ action = function(host, port) end end end --for - end --if + end --if local links = {} if r.response.status and r.response.body then links = httpspider.LinkExtractor:new(r.url, r.response.body, crawler.options):getLinks() diff --git a/scripts/http-stored-xss.nse b/scripts/http-stored-xss.nse index a793c7ace..091d8b70c 100644 --- a/scripts/http-stored-xss.nse +++ b/scripts/http-stored-xss.nse @@ -76,207 +76,207 @@ portrule = shortport.port_or_service( {80, 443}, {"http", "https"}, "tcp", "open -- Note, that more payloads will slow down your scan. payloads = { - -- Basic vectors. Each one is an indication of potential XSS vulnerability. - { vector = 'ghz>hzx', description = "Unfiltered '>' (greater than sign). An indication of potential XSS vulnerability." }, - { vector = 'hzx"zxc', description = "Unfiltered \" (double quotation mark). An indication of potential XSS vulnerability." }, - { vector = 'zxc\'xcv', description = "Unfiltered ' (apostrophe). An indication of potential XSS vulnerability." }, - } + -- Basic vectors. Each one is an indication of potential XSS vulnerability. + { vector = 'ghz>hzx', description = "Unfiltered '>' (greater than sign). An indication of potential XSS vulnerability." }, + { vector = 'hzx"zxc', description = "Unfiltered \" (double quotation mark). An indication of potential XSS vulnerability." }, + { vector = 'zxc\'xcv', description = "Unfiltered ' (apostrophe). An indication of potential XSS vulnerability." }, +} -- Create customized requests for all of our payloads. local makeRequests = function(host, port, submission, fields, fieldvalues) - local postdata = {} - for _, p in ipairs(payloads) do - for __, field in ipairs(fields) do - if field["type"] == "text" or field["type"] == "textarea" or field["type"] == "radio" or field["type"] == "checkbox" then + local postdata = {} + for _, p in ipairs(payloads) do + for __, field in ipairs(fields) do + if field["type"] == "text" or field["type"] == "textarea" or field["type"] == "radio" or field["type"] == "checkbox" then - local value = fieldvalues[field["name"]] - if value == nil then - value = p.vector - end - - postdata[field["name"]] = value - - end + local value = fieldvalues[field["name"]] + if value == nil then + value = p.vector end + postdata[field["name"]] = value + + end + end + stdnse.print_debug(2, "Making a POST request to " .. submission .. ": ") for i, content in pairs(postdata) do - stdnse.print_debug(2, i .. ": " .. content) + stdnse.print_debug(2, i .. ": " .. content) end local response = http.post(host, port, submission, { no_cache = true }, nil, postdata) - end + end end local checkPayload = function(body, p) - if (body:match(p)) then - return true - end + if (body:match(p)) then + return true + end end -- Check if the payloads were succesfull by checking the content of pages in the uploadspaths array. local checkRequests = function(body, target) - local output = {} - for _, p in ipairs(payloads) do - if checkPayload(body, p.vector) then - local report = " Payload: " .. p.vector .. "\n\t Uploaded on: " .. target - if p.description then - report = report .. "\n\t Description: " .. p.description - end - table.insert(output, report) - end + local output = {} + for _, p in ipairs(payloads) do + if checkPayload(body, p.vector) then + local report = " Payload: " .. p.vector .. "\n\t Uploaded on: " .. target + if p.description then + report = report .. "\n\t Description: " .. p.description + end + table.insert(output, report) end - return output + end + return output end local readFromFile = function(filename) - local database = { } - for l in io.lines(filename) do - table.insert(payloads, { vector = l }) - end + local database = { } + for l in io.lines(filename) do + table.insert(payloads, { vector = l }) + end end action = function(host, port) - local formpaths = stdnse.get_script_args("http-stored-xss.formpaths") - local uploadspaths = stdnse.get_script_args("http-stored-xss.uploadspaths") - local fieldvalues = stdnse.get_script_args("http-stored-xss.fieldvalues") or {} - local dbfile = stdnse.get_script_args("http-stored-xss.dbfile") + local formpaths = stdnse.get_script_args("http-stored-xss.formpaths") + local uploadspaths = stdnse.get_script_args("http-stored-xss.uploadspaths") + local fieldvalues = stdnse.get_script_args("http-stored-xss.fieldvalues") or {} + local dbfile = stdnse.get_script_args("http-stored-xss.dbfile") - if dbfile then - readFromFile(dbfile) - end + if dbfile then + readFromFile(dbfile) + end - local returntable = {} - local result + local returntable = {} + local result - local crawler = httpspider.Crawler:new( host, port, '/', { scriptname = SCRIPT_NAME, no_cache = true } ) + local crawler = httpspider.Crawler:new( host, port, '/', { scriptname = SCRIPT_NAME, no_cache = true } ) - if (not(crawler)) then - return - end + if (not(crawler)) then + return + end - crawler:set_timeout(10000) + crawler:set_timeout(10000) - local index, k, target, response + local index, k, target, response - -- Phase 1. Crawls through the website and POSTs malicious payloads. - while (true) do + -- Phase 1. Crawls through the website and POSTs malicious payloads. + while (true) do - if formpaths then + if formpaths then - k, target = next(formpaths, index) - if (k == nil) then - break - end - response = http.get(host, port, target, { no_cache = true }) - target = host.name .. target - else - - local status, r = crawler:crawl() - -- if the crawler fails it can be due to a number of different reasons - -- most of them are "legitimate" and should not be reason to abort - if ( not(status) ) then - if ( r.err ) then - return stdnse.format_output(true, ("ERROR: %s"):format(r.reason)) - else - break - end - end - - target = tostring(r.url) - response = r.response - - end - - if response.body then - - local forms = http.grab_forms(response.body) - - for i, form in ipairs(forms) do - - form = http.parse_form(form) - - if form then - - local action_absolute = string.find(form["action"], "https*://") - - -- Determine the path where the form needs to be submitted. - local submission - if action_absolute then - submission = form["action"] - else - local path_cropped = string.match(target, "(.*/).*") - path_cropped = path_cropped and path_cropped or "" - submission = path_cropped..form["action"] - end - - makeRequests(host, port, submission, form["fields"], fieldvalues) - - end - end - end - if (index) then - index = index + 1 - else - index = 1 - end - - end - - local crawler = httpspider.Crawler:new( host, port, '/', { scriptname = SCRIPT_NAME } ) - local index - - -- Phase 2. Crawls through the website and searches for the special crafted strings that were POSTed before. - while true do - if uploadspaths then - k, target = next(uploadspaths, index) - if (k == nil) then - break - end - response = http.get(host, port, target) - else - - local status, r = crawler:crawl() - -- if the crawler fails it can be due to a number of different reasons - -- most of them are "legitimate" and should not be reason to abort - if ( not(status) ) then - if ( r.err ) then - return stdnse.format_output(true, ("ERROR: %s"):format(r.reason)) - else - break - end - end - - target = tostring(r.url) - response = r.response - - end - - if response.body then - - result = checkRequests(response.body, target) - - if next(result) then - table.insert(returntable, result) - end - end - if (index) then - index = index + 1 - else - index = 1 - end - end - - if next(returntable) then - table.insert(returntable, 1, "Found the following stored XSS vulnerabilities: ") - return returntable + k, target = next(formpaths, index) + if (k == nil) then + break + end + response = http.get(host, port, target, { no_cache = true }) + target = host.name .. target else - return "Couldn't find any stored XSS vulnerabilities." + + local status, r = crawler:crawl() + -- if the crawler fails it can be due to a number of different reasons + -- most of them are "legitimate" and should not be reason to abort + if ( not(status) ) then + if ( r.err ) then + return stdnse.format_output(true, ("ERROR: %s"):format(r.reason)) + else + break + end + end + + target = tostring(r.url) + response = r.response + end + + if response.body then + + local forms = http.grab_forms(response.body) + + for i, form in ipairs(forms) do + + form = http.parse_form(form) + + if form then + + local action_absolute = string.find(form["action"], "https*://") + + -- Determine the path where the form needs to be submitted. + local submission + if action_absolute then + submission = form["action"] + else + local path_cropped = string.match(target, "(.*/).*") + path_cropped = path_cropped and path_cropped or "" + submission = path_cropped..form["action"] + end + + makeRequests(host, port, submission, form["fields"], fieldvalues) + + end + end + end + if (index) then + index = index + 1 + else + index = 1 + end + + end + + local crawler = httpspider.Crawler:new( host, port, '/', { scriptname = SCRIPT_NAME } ) + local index + + -- Phase 2. Crawls through the website and searches for the special crafted strings that were POSTed before. + while true do + if uploadspaths then + k, target = next(uploadspaths, index) + if (k == nil) then + break + end + response = http.get(host, port, target) + else + + local status, r = crawler:crawl() + -- if the crawler fails it can be due to a number of different reasons + -- most of them are "legitimate" and should not be reason to abort + if ( not(status) ) then + if ( r.err ) then + return stdnse.format_output(true, ("ERROR: %s"):format(r.reason)) + else + break + end + end + + target = tostring(r.url) + response = r.response + + end + + if response.body then + + result = checkRequests(response.body, target) + + if next(result) then + table.insert(returntable, result) + end + end + if (index) then + index = index + 1 + else + index = 1 + end + end + + if next(returntable) then + table.insert(returntable, 1, "Found the following stored XSS vulnerabilities: ") + return returntable + else + return "Couldn't find any stored XSS vulnerabilities." + end end diff --git a/scripts/http-virustotal.nse b/scripts/http-virustotal.nse index c386d5bd2..cb22912df 100644 --- a/scripts/http-virustotal.nse +++ b/scripts/http-virustotal.nse @@ -102,154 +102,154 @@ local arg_checksum = stdnse.get_script_args(SCRIPT_NAME .. ".checksum") prerule = function() return true end local function readFile(filename) - local f = io.open(filename, "r") - if ( not(f) ) then - return false, ("Failed to open file: %s"):format(filename) - end + local f = io.open(filename, "r") + if ( not(f) ) then + return false, ("Failed to open file: %s"):format(filename) + end - local str = f:read("*all") - if ( not(str) ) then - f:close() - return false, "Failed to read file contents" - end - f:close() - return true, str + local str = f:read("*all") + if ( not(str) ) then + f:close() + return false, "Failed to read file contents" + end + f:close() + return true, str end local function requestFileScan(filename) - local status, str = readFile(filename) - if ( not(status) ) then - return false, str - end + local status, str = readFile(filename) + if ( not(status) ) then + return false, str + end - local shortfile = filename:match("^.*[\\/](.*)$") - local boundary = "----------------------------nmapboundary" - local header = { ["Content-Type"] = ("multipart/form-data; boundary=%s"):format(boundary) } - local postdata = ("--%s\r\n"):format(boundary) - postdata = postdata .. "Content-Disposition: form-data; name=\"apikey\"\r\n\r\n" - postdata = postdata .. arg_apiKey .. "\r\n" - postdata = postdata .. ("--%s\r\n" .. - "Content-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\n" .. - "Content-Type: text/plain\r\n\r\n%s\r\n--%s--\r\n"):format(boundary, shortfile, str, boundary) + local shortfile = filename:match("^.*[\\/](.*)$") + local boundary = "----------------------------nmapboundary" + local header = { ["Content-Type"] = ("multipart/form-data; boundary=%s"):format(boundary) } + local postdata = ("--%s\r\n"):format(boundary) + postdata = postdata .. "Content-Disposition: form-data; name=\"apikey\"\r\n\r\n" + postdata = postdata .. arg_apiKey .. "\r\n" + postdata = postdata .. ("--%s\r\n" .. + "Content-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\n" .. + "Content-Type: text/plain\r\n\r\n%s\r\n--%s--\r\n"):format(boundary, shortfile, str, boundary) - local host = "www.virustotal.com" - local port = { number = 80, protocol = "tcp" } - local path = "/vtapi/v2/file/scan" + local host = "www.virustotal.com" + local port = { number = 80, protocol = "tcp" } + local path = "/vtapi/v2/file/scan" - local response = http.post( host, port, path, { header = header }, nil, postdata ) - if ( not(response) or response.status ~= 200 ) then - return false, "Failed to request file scan" - end + local response = http.post( host, port, path, { header = header }, nil, postdata ) + if ( not(response) or response.status ~= 200 ) then + return false, "Failed to request file scan" + end - local status, json_data = json.parse(response.body) - if ( not(status) ) then - return false, "Failed to parse JSON response" - end + local status, json_data = json.parse(response.body) + if ( not(status) ) then + return false, "Failed to parse JSON response" + end - return true, json_data + return true, json_data end local function getFileScanReport(resource) - local host = "www.virustotal.com" - local port = { number = 80, protocol = "tcp" } - local path = "/vtapi/v2/file/report" + local host = "www.virustotal.com" + local port = { number = 80, protocol = "tcp" } + local path = "/vtapi/v2/file/report" - local response = http.post(host, port, path, nil, nil, { ["apikey"] = arg_apiKey, ["resource"] = resource }) - if ( not(response) or response.status ~= 200 ) then - return false, "Failed to retrieve scan report" - end + local response = http.post(host, port, path, nil, nil, { ["apikey"] = arg_apiKey, ["resource"] = resource }) + if ( not(response) or response.status ~= 200 ) then + return false, "Failed to retrieve scan report" + end - local status, json_data = json.parse(response.body) - if ( not(status) ) then - return false, "Failed to parse JSON response" - end + local status, json_data = json.parse(response.body) + if ( not(status) ) then + return false, "Failed to parse JSON response" + end - return true, json_data + return true, json_data end local function calcSHA256(filename) - local status, str = readFile(filename) - if ( not(status) ) then - return false, str - end - return true, stdnse.tohex(openssl.digest("sha256", str)) + local status, str = readFile(filename) + if ( not(status) ) then + return false, str + end + return true, stdnse.tohex(openssl.digest("sha256", str)) end local function parseScanReport(report) - local result = {} + local result = {} - table.insert(result, ("Permalink: %s"):format(report.permalink)) - table.insert(result, ("Scan date: %s"):format(report.scan_date)) - table.insert(result, ("Positives: %s"):format(report.positives)) - table.insert(result, { - name = "digests", - ("SHA1: %s"):format(report.sha1), - ("SHA256: %s"):format(report.sha256), - ("MD5: %s"):format(report.md5) - }) + table.insert(result, ("Permalink: %s"):format(report.permalink)) + table.insert(result, ("Scan date: %s"):format(report.scan_date)) + table.insert(result, ("Positives: %s"):format(report.positives)) + table.insert(result, { + name = "digests", + ("SHA1: %s"):format(report.sha1), + ("SHA256: %s"):format(report.sha256), + ("MD5: %s"):format(report.md5) + }) - local tmp = {} - for name, scanres in pairs(report.scans) do - local res = ( scanres.detected ) and scanres.result or "-" - table.insert(tmp, { name = name, result = res, update = scanres.update, version = scanres.version }) - end - table.sort(tmp, function(a,b) return a.name:upper() 2 and diffs[i-1] > 20000 then - return "Randomized" - end + if #ipids > 2 and diffs[i-1] > 20000 then + return "Randomized" + end - i = i + 1 - end + i = i + 1 + end - if allzeros then - return "All zeros" - end + if allzeros then + return "All zeros" + end - i = 1 + i = 1 - while i <= #diffs do - if diffs[i] ~= 0 then - allsame = false - end + while i <= #diffs do + if diffs[i] ~= 0 then + allsame = false + end - if (diffs[i] > 1000) and ((diffs[i] % 256) ~= 0 or - ((diffs[i] % 256) == 0 and diffs[i] > 25600)) then - return "Random Positive Increments" - end + if (diffs[i] > 1000) and ((diffs[i] % 256) ~= 0 or + ((diffs[i] % 256) == 0 and diffs[i] > 25600)) then + return "Random Positive Increments" + end - if diffs[i] > 5120 or (diffs[i] % 256) ~= 0 then - mul256 = false - end + if diffs[i] > 5120 or (diffs[i] % 256) ~= 0 then + mul256 = false + end - if diffs[i] >= 10 then - inc = false - end + if diffs[i] >= 10 then + inc = false + end - i = i + 1 - end + i = i + 1 + end - if allsame then - return "Constant" - end + if allsame then + return "Constant" + end - if mul256 then - return "Broken incremental!" - end + if mul256 then + return "Broken incremental!" + end - if inc then - return "Incremental!" - end + if inc then + return "Incremental!" + end - return "Unknown" + return "Unknown" end --- Determines what port to probe -- @param host Host object local getport = function(host) - for _, k in ipairs({"ipidseq.probeport", "probeport"}) do - if nmap.registry.args[k] then - return tonumber(nmap.registry.args[k]) - end - end + for _, k in ipairs({"ipidseq.probeport", "probeport"}) do + if nmap.registry.args[k] then + return tonumber(nmap.registry.args[k]) + end + end - --local states = { "open", "closed", "unfiltered", "open|filtered", "closed|filtered" } - local states = { "open", "closed" } - local port = nil + --local states = { "open", "closed", "unfiltered", "open|filtered", "closed|filtered" } + local states = { "open", "closed" } + local port = nil - for _, s in ipairs(states) do - port = nmap.get_ports(host, nil, "tcp", s) - if port then - break - end - end + for _, s in ipairs(states) do + port = nmap.get_ports(host, nil, "tcp", s) + if port then + break + end + end - if not port then - return nil - end + if not port then + return nil + end - return port.number + return port.number end hostrule = function(host) - if not nmap.is_privileged() then - nmap.registry[SCRIPT_NAME] = nmap.registry[SCRIPT_NAME] or {} - if not nmap.registry[SCRIPT_NAME].rootfail then - stdnse.print_verbose("%s not running for lack of privileges.", SCRIPT_NAME) - end - nmap.registry[SCRIPT_NAME].rootfail = true - return nil - end + if not nmap.is_privileged() then + nmap.registry[SCRIPT_NAME] = nmap.registry[SCRIPT_NAME] or {} + if not nmap.registry[SCRIPT_NAME].rootfail then + stdnse.print_verbose("%s not running for lack of privileges.", SCRIPT_NAME) + end + nmap.registry[SCRIPT_NAME].rootfail = true + return nil + end - if nmap.address_family() ~= 'inet' then - stdnse.print_debug("%s is IPv4 compatible only.", SCRIPT_NAME) - return false - end - if not host.interface then - return false - end - ipidseqport = getport(host) - return (ipidseqport ~= nil) + if nmap.address_family() ~= 'inet' then + stdnse.print_debug("%s is IPv4 compatible only.", SCRIPT_NAME) + return false + end + if not host.interface then + return false + end + ipidseqport = getport(host) + return (ipidseqport ~= nil) end action = function(host) - local i = 1 - local ipids = {} - local sock = nmap.new_dnet() - local pcap = nmap.new_socket() - local saddr = packet.toip(host.bin_ip_src) - local daddr = packet.toip(host.bin_ip) - local try = nmap.new_try() + local i = 1 + local ipids = {} + local sock = nmap.new_dnet() + local pcap = nmap.new_socket() + local saddr = packet.toip(host.bin_ip_src) + local daddr = packet.toip(host.bin_ip) + local try = nmap.new_try() - try(sock:ip_open()) + try(sock:ip_open()) - try = nmap.new_try(function() sock:ip_close() end) + try = nmap.new_try(function() sock:ip_close() end) - pcap:pcap_open(host.interface, 104, false, "tcp and dst host " .. saddr .. " and src host " .. daddr .. " and src port " .. ipidseqport) + pcap:pcap_open(host.interface, 104, false, "tcp and dst host " .. saddr .. " and src host " .. daddr .. " and src port " .. ipidseqport) - pcap:set_timeout(host.times.timeout * 1000) + pcap:set_timeout(host.times.timeout * 1000) - local tcp = genericpkt(host, ipidseqport) + local tcp = genericpkt(host, ipidseqport) - while i <= NUMPROBES do - try(sock:ip_send(tcp.buf, host)) + while i <= NUMPROBES do + try(sock:ip_send(tcp.buf, host)) - local status, len, _, layer3 = pcap:pcap_receive() - local test = bin.pack('AA=S=S', tcp.ip_bin_src, tcp.ip_bin_dst, tcp.tcp_sport, tcp.tcp_dport) - while status and test ~= check(layer3) do - status, len, _, layer3 = pcap:pcap_receive() - end + local status, len, _, layer3 = pcap:pcap_receive() + local test = bin.pack('AA=S=S', tcp.ip_bin_src, tcp.ip_bin_dst, tcp.tcp_sport, tcp.tcp_dport) + while status and test ~= check(layer3) do + status, len, _, layer3 = pcap:pcap_receive() + end - if status then - table.insert(ipids, packet.u16(layer3, 4)) - end + if status then + table.insert(ipids, packet.u16(layer3, 4)) + end - updatepkt(tcp) + updatepkt(tcp) - i = i + 1 - end + i = i + 1 + end - pcap:close() - sock:ip_close() + pcap:close() + sock:ip_close() - local output = ipidseqclass(ipids) + local output = ipidseqclass(ipids) - if nmap.debugging() > 0 then - output = output .. " [used port " .. ipidseqport .. "]" - end + if nmap.debugging() > 0 then + output = output .. " [used port " .. ipidseqport .. "]" + end - return output + return output end diff --git a/scripts/ipv6-ra-flood.nse b/scripts/ipv6-ra-flood.nse index c3656026d..e9b5ca0b5 100644 --- a/scripts/ipv6-ra-flood.nse +++ b/scripts/ipv6-ra-flood.nse @@ -43,50 +43,50 @@ try = nmap.new_try() math.randomseed(os.time()) prerule = function() - if nmap.address_family() ~= "inet6" then - stdnse.print_debug("%s is IPv6 compatible only.", SCRIPT_NAME) - return false - end + if nmap.address_family() ~= "inet6" then + stdnse.print_debug("%s is IPv6 compatible only.", SCRIPT_NAME) + return false + end - if not nmap.is_privileged() then - stdnse.print_debug("Running %s needs root privileges.", SCRIPT_NAME) - return false - end + if not nmap.is_privileged() then + stdnse.print_debug("Running %s needs root privileges.", SCRIPT_NAME) + return false + end - if not stdnse.get_script_args(SCRIPT_NAME .. ".interface") and not nmap.get_interface() then - stdnse.print_debug("No interface was selected, aborting...", SCRIPT_NAME) - return false - end + if not stdnse.get_script_args(SCRIPT_NAME .. ".interface") and not nmap.get_interface() then + stdnse.print_debug("No interface was selected, aborting...", SCRIPT_NAME) + return false + end - return true + return true end local function get_interface() - local arg_interface = stdnse.get_script_args(SCRIPT_NAME .. ".interface") or nmap.get_interface() + local arg_interface = stdnse.get_script_args(SCRIPT_NAME .. ".interface") or nmap.get_interface() - local if_table = nmap.get_interface_info(arg_interface) + local if_table = nmap.get_interface_info(arg_interface) - if if_table and packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then - return if_table.device - else - stdnse.print_debug("Interface %s not supported or not properly configured, exiting...", arg_interface) - end + if if_table and packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then + return if_table.device + else + stdnse.print_debug("Interface %s not supported or not properly configured, exiting...", arg_interface) + end end --- Generates random MAC address -- @return mac string containing random MAC address local function random_mac() - local mac = string.format("%02x:%02x:%02x:%02x:%02x:%02x", 00, 180, math.random(256)-1, math.random(256)-1, math.random(256)-1, math.random(256)-1) - return mac + local mac = string.format("%02x:%02x:%02x:%02x:%02x:%02x", 00, 180, math.random(256)-1, math.random(256)-1, math.random(256)-1, math.random(256)-1) + return mac end --- Generates random IPv6 prefix -- @return prefix string containing random IPv6 /64 prefix local function get_random_prefix() - local prefix = string.format("2a01:%02x%02x:%02x%02x:%02x%02x::", math.random(256)-1, math.random(256)-1, math.random(256)-1, math.random(256)-1, math.random(256)-1, math.random(256)-1) + local prefix = string.format("2a01:%02x%02x:%02x%02x:%02x%02x::", math.random(256)-1, math.random(256)-1, math.random(256)-1, math.random(256)-1, math.random(256)-1, math.random(256)-1) - return prefix + return prefix end --- Build an ICMPv6 payload of Router Advertisement. @@ -99,94 +99,94 @@ end -- @return icmpv6_payload string representing ICMPv6 RA payload local function build_router_advert(mac_src,prefix,prefix_len,valid_time,preferred_time, mtu) - local ra_msg = string.char(0x0, --cur hop limit - 0x08, --flags - 0x00,0x00, --router lifetime - 0x00,0x00,0x00,0x00, --reachable time - 0x00,0x00,0x00,0x00) --retrans timer + local ra_msg = string.char(0x0, --cur hop limit + 0x08, --flags + 0x00,0x00, --router lifetime + 0x00,0x00,0x00,0x00, --reachable time + 0x00,0x00,0x00,0x00) --retrans timer - local mtu_option_msg = string.char(0x00, 0x00) .. -- reserved - packet.numtostr32(mtu) -- MTU + local mtu_option_msg = string.char(0x00, 0x00) .. -- reserved + packet.numtostr32(mtu) -- MTU - local prefix_option_msg = string.char(prefix_len, 0xc0) .. --flags: Onlink, Auto - packet.set_u32("....", 0, valid_time) .. -- valid lifetime - packet.set_u32("....", 0, preferred_time) .. -- preffered lifetime - string.char(0,0,0,0) .. --unknown - prefix + local prefix_option_msg = string.char(prefix_len, 0xc0) .. --flags: Onlink, Auto + packet.set_u32("....", 0, valid_time) .. -- valid lifetime + packet.set_u32("....", 0, preferred_time) .. -- preffered lifetime + string.char(0,0,0,0) .. --unknown + prefix - local icmpv6_mtu_option = packet.Packet:set_icmpv6_option(packet.ND_OPT_MTU, mtu_option_msg) - local icmpv6_prefix_option = packet.Packet:set_icmpv6_option(packet.ND_OPT_PREFIX_INFORMATION, prefix_option_msg) - local icmpv6_src_link_option = packet.Packet:set_icmpv6_option(packet.ND_OPT_SOURCE_LINKADDR, mac_src) + local icmpv6_mtu_option = packet.Packet:set_icmpv6_option(packet.ND_OPT_MTU, mtu_option_msg) + local icmpv6_prefix_option = packet.Packet:set_icmpv6_option(packet.ND_OPT_PREFIX_INFORMATION, prefix_option_msg) + local icmpv6_src_link_option = packet.Packet:set_icmpv6_option(packet.ND_OPT_SOURCE_LINKADDR, mac_src) - local icmpv6_payload = ra_msg .. icmpv6_mtu_option .. icmpv6_prefix_option .. icmpv6_src_link_option + local icmpv6_payload = ra_msg .. icmpv6_mtu_option .. icmpv6_prefix_option .. icmpv6_src_link_option - return icmpv6_payload + return icmpv6_payload end --- Broadcasting on the selected interface -- @param iface table containing interface information local function broadcast_on_interface(iface) - stdnse.print_verbose("Starting " .. SCRIPT_NAME .. " on interface " .. iface) + stdnse.print_verbose("Starting " .. SCRIPT_NAME .. " on interface " .. iface) - -- packet counter - local counter = 0 + -- packet counter + local counter = 0 - local arg_timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME..".timeout")) - arg_timeout = arg_timeout or 30 + local arg_timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME..".timeout")) + arg_timeout = arg_timeout or 30 - local dnet = nmap.new_dnet() + local dnet = nmap.new_dnet() - try(dnet:ethernet_open(iface)) + try(dnet:ethernet_open(iface)) - local dst_mac = packet.mactobin("33:33:00:00:00:01") - local dst_ip6_addr = packet.ip6tobin("ff02::1") + local dst_mac = packet.mactobin("33:33:00:00:00:01") + local dst_ip6_addr = packet.ip6tobin("ff02::1") - local prefix_len = 64 + local prefix_len = 64 - --- maximum possible value of 4-byte integer - local valid_time = tonumber(0xffffffff) - local preffered_time = tonumber(0xffffffff) + --- maximum possible value of 4-byte integer + local valid_time = tonumber(0xffffffff) + local preffered_time = tonumber(0xffffffff) - local mtu = 1500 + local mtu = 1500 - local start, stop = os.time() + local start, stop = os.time() - while true do + while true do - local src_mac = packet.mactobin(random_mac()) - local src_ip6_addr = packet.mac_to_lladdr(src_mac) + local src_mac = packet.mactobin(random_mac()) + local src_ip6_addr = packet.mac_to_lladdr(src_mac) - local prefix = packet.ip6tobin(get_random_prefix()) + local prefix = packet.ip6tobin(get_random_prefix()) - local packet = packet.Frame:new() + local packet = packet.Frame:new() - packet.mac_src = src_mac - packet.mac_dst = dst_mac - packet.ip_bin_src = src_ip6_addr - packet.ip_bin_dst = dst_ip6_addr + packet.mac_src = src_mac + packet.mac_dst = dst_mac + packet.ip_bin_src = src_ip6_addr + packet.ip_bin_dst = dst_ip6_addr - local icmpv6_payload = build_router_advert(src_mac, prefix, prefix_len, valid_time, preffered_time, mtu) - packet:build_icmpv6_header(134, 0, icmpv6_payload) - packet:build_ipv6_packet() - packet:build_ether_frame() + local icmpv6_payload = build_router_advert(src_mac, prefix, prefix_len, valid_time, preffered_time, mtu) + packet:build_icmpv6_header(134, 0, icmpv6_payload) + packet:build_ipv6_packet() + packet:build_ether_frame() - try(dnet:ethernet_send(packet.frame_buf)) + try(dnet:ethernet_send(packet.frame_buf)) - counter = counter + 1 + counter = counter + 1 - if arg_timeout and arg_timeout > 0 and arg_timeout <= os.time() - start then - stop = os.time() - break - end - end + if arg_timeout and arg_timeout > 0 and arg_timeout <= os.time() - start then + stop = os.time() + break + end + end - if counter > 0 then - stdnse.print_debug("%s generated %d packets in %d seconds.", SCRIPT_NAME, counter, stop - start) - end + if counter > 0 then + stdnse.print_debug("%s generated %d packets in %d seconds.", SCRIPT_NAME, counter, stop - start) + end end function action() - local interface = get_interface() + local interface = get_interface() - broadcast_on_interface(interface) + broadcast_on_interface(interface) end diff --git a/scripts/irc-unrealircd-backdoor.nse b/scripts/irc-unrealircd-backdoor.nse index e7de0e2a4..58e990711 100644 --- a/scripts/irc-unrealircd-backdoor.nse +++ b/scripts/irc-unrealircd-backdoor.nse @@ -58,159 +58,159 @@ portrule = shortport.port_or_service({6666,6667,6697,6679,8067},{"irc","ircs"}) action = function(host, port) - local socket = nmap.new_socket() - local code, message - local status, err - local data - -- Wait up to this long for the server to send its startup messages and - -- a response to our noop_command. After this, send the full_command. - -- Usually we don't have to wait the full time because we can detect - -- the response to noop_command. - local banner_timeout = 60 - -- Send a command to sleep this long. This just has to be long enough - -- to remove confusion from network delay. - local delay = 8 + local socket = nmap.new_socket() + local code, message + local status, err + local data + -- Wait up to this long for the server to send its startup messages and + -- a response to our noop_command. After this, send the full_command. + -- Usually we don't have to wait the full time because we can detect + -- the response to noop_command. + local banner_timeout = 60 + -- Send a command to sleep this long. This just has to be long enough + -- to remove confusion from network delay. + local delay = 8 - -- If the command takes (delay - delay_fudge) or more seconds, the server is vulnerable. - -- I defined the furdge as 1 second, for now, just because of rounding issues. In practice, - -- the actual delay should never be shorter than the given delay, only longer. - local delay_fudge = 1 + -- If the command takes (delay - delay_fudge) or more seconds, the server is vulnerable. + -- I defined the furdge as 1 second, for now, just because of rounding issues. In practice, + -- the actual delay should never be shorter than the given delay, only longer. + local delay_fudge = 1 - -- We send this command on connection because comm.tryssl needs to send - -- something; it also allows us to detect the end of server - -- initialization. - local noop_command = "TIME" + -- We send this command on connection because comm.tryssl needs to send + -- something; it also allows us to detect the end of server + -- initialization. + local noop_command = "TIME" - -- The 'AB' sequence triggers the backdoor to run a command. - local trigger = "AB" + -- The 'AB' sequence triggers the backdoor to run a command. + local trigger = "AB" - -- We define a highly unique variable as a type of 'ping' -- it lets us see when our - -- command returns. Typically, asynchronous data will be received after the initial - -- connection -- this lets us ignore that extra data. - local unique = "SOMETHINGUNIQUE" + -- We define a highly unique variable as a type of 'ping' -- it lets us see when our + -- command returns. Typically, asynchronous data will be received after the initial + -- connection -- this lets us ignore that extra data. + local unique = "SOMETHINGUNIQUE" - -- On Linux, do a simple sleep command. - local command_linux = "sleep " .. delay + -- On Linux, do a simple sleep command. + local command_linux = "sleep " .. delay - -- Set up an extra command, if the user requested one - local command_extra = "" - if(stdnse.get_script_args('irc-unrealircd-backdoor.command')) then - command_extra = stdnse.get_script_args('irc-unrealircd-backdoor.command') - -- Replace "%IP%" with the ip address - command_extra = string.gsub(command_extra, '%%IP%%', host.ip) - end + -- Set up an extra command, if the user requested one + local command_extra = "" + if(stdnse.get_script_args('irc-unrealircd-backdoor.command')) then + command_extra = stdnse.get_script_args('irc-unrealircd-backdoor.command') + -- Replace "%IP%" with the ip address + command_extra = string.gsub(command_extra, '%%IP%%', host.ip) + end - -- Windows, unfortunately, doesn't have a sleep command. Instead, we use 'ping' to - -- simulate a sleep (thanks to Ed Skoudis for teaching me this one!). We always want - -- to add 1 to the delay because the first ping happens instantly. - -- - -- This is likely unnecessary, because the Windows version of UnrealIRCd is reportedly - -- not vulnerable. However, it's possible that some odd person may have compiled it - -- from the vulnerable sourcecode, so we check for it anyways. - local command_windows = "ping -n " .. (delay + 1) .. " 127.0.0.1" + -- Windows, unfortunately, doesn't have a sleep command. Instead, we use 'ping' to + -- simulate a sleep (thanks to Ed Skoudis for teaching me this one!). We always want + -- to add 1 to the delay because the first ping happens instantly. + -- + -- This is likely unnecessary, because the Windows version of UnrealIRCd is reportedly + -- not vulnerable. However, it's possible that some odd person may have compiled it + -- from the vulnerable sourcecode, so we check for it anyways. + local command_windows = "ping -n " .. (delay + 1) .. " 127.0.0.1" - -- Put together the full command - local full_command = string.format("%s;%s;%s;%s;%s", trigger, unique, command_linux, command_windows, command_extra) + -- Put together the full command + local full_command = string.format("%s;%s;%s;%s;%s", trigger, unique, command_linux, command_windows, command_extra) - -- wait time: get rid of fast reconnecting annoyance - if(stdnse.get_script_args('irc-unrealircd-backdoor.wait')) then - local waittime = stdnse.get_script_args('irc-unrealircd-backdoor.wait') - stdnse.print_debug(1, "irc-unrealircd-backdoor: waiting for %i seconds", waittime) - stdnse.sleep(waittime) - end + -- wait time: get rid of fast reconnecting annoyance + if(stdnse.get_script_args('irc-unrealircd-backdoor.wait')) then + local waittime = stdnse.get_script_args('irc-unrealircd-backdoor.wait') + stdnse.print_debug(1, "irc-unrealircd-backdoor: waiting for %i seconds", waittime) + stdnse.sleep(waittime) + end - -- Send an innocuous command as fodder for tryssl. - stdnse.print_debug(1, "irc-unrealircd-backdoor: Sending command: %s", noop_command); - local socket, response = comm.tryssl(host, port, noop_command .. "\n", {recv_before=false}) + -- Send an innocuous command as fodder for tryssl. + stdnse.print_debug(1, "irc-unrealircd-backdoor: Sending command: %s", noop_command); + local socket, response = comm.tryssl(host, port, noop_command .. "\n", {recv_before=false}) - -- Make sure the socket worked - if(not(socket) or not(response)) then - stdnse.print_debug(1, "irc-unrealircd-backdoor: Couldn't connect to remote host") - return nil - end + -- Make sure the socket worked + if(not(socket) or not(response)) then + stdnse.print_debug(1, "irc-unrealircd-backdoor: Couldn't connect to remote host") + return nil + end - socket:set_timeout(banner_timeout * 1000) + socket:set_timeout(banner_timeout * 1000) - -- Look for the end of initial server messages. This allows reverse DNS - -- resolution and ident lookups to time out and not interfere with our - -- timing measurement. - status = true - data = response - while status and not (string.find(data, noop_command) or string.find(data, " 451 ")) do - status, response = socket:receive_bytes(0) - if status then - data = data .. response - end - end + -- Look for the end of initial server messages. This allows reverse DNS + -- resolution and ident lookups to time out and not interfere with our + -- timing measurement. + status = true + data = response + while status and not (string.find(data, noop_command) or string.find(data, " 451 ")) do + status, response = socket:receive_bytes(0) + if status then + data = data .. response + end + end - if not status then - stdnse.print_debug(1, "irc-unrealircd-backdoor: Receive failed after %s: %s", noop_command, response) - return nil - end + if not status then + stdnse.print_debug(1, "irc-unrealircd-backdoor: Receive failed after %s: %s", noop_command, response) + return nil + end - -- Send the backdoor command. - stdnse.print_debug(1, "irc-unrealircd-backdoor: Sending command: %s", full_command); - status, err = socket:send(full_command .. "\n") - if not status then - stdnse.print_debug(1, "irc-unrealircd-backdoor: Send failed: %s", err) - return nil - end + -- Send the backdoor command. + stdnse.print_debug(1, "irc-unrealircd-backdoor: Sending command: %s", full_command); + status, err = socket:send(full_command .. "\n") + if not status then + stdnse.print_debug(1, "irc-unrealircd-backdoor: Send failed: %s", err) + return nil + end - -- Get the current time so we can measure the delay - local time = os.time(os.date('*t')) - socket:set_timeout((delay + 5) * 1000) + -- Get the current time so we can measure the delay + local time = os.time(os.date('*t')) + socket:set_timeout((delay + 5) * 1000) - -- Accumulate the response in the 'data' string - status = true - data = "" - while not string.find(data, unique) do - status, response = socket:receive_bytes(0) - if status then - data = data .. response - else - -- If the server unexpectedly closes the connection, it - -- is usually related to throttling. Therefore, we - -- print a throttling warning. - stdnse.print_debug(1, "irc-unrealircd-backdoor: Receive failed: %s", response) - socket:close() - return "Server closed connection, possibly due to too many reconnects. Try again with argument irc-unrealircd-backdoor.wait set to 100 (or higher if you get this message again)." - end - end + -- Accumulate the response in the 'data' string + status = true + data = "" + while not string.find(data, unique) do + status, response = socket:receive_bytes(0) + if status then + data = data .. response + else + -- If the server unexpectedly closes the connection, it + -- is usually related to throttling. Therefore, we + -- print a throttling warning. + stdnse.print_debug(1, "irc-unrealircd-backdoor: Receive failed: %s", response) + socket:close() + return "Server closed connection, possibly due to too many reconnects. Try again with argument irc-unrealircd-backdoor.wait set to 100 (or higher if you get this message again)." + end + end - -- Determine the elapsed time - local elapsed = os.time(os.date('*t')) - time + -- Determine the elapsed time + local elapsed = os.time(os.date('*t')) - time - -- Let the user know that everything's working - stdnse.print_debug(1, "irc-unrealircd-backdoor: Received a response to our command in " .. elapsed .. " seconds") + -- Let the user know that everything's working + stdnse.print_debug(1, "irc-unrealircd-backdoor: Received a response to our command in " .. elapsed .. " seconds") - -- Determine whether or not the vulnerability is present - if(elapsed > (delay - delay_fudge)) then - -- Check if the user wants to kill the server. - if(stdnse.get_script_args('irc-unrealircd-backdoor.kill')) then - stdnse.print_debug(1, "irc-unrealircd-backdoor: Attempting to kill the Trojanned UnrealIRCd server...") + -- Determine whether or not the vulnerability is present + if(elapsed > (delay - delay_fudge)) then + -- Check if the user wants to kill the server. + if(stdnse.get_script_args('irc-unrealircd-backdoor.kill')) then + stdnse.print_debug(1, "irc-unrealircd-backdoor: Attempting to kill the Trojanned UnrealIRCd server...") - local linux_kill = "kill `ps -e | grep ircd | awk '{ print $1 }'`" - local windows_kill = 'wmic process where "name like \'%ircd%\'" delete' - local kill_command = string.format("%s||%s||%s", trigger, linux_kill, windows_kill) + local linux_kill = "kill `ps -e | grep ircd | awk '{ print $1 }'`" + local windows_kill = 'wmic process where "name like \'%ircd%\'" delete' + local kill_command = string.format("%s||%s||%s", trigger, linux_kill, windows_kill) - -- Kill the process - stdnse.print_debug(1, "Running kill command: %s", kill_command) - socket:send(kill_command .. "\n") - end + -- Kill the process + stdnse.print_debug(1, "Running kill command: %s", kill_command) + socket:send(kill_command .. "\n") + end - stdnse.print_debug(1, "irc-unrealircd-backdoor: Looks like the Trojanned unrealircd is running!") + stdnse.print_debug(1, "irc-unrealircd-backdoor: Looks like the Trojanned unrealircd is running!") - -- Close the socket - socket:close() + -- Close the socket + socket:close() - return "Looks like trojaned version of unrealircd. See http://seclists.org/fulldisclosure/2010/Jun/277" - end + return "Looks like trojaned version of unrealircd. See http://seclists.org/fulldisclosure/2010/Jun/277" + end - -- Close the socket - socket:close() + -- Close the socket + socket:close() - stdnse.print_debug(1, "irc-unrealircd-backdoor: The Trojanned version of unrealircd probably isn't running.") + stdnse.print_debug(1, "irc-unrealircd-backdoor: The Trojanned version of unrealircd probably isn't running.") - return nil + return nil end diff --git a/scripts/llmnr-resolve.nse b/scripts/llmnr-resolve.nse index b502b8ba5..15a6ac485 100644 --- a/scripts/llmnr-resolve.nse +++ b/scripts/llmnr-resolve.nse @@ -37,11 +37,11 @@ For more information, see: -- prerule = function() - if not nmap.is_privileged() then - stdnse.print_verbose("%s not running due to lack of privileges.", SCRIPT_NAME) - return false - end - return true + if not nmap.is_privileged() then + stdnse.print_verbose("%s not running due to lack of privileges.", SCRIPT_NAME) + return false + end + return true end author = "Hani Benhabiles" @@ -55,30 +55,30 @@ categories = {"discovery", "safe", "broadcast"} -- @param hostname Hostname to query for. -- @return query Raw llmnr query. local llmnrQuery = function(hostname) - local query = bin.pack(">S", math.random(0,65535)) -- transaction ID - query = query .. bin.pack(">S", 0x0000) -- Flags: Standard Query - query = query .. bin.pack(">S", 0x0001) -- Questions = 1 - query = query .. bin.pack(">S", 0x0000) -- Answer RRs = 0 - query = query .. bin.pack(">S", 0x0000) -- Authority RRs = 0 - query = query .. bin.pack(">S", 0x0000) -- Additional RRs = 0 - query = query .. bin.pack(">CAC", #hostname, hostname, 0x00) -- Hostname - query = query .. bin.pack(">S", 0x0001) -- Type: Host Address - query = query .. bin.pack(">S", 0x0001) -- Class: IN - return query + local query = bin.pack(">S", math.random(0,65535)) -- transaction ID + query = query .. bin.pack(">S", 0x0000) -- Flags: Standard Query + query = query .. bin.pack(">S", 0x0001) -- Questions = 1 + query = query .. bin.pack(">S", 0x0000) -- Answer RRs = 0 + query = query .. bin.pack(">S", 0x0000) -- Authority RRs = 0 + query = query .. bin.pack(">S", 0x0000) -- Additional RRs = 0 + query = query .. bin.pack(">CAC", #hostname, hostname, 0x00) -- Hostname + query = query .. bin.pack(">S", 0x0001) -- Type: Host Address + query = query .. bin.pack(">S", 0x0001) -- Class: IN + return query end --- Sends a llmnr query. -- @param query Query to send. local llmnrSend = function(query, mcast, mport) - -- Multicast IP and UDP port - local sock = nmap.new_socket() - local status, err = sock:connect(mcast, mport, "udp") - if not status then - stdnse.print_debug("%s: %s", SCRIPT_NAME, err) - return - end - sock:send(query) - sock:close() + -- Multicast IP and UDP port + local sock = nmap.new_socket() + local status, err = sock:connect(mcast, mport, "udp") + if not status then + stdnse.print_debug("%s: %s", SCRIPT_NAME, err) + return + end + sock:send(query) + sock:close() end -- Listens for llmnr responses @@ -86,130 +86,130 @@ end -- @param timeout Maximum time to listen. -- @param result table to put responses into. local llmnrListen = function(interface, timeout, result) - local condvar = nmap.condvar(result) - local start = nmap.clock_ms() - local listener = nmap.new_socket() - local status, l3data, _ + local condvar = nmap.condvar(result) + local start = nmap.clock_ms() + local listener = nmap.new_socket() + local status, l3data, _ - -- packets that are sent to our UDP port number 5355 - local filter = 'dst host ' .. interface.address .. ' and udp src port 5355' - listener:set_timeout(100) - listener:pcap_open(interface.device, 1024, true, filter) + -- packets that are sent to our UDP port number 5355 + local filter = 'dst host ' .. interface.address .. ' and udp src port 5355' + listener:set_timeout(100) + listener:pcap_open(interface.device, 1024, true, filter) - while (nmap.clock_ms() - start) < timeout do - status, _, _, l3data = listener:pcap_receive() - if status then - local p = packet.Packet:new(l3data, #l3data) - -- Skip IP and UDP headers - local llmnr = string.sub(l3data, p.ip_hl*4 + 8 + 1) - -- Flags - local _, trans = bin.unpack(">S", llmnr) - local _, flags = bin.unpack(">S", llmnr, 3) - -- Questions number - local _, questions = bin.unpack(">S", llmnr, 5) + while (nmap.clock_ms() - start) < timeout do + status, _, _, l3data = listener:pcap_receive() + if status then + local p = packet.Packet:new(l3data, #l3data) + -- Skip IP and UDP headers + local llmnr = string.sub(l3data, p.ip_hl*4 + 8 + 1) + -- Flags + local _, trans = bin.unpack(">S", llmnr) + local _, flags = bin.unpack(">S", llmnr, 3) + -- Questions number + local _, questions = bin.unpack(">S", llmnr, 5) - -- Make verifications - -- Message == Response bit - -- and 1 Question (hostname we requested) and - if (bit.rshift(flags, 15) == 1) and questions == 0x01 then - stdnse.print_debug("%s got response from %s", SCRIPT_NAME, p.ip_src) - -- Skip header's 12 bytes - -- extract host length - local index, qlen = bin.unpack(">C", llmnr, 13) - -- Skip hostname, null byte, type field and class field - index = index + qlen + 1 + 2 + 2 + -- Make verifications + -- Message == Response bit + -- and 1 Question (hostname we requested) and + if (bit.rshift(flags, 15) == 1) and questions == 0x01 then + stdnse.print_debug("%s got response from %s", SCRIPT_NAME, p.ip_src) + -- Skip header's 12 bytes + -- extract host length + local index, qlen = bin.unpack(">C", llmnr, 13) + -- Skip hostname, null byte, type field and class field + index = index + qlen + 1 + 2 + 2 - -- Now, answer record - local response, alen = {} - index, alen = bin.unpack(">C", llmnr, index) - -- Extract hostname with the correct case sensivity. - index, response.hostname = bin.unpack(">A".. alen, llmnr, index) + -- Now, answer record + local response, alen = {} + index, alen = bin.unpack(">C", llmnr, index) + -- Extract hostname with the correct case sensivity. + index, response.hostname = bin.unpack(">A".. alen, llmnr, index) - -- skip null byte, type, class, ttl, dlen - index = index + 1 + 2 + 2 + 4 + 2 - index, response.address = bin.unpack(" 0 then - for _, response in pairs(result) do - table.insert(output, response.hostname.. " : " .. response.address) - if target.ALLOW_NEW_TARGETS then - target.add(response.address) - end + -- Check responses + if #result > 0 then + for _, response in pairs(result) do + table.insert(output, response.hostname.. " : " .. response.address) + if target.ALLOW_NEW_TARGETS then + target.add(response.address) end - if ( not(target.ALLOW_NEW_TARGETS) ) then - table.insert(output,"Use the newtargets script-arg to add the results as targets") - end - return stdnse.format_output(true, output) end + if ( not(target.ALLOW_NEW_TARGETS) ) then + table.insert(output,"Use the newtargets script-arg to add the results as targets") + end + return stdnse.format_output(true, output) + end end diff --git a/scripts/ms-sql-info.nse b/scripts/ms-sql-info.nse index 18366a08c..2ab52b005 100644 --- a/scripts/ms-sql-info.nse +++ b/scripts/ms-sql-info.nse @@ -105,7 +105,7 @@ be disabled using the mssql.scanned-ports-only script argument. -- added script arg to prevent script from connecting to ports that -- weren't in original Nmap scan ) -- rev 1.5 (2011-02-01 - Moved discovery functionality into ms-sql-discover.nse and --- broadcast-ms-sql-discovery.nse ) +-- broadcast-ms-sql-discovery.nse ) author = "Chris Woodbury, Thomas Buchanan" @@ -115,75 +115,75 @@ categories = {"default", "discovery", "safe"} hostrule = function(host) - if ( mssql.Helper.WasDiscoveryPerformed( host ) ) then - return mssql.Helper.GetDiscoveredInstances( host ) ~= nil - else - local sqlDefaultPort = nmap.get_port_state( host, {number = 1433, protocol = "tcp"} ) - local sqlBrowserPort = nmap.get_port_state( host, {number = 1434, protocol = "udp"} ) - -- smb.get_port() will return nil if no SMB port was scanned OR if SMB ports were scanned but none was open - local smbPortNumber = smb.get_port( host ) + if ( mssql.Helper.WasDiscoveryPerformed( host ) ) then + return mssql.Helper.GetDiscoveredInstances( host ) ~= nil + else + local sqlDefaultPort = nmap.get_port_state( host, {number = 1433, protocol = "tcp"} ) + local sqlBrowserPort = nmap.get_port_state( host, {number = 1434, protocol = "udp"} ) + -- smb.get_port() will return nil if no SMB port was scanned OR if SMB ports were scanned but none was open + local smbPortNumber = smb.get_port( host ) - if ( (stdnse.get_script_args( {"mssql.instance-all", "mssql.instance-name", "mssql.instance-port"} ) ~= nil) or - (sqlBrowserPort and (sqlBrowserPort.state == "open" or sqlBrowserPort.state == "open|filtered")) or - (sqlDefaultPort and (sqlDefaultPort.state == "open" or sqlDefaultPort.state == "open|filtered")) or - (smbPortNumber ~= nil) ) then - return true - end - end + if ( (stdnse.get_script_args( {"mssql.instance-all", "mssql.instance-name", "mssql.instance-port"} ) ~= nil) or + (sqlBrowserPort and (sqlBrowserPort.state == "open" or sqlBrowserPort.state == "open|filtered")) or + (sqlDefaultPort and (sqlDefaultPort.state == "open" or sqlDefaultPort.state == "open|filtered")) or + (smbPortNumber ~= nil) ) then + return true + end + end end --- Adds a label and value to an output table. If the value is a boolean, it is -- converted to Yes/No; if the value is nil, nothing is added to the table. local function add_to_output_table( outputTable, outputLabel, outputData ) - if outputData == nil then return end + if outputData == nil then return end - if outputData == true then - outputData = "Yes" - elseif outputData == false then - outputData = "No" - end + if outputData == true then + outputData = "Yes" + elseif outputData == false then + outputData = "No" + end - table.insert(outputTable, string.format( "%s: %s", outputLabel, outputData ) ) + table.insert(outputTable, string.format( "%s: %s", outputLabel, outputData ) ) end --- Returns formatted output for the given version data local function create_version_output_table( versionInfo ) - local versionOutput = {} + local versionOutput = {} - versionOutput["name"] = "Version: " .. versionInfo:ToString() - if ( versionInfo.source ~= "SSRP" ) then - add_to_output_table( versionOutput, "Version number", versionInfo.versionNumber ) - end - add_to_output_table( versionOutput, "Product", versionInfo.productName ) - add_to_output_table( versionOutput, "Service pack level", versionInfo.servicePackLevel ) - add_to_output_table( versionOutput, "Post-SP patches applied", versionInfo.patched ) + versionOutput["name"] = "Version: " .. versionInfo:ToString() + if ( versionInfo.source ~= "SSRP" ) then + add_to_output_table( versionOutput, "Version number", versionInfo.versionNumber ) + end + add_to_output_table( versionOutput, "Product", versionInfo.productName ) + add_to_output_table( versionOutput, "Service pack level", versionInfo.servicePackLevel ) + add_to_output_table( versionOutput, "Post-SP patches applied", versionInfo.patched ) - return versionOutput + return versionOutput end --- Returns formatted output for the given instance local function create_instance_output_table( instance ) - -- if we didn't get anything useful (due to errors or the port not actually - -- being SQL Server), don't report anything - if not ( instance.instanceName or instance.version ) then return nil end + -- if we didn't get anything useful (due to errors or the port not actually + -- being SQL Server), don't report anything + if not ( instance.instanceName or instance.version ) then return nil end - local instanceOutput = {} - instanceOutput["name"] = string.format( "[%s]", instance:GetName() ) + local instanceOutput = {} + instanceOutput["name"] = string.format( "[%s]", instance:GetName() ) - add_to_output_table( instanceOutput, "Instance name", instance.instanceName ) - if instance.version then - local versionOutput = create_version_output_table( instance.version ) - table.insert( instanceOutput, versionOutput ) - end - if instance.port then add_to_output_table( instanceOutput, "TCP port", instance.port.number ) end - add_to_output_table( instanceOutput, "Named pipe", instance.pipeName ) - add_to_output_table( instanceOutput, "Clustered", instance.isClustered ) + add_to_output_table( instanceOutput, "Instance name", instance.instanceName ) + if instance.version then + local versionOutput = create_version_output_table( instance.version ) + table.insert( instanceOutput, versionOutput ) + end + if instance.port then add_to_output_table( instanceOutput, "TCP port", instance.port.number ) end + add_to_output_table( instanceOutput, "Named pipe", instance.pipeName ) + add_to_output_table( instanceOutput, "Clustered", instance.isClustered ) - return instanceOutput + return instanceOutput end @@ -191,74 +191,74 @@ end --- Processes a single instance, attempting to determine its version, etc. local function process_instance( instance ) - local foundVersion = false - local ssnetlibVersion + local foundVersion = false + local ssnetlibVersion - -- If possible and allowed (see 'mssql.scanned-ports-only' argument), we'll - -- connect to the instance to get an accurate version number - if ( instance:HasNetworkProtocols() ) then - local ssnetlibVersion - foundVersion, ssnetlibVersion = mssql.Helper.GetInstanceVersion( instance ) - if ( foundVersion ) then - instance.version = ssnetlibVersion - stdnse.print_debug( 1, "%s: Retrieved SSNetLib version for %s.", SCRIPT_NAME, instance:GetName() ) - else - stdnse.print_debug( 1, "%s: Could not retrieve SSNetLib version for %s.", SCRIPT_NAME, instance:GetName() ) - end - end + -- If possible and allowed (see 'mssql.scanned-ports-only' argument), we'll + -- connect to the instance to get an accurate version number + if ( instance:HasNetworkProtocols() ) then + local ssnetlibVersion + foundVersion, ssnetlibVersion = mssql.Helper.GetInstanceVersion( instance ) + if ( foundVersion ) then + instance.version = ssnetlibVersion + stdnse.print_debug( 1, "%s: Retrieved SSNetLib version for %s.", SCRIPT_NAME, instance:GetName() ) + else + stdnse.print_debug( 1, "%s: Could not retrieve SSNetLib version for %s.", SCRIPT_NAME, instance:GetName() ) + end + end - -- If we didn't get a version from SSNetLib, give the user some detail as to why - if ( not foundVersion ) then - if ( not instance:HasNetworkProtocols() ) then - stdnse.print_debug( 1, "%s: %s has no network protocols enabled.", SCRIPT_NAME, instance:GetName() ) - end - if ( instance.version ) then - stdnse.print_debug( 1, "%s: Using version number from SSRP response for %s.", SCRIPT_NAME, instance:GetName() ) - else - stdnse.print_debug( 1, "%s: Version info could not be retrieved for %s.", SCRIPT_NAME, instance:GetName() ) - end - end + -- If we didn't get a version from SSNetLib, give the user some detail as to why + if ( not foundVersion ) then + if ( not instance:HasNetworkProtocols() ) then + stdnse.print_debug( 1, "%s: %s has no network protocols enabled.", SCRIPT_NAME, instance:GetName() ) + end + if ( instance.version ) then + stdnse.print_debug( 1, "%s: Using version number from SSRP response for %s.", SCRIPT_NAME, instance:GetName() ) + else + stdnse.print_debug( 1, "%s: Version info could not be retrieved for %s.", SCRIPT_NAME, instance:GetName() ) + end + end - -- Give some version info back to Nmap - if ( instance.port and instance.version ) then - instance.version:PopulateNmapPortVersion( instance.port ) - nmap.set_port_version( instance.host, instance.port) - end + -- Give some version info back to Nmap + if ( instance.port and instance.version ) then + instance.version:PopulateNmapPortVersion( instance.port ) + nmap.set_port_version( instance.host, instance.port) + end end action = function( host ) - local scriptOutput = {} + local scriptOutput = {} - local status, instanceList = mssql.Helper.GetTargetInstances( host ) - -- if no instances were targeted, then display info on all - if ( not status ) then - if ( not mssql.Helper.WasDiscoveryPerformed( host ) ) then - mssql.Helper.Discover( host ) - end - instanceList = mssql.Helper.GetDiscoveredInstances( host ) - end + local status, instanceList = mssql.Helper.GetTargetInstances( host ) + -- if no instances were targeted, then display info on all + if ( not status ) then + if ( not mssql.Helper.WasDiscoveryPerformed( host ) ) then + mssql.Helper.Discover( host ) + end + instanceList = mssql.Helper.GetDiscoveredInstances( host ) + end - if ( not instanceList ) then - return stdnse.format_output( false, instanceList or "" ) - else - for _, instance in ipairs( instanceList ) do - if instance.serverName then - table.insert(scriptOutput, string.format( "Windows server name: %s", instance.serverName )) - break - end - end - for _, instance in pairs( instanceList ) do - process_instance( instance ) - local instanceOutput = create_instance_output_table( instance ) - if instanceOutput then - table.insert( scriptOutput, instanceOutput ) - end - end - end + if ( not instanceList ) then + return stdnse.format_output( false, instanceList or "" ) + else + for _, instance in ipairs( instanceList ) do + if instance.serverName then + table.insert(scriptOutput, string.format( "Windows server name: %s", instance.serverName )) + break + end + end + for _, instance in pairs( instanceList ) do + process_instance( instance ) + local instanceOutput = create_instance_output_table( instance ) + if instanceOutput then + table.insert( scriptOutput, instanceOutput ) + end + end + end - return stdnse.format_output( true, scriptOutput ) + return stdnse.format_output( true, scriptOutput ) end diff --git a/scripts/ms-sql-tables.nse b/scripts/ms-sql-tables.nse index 7e667820b..04557657b 100644 --- a/scripts/ms-sql-tables.nse +++ b/scripts/ms-sql-tables.nse @@ -54,7 +54,7 @@ be disabled using the mssql.scanned-ports-only script argument. -- (default 5). If set to zero or less all tables are returned. -- -- @args ms-sql-tables.keywords If set shows only tables or columns matching --- the keywords +-- the keywords -- -- @output -- | ms-sql-tables: @@ -84,13 +84,13 @@ be disabled using the mssql.scanned-ports-only script argument. -- Created 01/17/2010 - v0.1 - created by Patrik Karlsson -- Revised 04/02/2010 - v0.2 --- - Added support for filters --- - Changed output formatting of restrictions --- - Added parameter information in output if parameters are using their --- defaults. +-- - Added support for filters +-- - Changed output formatting of restrictions +-- - Added parameter information in output if parameters are using their +-- defaults. -- Revised 02/01/2011 - v0.3 (Chris Woodbury) --- - Added ability to run against all instances on a host; --- - Added compatibility with changes in mssql.lua +-- - Added ability to run against all instances on a host; +-- - Added compatibility with changes in mssql.lua author = "Patrik Karlsson" license = "Same as Nmap--See http://nmap.org/book/man-legal.html" @@ -104,169 +104,169 @@ portrule = mssql.Helper.GetPortrule_Standard() local function process_instance( instance ) - local status, result, dbs, tables + local status, result, dbs, tables - local output = {} - local exclude_dbs = { "'master'", "'tempdb'", "'model'", "'msdb'" } - local db_query - local done_dbs = {} - local db_limit, tbl_limit + local output = {} + local exclude_dbs = { "'master'", "'tempdb'", "'model'", "'msdb'" } + local db_query + local done_dbs = {} + local db_limit, tbl_limit - local DB_COUNT = stdnse.get_script_args( {'ms-sql-tables.maxdb', 'mssql-tables.maxdb'} ) - and tonumber( stdnse.get_script_args( {'ms-sql-tables.maxdb', 'mssql-tables.maxdb'} ) ) or 5 - local TABLE_COUNT = stdnse.get_script_args( {'ms-sql-tables.maxtables', 'mssql-tables.maxtables' } ) - and tonumber( stdnse.get_script_args( {'ms-sql-tables.maxtables', 'mssql-tables.maxtables' } ) ) or 2 - local keywords_filter = "" + local DB_COUNT = stdnse.get_script_args( {'ms-sql-tables.maxdb', 'mssql-tables.maxdb'} ) + and tonumber( stdnse.get_script_args( {'ms-sql-tables.maxdb', 'mssql-tables.maxdb'} ) ) or 5 + local TABLE_COUNT = stdnse.get_script_args( {'ms-sql-tables.maxtables', 'mssql-tables.maxtables' } ) + and tonumber( stdnse.get_script_args( {'ms-sql-tables.maxtables', 'mssql-tables.maxtables' } ) ) or 2 + local keywords_filter = "" - if ( DB_COUNT <= 0 ) then - db_limit = "" - else - db_limit = string.format( "TOP %d", DB_COUNT ) - end - if (TABLE_COUNT <= 0 ) then - tbl_limit = "" - else - tbl_limit = string.format( "TOP %d", TABLE_COUNT ) - end + if ( DB_COUNT <= 0 ) then + db_limit = "" + else + db_limit = string.format( "TOP %d", DB_COUNT ) + end + if (TABLE_COUNT <= 0 ) then + tbl_limit = "" + else + tbl_limit = string.format( "TOP %d", TABLE_COUNT ) + end - -- Build the keyword filter - if ( stdnse.get_script_args( {'ms-sql-tables.keywords', 'mssql-tables.keywords' } ) ) then - local keywords = stdnse.get_script_args( {'ms-sql-tables.keywords', 'mssql-tables.keywords' } ) - local tmp_tbl = {} + -- Build the keyword filter + if ( stdnse.get_script_args( {'ms-sql-tables.keywords', 'mssql-tables.keywords' } ) ) then + local keywords = stdnse.get_script_args( {'ms-sql-tables.keywords', 'mssql-tables.keywords' } ) + local tmp_tbl = {} - if( type(keywords) == 'string' ) then - keywords = { keywords } - end + if( type(keywords) == 'string' ) then + keywords = { keywords } + end - for _, v in ipairs(keywords) do - table.insert(tmp_tbl, ("'%s'"):format(v)) - end + for _, v in ipairs(keywords) do + table.insert(tmp_tbl, ("'%s'"):format(v)) + end - keywords_filter = (" AND ( so.name IN (%s) or sc.name IN (%s) ) "):format( - stdnse.strjoin(",", tmp_tbl), - stdnse.strjoin(",", tmp_tbl) - ) - end + keywords_filter = (" AND ( so.name IN (%s) or sc.name IN (%s) ) "):format( + stdnse.strjoin(",", tmp_tbl), + stdnse.strjoin(",", tmp_tbl) + ) + end - db_query = ("SELECT %s name from master..sysdatabases WHERE name NOT IN (%s)"):format(db_limit, stdnse.strjoin(",", exclude_dbs)) + db_query = ("SELECT %s name from master..sysdatabases WHERE name NOT IN (%s)"):format(db_limit, stdnse.strjoin(",", exclude_dbs)) - local creds = mssql.Helper.GetLoginCredentials_All( instance ) - if ( not creds ) then - output = "ERROR: No login credentials." - else - for username, password in pairs( creds ) do - local helper = mssql.Helper:new() - status, result = helper:ConnectEx( instance ) - if ( not(status) ) then - table.insert(output, "ERROR: " .. result) - break - end + local creds = mssql.Helper.GetLoginCredentials_All( instance ) + if ( not creds ) then + output = "ERROR: No login credentials." + else + for username, password in pairs( creds ) do + local helper = mssql.Helper:new() + status, result = helper:ConnectEx( instance ) + if ( not(status) ) then + table.insert(output, "ERROR: " .. result) + break + end - if ( status ) then - status = helper:Login( username, password, nil, instance.host.ip ) - end + if ( status ) then + status = helper:Login( username, password, nil, instance.host.ip ) + end - if ( status ) then - status, dbs = helper:Query( db_query ) - end + if ( status ) then + status, dbs = helper:Query( db_query ) + end - if ( status ) then - -- all done? - if ( #done_dbs == #dbs.rows ) then - break - end + if ( status ) then + -- all done? + if ( #done_dbs == #dbs.rows ) then + break + end - for k, v in pairs(dbs.rows) do - if ( not( stdnse.contains( done_dbs, v[1] ) ) ) then - local query = [[ SELECT so.name 'table', sc.name 'column', st.name 'type', sc.length - FROM %s..syscolumns sc, %s..sysobjects so, %s..systypes st - WHERE so.id = sc.id AND sc.xtype=st.xtype AND - so.id IN (SELECT %s id FROM %s..sysobjects WHERE xtype='U') %s ORDER BY so.name, sc.name, st.name]] - query = query:format( v[1], v[1], v[1], tbl_limit, v[1], keywords_filter) - status, tables = helper:Query( query ) - if ( not(status) ) then - stdnse.print_debug(tables) - else - local item = {} - item = mssql.Util.FormatOutputTable( tables, true ) - if ( #item == 0 and keywords_filter ~= "" ) then - table.insert(item, "Filter returned no matches") - end - item.name = v[1] + for k, v in pairs(dbs.rows) do + if ( not( stdnse.contains( done_dbs, v[1] ) ) ) then + local query = [[ SELECT so.name 'table', sc.name 'column', st.name 'type', sc.length + FROM %s..syscolumns sc, %s..sysobjects so, %s..systypes st + WHERE so.id = sc.id AND sc.xtype=st.xtype AND + so.id IN (SELECT %s id FROM %s..sysobjects WHERE xtype='U') %s ORDER BY so.name, sc.name, st.name]] + query = query:format( v[1], v[1], v[1], tbl_limit, v[1], keywords_filter) + status, tables = helper:Query( query ) + if ( not(status) ) then + stdnse.print_debug(tables) + else + local item = {} + item = mssql.Util.FormatOutputTable( tables, true ) + if ( #item == 0 and keywords_filter ~= "" ) then + table.insert(item, "Filter returned no matches") + end + item.name = v[1] - table.insert(output, item) - table.insert(done_dbs, v[1]) - end - end - end - end - helper:Disconnect() - end + table.insert(output, item) + table.insert(done_dbs, v[1]) + end + end + end + end + helper:Disconnect() + end - local pos = 1 - local restrict_tbl = {} + local pos = 1 + local restrict_tbl = {} - if ( stdnse.get_script_args( {'ms-sql-tables.keywords', 'mssql-tables.keywords' } ) ) then - local tmp = stdnse.get_script_args( {'ms-sql-tables.keywords', 'mssql-tables.keywords' } ) - if ( type(tmp) == 'table' ) then - tmp = stdnse.strjoin(',', tmp) - end - table.insert(restrict_tbl, 1, ("Filter: %s"):format(tmp)) - pos = pos + 1 - else - table.insert(restrict_tbl, 1, "No filter (see ms-sql-tables.keywords)") - end + if ( stdnse.get_script_args( {'ms-sql-tables.keywords', 'mssql-tables.keywords' } ) ) then + local tmp = stdnse.get_script_args( {'ms-sql-tables.keywords', 'mssql-tables.keywords' } ) + if ( type(tmp) == 'table' ) then + tmp = stdnse.strjoin(',', tmp) + end + table.insert(restrict_tbl, 1, ("Filter: %s"):format(tmp)) + pos = pos + 1 + else + table.insert(restrict_tbl, 1, "No filter (see ms-sql-tables.keywords)") + end - if ( DB_COUNT > 0 ) then - local tmp = ("Output restricted to %d databases"):format(DB_COUNT) - if ( not(stdnse.get_script_args( { 'ms-sql-tables.maxdb', 'mssql-tables.maxdb' } ) ) ) then - tmp = tmp .. " (see ms-sql-tables.maxdb)" - end - table.insert(restrict_tbl, 1, tmp) - pos = pos + 1 - end + if ( DB_COUNT > 0 ) then + local tmp = ("Output restricted to %d databases"):format(DB_COUNT) + if ( not(stdnse.get_script_args( { 'ms-sql-tables.maxdb', 'mssql-tables.maxdb' } ) ) ) then + tmp = tmp .. " (see ms-sql-tables.maxdb)" + end + table.insert(restrict_tbl, 1, tmp) + pos = pos + 1 + end - if ( TABLE_COUNT > 0 ) then - local tmp = ("Output restricted to %d tables"):format(TABLE_COUNT) - if ( not(stdnse.get_script_args( { 'ms-sql-tables.maxtables', 'mssql-tables.maxtables' } ) ) ) then - tmp = tmp .. " (see ms-sql-tables.maxtables)" - end - table.insert(restrict_tbl, 1, tmp) - pos = pos + 1 - end + if ( TABLE_COUNT > 0 ) then + local tmp = ("Output restricted to %d tables"):format(TABLE_COUNT) + if ( not(stdnse.get_script_args( { 'ms-sql-tables.maxtables', 'mssql-tables.maxtables' } ) ) ) then + tmp = tmp .. " (see ms-sql-tables.maxtables)" + end + table.insert(restrict_tbl, 1, tmp) + pos = pos + 1 + end - if ( 1 < pos and type( output ) == "table" and #output > 0) then - restrict_tbl.name = "Restrictions" - table.insert(output, "") - table.insert(output, restrict_tbl) - end - end + if ( 1 < pos and type( output ) == "table" and #output > 0) then + restrict_tbl.name = "Restrictions" + table.insert(output, "") + table.insert(output, restrict_tbl) + end + end - local instanceOutput = {} - instanceOutput["name"] = string.format( "[%s]", instance:GetName() ) - table.insert( instanceOutput, output ) + local instanceOutput = {} + instanceOutput["name"] = string.format( "[%s]", instance:GetName() ) + table.insert( instanceOutput, output ) - return instanceOutput + return instanceOutput end action = function( host, port ) - local scriptOutput = {} - local status, instanceList = mssql.Helper.GetTargetInstances( host, port ) + local scriptOutput = {} + local status, instanceList = mssql.Helper.GetTargetInstances( host, port ) - if ( not status ) then - return stdnse.format_output( false, instanceList ) - else - for _, instance in pairs( instanceList ) do - local instanceOutput = process_instance( instance ) - if instanceOutput then - table.insert( scriptOutput, instanceOutput ) - end - end - end + if ( not status ) then + return stdnse.format_output( false, instanceList ) + else + for _, instance in pairs( instanceList ) do + local instanceOutput = process_instance( instance ) + if instanceOutput then + table.insert( scriptOutput, instanceOutput ) + end + end + end - return stdnse.format_output( true, scriptOutput ) + return stdnse.format_output( true, scriptOutput ) end diff --git a/scripts/mysql-info.nse b/scripts/mysql-info.nse index 98440474a..b4b097796 100644 --- a/scripts/mysql-info.nse +++ b/scripts/mysql-info.nse @@ -40,169 +40,169 @@ end --@param num Start of the two bytes --@return The converted number local ntohs = function(num) - local b1 = bit.band(num:byte(1), 255) - local b2 = bit.band(num:byte(2), 255) + local b1 = bit.band(num:byte(1), 255) + local b2 = bit.band(num:byte(2), 255) - return bit.bor(b1, bit.lshift(b2, 8)) + return bit.bor(b1, bit.lshift(b2, 8)) end --- Converts three bytes into a number --@param num Start of the three bytes --@return The converted number local ntoh3 = function(num) - local b1 = bit.band(num:byte(1), 255) - local b2 = bit.band(num:byte(2), 255) - local b3 = bit.band(num:byte(3), 255) + local b1 = bit.band(num:byte(1), 255) + local b2 = bit.band(num:byte(2), 255) + local b3 = bit.band(num:byte(3), 255) - return bit.bor(b1, bit.lshift(b2, 8), bit.lshift(b3, 16)) + return bit.bor(b1, bit.lshift(b2, 8), bit.lshift(b3, 16)) end --- Converts four bytes into a number --@param num Start of the four bytes --@return The converted number local ntohl = function(num) - local b1 = bit.band(num:byte(1), 255) - local b2 = bit.band(num:byte(2), 255) - local b3 = bit.band(num:byte(3), 255) - local b4 = bit.band(num:byte(4), 255) + local b1 = bit.band(num:byte(1), 255) + local b2 = bit.band(num:byte(2), 255) + local b3 = bit.band(num:byte(3), 255) + local b4 = bit.band(num:byte(4), 255) - return bit.bor(b1, bit.lshift(b2, 8), bit.lshift(b3, 16), bit.lshift(b4, 24)) + return bit.bor(b1, bit.lshift(b2, 8), bit.lshift(b3, 16), bit.lshift(b4, 24)) end --- Converts a number to a string description of the capabilities --@param num Start of the capabilities data --@return String describing the capabilities offered local capabilities = function(num) - local caps = "" + local caps = "" - if bit.band(num, 1) > 0 then - caps = caps .. "Long Passwords, " - end + if bit.band(num, 1) > 0 then + caps = caps .. "Long Passwords, " + end - if bit.band(num, 8) > 0 then - caps = caps .. "Connect with DB, " - end + if bit.band(num, 8) > 0 then + caps = caps .. "Connect with DB, " + end - if bit.band(num, 32) > 0 then - caps = caps .. "Compress, " - end + if bit.band(num, 32) > 0 then + caps = caps .. "Compress, " + end - if bit.band(num, 64) > 0 then - caps = caps .. "ODBC, " - end + if bit.band(num, 64) > 0 then + caps = caps .. "ODBC, " + end - if bit.band(num, 2048) > 0 then - caps = caps .. "SSL, " - end + if bit.band(num, 2048) > 0 then + caps = caps .. "SSL, " + end - if bit.band(num, 8192) > 0 then - caps = caps .. "Transactions, " - end + if bit.band(num, 8192) > 0 then + caps = caps .. "Transactions, " + end - if bit.band(num, 32768) > 0 then - caps = caps .. "Secure Connection, " - end + if bit.band(num, 32768) > 0 then + caps = caps .. "Secure Connection, " + end - return caps:gsub(", $", "") + return caps:gsub(", $", "") end portrule = function(host, port) - local extra = port.version.extrainfo + local extra = port.version.extrainfo - return (port.number == 3306 or port.service == "mysql") - and port.protocol == "tcp" - and port.state == "open" - and not (extra ~= nil - and (extra:match("[Uu]nauthorized") - or extra:match("[Tt]oo many connection"))) + return (port.number == 3306 or port.service == "mysql") + and port.protocol == "tcp" + and port.state == "open" + and not (extra ~= nil + and (extra:match("[Uu]nauthorized") + or extra:match("[Tt]oo many connection"))) end action = function(host, port) - local output = "" + local output = "" - local status, response = comm.get_banner(host, port, {timeout=5000}) + local status, response = comm.get_banner(host, port, {timeout=5000}) - if not status then - return - end + if not status then + return + end - local length = ntoh3(response:sub(1, 3)) + local length = ntoh3(response:sub(1, 3)) - if length ~= response:len() - 4 then - return "Invalid greeting (Not MySQL?)" - end + if length ~= response:len() - 4 then + return "Invalid greeting (Not MySQL?)" + end - -- Keeps track of where we are in the binary data - local offset = 1 + 4 + -- Keeps track of where we are in the binary data + local offset = 1 + 4 - local protocol = response:byte(offset) + local protocol = response:byte(offset) - offset = offset + 1 + offset = offset + 1 - -- If a 0xff is here instead of the protocol, an error occurred. - -- Pass it along to the user.. - if (protocol == 255) then - output = "MySQL Error detected!\n" + -- If a 0xff is here instead of the protocol, an error occurred. + -- Pass it along to the user.. + if (protocol == 255) then + output = "MySQL Error detected!\n" - local sqlerrno = ntohs(response:sub(offset, offset + 2)) + local sqlerrno = ntohs(response:sub(offset, offset + 2)) - offset = offset + 2 + offset = offset + 2 - local sqlerrstr = response:sub(offset) + local sqlerrstr = response:sub(offset) - output = output .. "Error Code was: " .. sqlerrno .. "\n" + output = output .. "Error Code was: " .. sqlerrno .. "\n" - output = output .. sqlerrstr + output = output .. sqlerrstr - return output - end + return output + end - local version = getstring(response:sub(offset)) + local version = getstring(response:sub(offset)) - offset = offset + version:len() + 1 + offset = offset + version:len() + 1 - local threadid = ntohl(response:sub(offset, offset + 4)) + local threadid = ntohl(response:sub(offset, offset + 4)) - offset = offset + 4 + offset = offset + 4 - local salt = getstring(response:sub(offset)) + local salt = getstring(response:sub(offset)) - offset = offset + salt:len() + 1 + offset = offset + salt:len() + 1 - local caps = capabilities(ntohs(response:sub(offset, offset + 2))) + local caps = capabilities(ntohs(response:sub(offset, offset + 2))) - offset = offset + 2 + offset = offset + 2 - offset = offset + 1 + offset = offset + 1 - local status = "" + local status = "" - if ntohs(response:sub(offset, offset + 2)) == 2 then - status = "Autocommit" - end + if ntohs(response:sub(offset, offset + 2)) == 2 then + status = "Autocommit" + end - offset = offset + 2 + offset = offset + 2 - offset = offset + 13 -- unused + offset = offset + 13 -- unused - if response:len() - offset + 1 == 13 then - salt = salt .. getstring(response:sub(offset)) - end + if response:len() - offset + 1 == 13 then + salt = salt .. getstring(response:sub(offset)) + end - output = output .. "Protocol: " .. protocol .. "\n" - output = output .. "Version: " .. version .. "\n" - output = output .. "Thread ID: " .. threadid .. "\n" + output = output .. "Protocol: " .. protocol .. "\n" + output = output .. "Version: " .. version .. "\n" + output = output .. "Thread ID: " .. threadid .. "\n" - if caps:len() > 0 then - output = output .. "Some Capabilities: " .. caps .. "\n" - end + if caps:len() > 0 then + output = output .. "Some Capabilities: " .. caps .. "\n" + end - if status:len() > 0 then - output = output .. "Status: " .. status .. "\n" - end + if status:len() > 0 then + output = output .. "Status: " .. status .. "\n" + end - output = output .. "Salt: " .. salt .. "\n" + output = output .. "Salt: " .. salt .. "\n" - return output + return output end diff --git a/scripts/nbstat.nse b/scripts/nbstat.nse index b1f61326d..244f7269d 100644 --- a/scripts/nbstat.nse +++ b/scripts/nbstat.nse @@ -87,155 +87,155 @@ categories = {"default", "discovery", "safe"} hostrule = function(host) - -- The following is an attempt to only run this script against hosts - -- that will probably respond to a UDP 137 probe. One might argue - -- that sending a single UDP packet and waiting for a response is no - -- big deal and that it should be done for every host. In that case - -- simply change this rule to always return true. + -- The following is an attempt to only run this script against hosts + -- that will probably respond to a UDP 137 probe. One might argue + -- that sending a single UDP packet and waiting for a response is no + -- big deal and that it should be done for every host. In that case + -- simply change this rule to always return true. - local port_t135 = nmap.get_port_state(host, - {number=135, protocol="tcp"}) - local port_t139 = nmap.get_port_state(host, - {number=139, protocol="tcp"}) - local port_t445 = nmap.get_port_state(host, - {number=445, protocol="tcp"}) - local port_u137 = nmap.get_port_state(host, - {number=137, protocol="udp"}) + local port_t135 = nmap.get_port_state(host, + {number=135, protocol="tcp"}) + local port_t139 = nmap.get_port_state(host, + {number=139, protocol="tcp"}) + local port_t445 = nmap.get_port_state(host, + {number=445, protocol="tcp"}) + local port_u137 = nmap.get_port_state(host, + {number=137, protocol="udp"}) - return (port_t135 ~= nil and port_t135.state == "open") or - (port_t139 ~= nil and port_t139.state == "open") or - (port_t445 ~= nil and port_t445.state == "open") or - (port_u137 ~= nil and - (port_u137.state == "open" or - port_u137.state == "open|filtered")) + return (port_t135 ~= nil and port_t135.state == "open") or + (port_t139 ~= nil and port_t139.state == "open") or + (port_t445 ~= nil and port_t445.state == "open") or + (port_u137 ~= nil and + (port_u137.state == "open" or + port_u137.state == "open|filtered")) end action = function(host) - local i - local status - local names, statistics - local server_name, user_name - local mac, prefix, manuf - local response = {} - local catch = function() return end - local try = nmap.new_try(catch) + local i + local status + local names, statistics + local server_name, user_name + local mac, prefix, manuf + local response = {} + local catch = function() return end + local try = nmap.new_try(catch) - -- Get the list of NetBIOS names - status, names, statistics = netbios.do_nbstat(host) - status, names, statistics = netbios.do_nbstat(host) - status, names, statistics = netbios.do_nbstat(host) - status, names, statistics = netbios.do_nbstat(host) - if(status == false) then - return stdnse.format_output(false, names) - end + -- Get the list of NetBIOS names + status, names, statistics = netbios.do_nbstat(host) + status, names, statistics = netbios.do_nbstat(host) + status, names, statistics = netbios.do_nbstat(host) + status, names, statistics = netbios.do_nbstat(host) + if(status == false) then + return stdnse.format_output(false, names) + end - -- Get the server name - status, server_name = netbios.get_server_name(host, names) - if(status == false) then - return stdnse.format_output(false, server_name) - end + -- Get the server name + status, server_name = netbios.get_server_name(host, names) + if(status == false) then + return stdnse.format_output(false, server_name) + end - -- Get the logged in user - status, user_name = netbios.get_user_name(host, names) - if(status == false) then - return stdnse.format_output(false, user_name) - end + -- Get the logged in user + status, user_name = netbios.get_user_name(host, names) + if(status == false) then + return stdnse.format_output(false, user_name) + end local mac_prefixes = try(datafiles.parse_mac_prefixes()) - -- Format the Mac address in the standard way - if(#statistics >= 6) then - -- MAC prefixes are matched on the first three bytes, all uppercase - prefix = string.upper(string.format("%02x%02x%02x", statistics:byte(1), statistics:byte(2), statistics:byte(3))) - mac = { - address = ("%02x:%02x:%02x:%02x:%02x:%02x"):format( statistics:byte(1), statistics:byte(2), statistics:byte(3), statistics:byte(4), statistics:byte(5), statistics:byte(6) ), - manuf = mac_prefixes[prefix] or "unknown" - } - host.registry['nbstat'] = { - server_name = server_name, - mac = mac.address - } - -- Samba doesn't set the Mac address, and nmap-mac-prefixes shows that as Xerox - if(mac.address == "00:00:00:00:00:00") then - mac.address = "" - mac.manuf = "unknown" - end - else - mac = { - address = "", - manuf = "unknown" - } - end - setmetatable(mac, { - -- MAC is formatted as "00:11:22:33:44:55 (Manufacturer)" - __tostring=function(t) return string.format("%s (%s)", t.address, t.manuf) end - }) + -- Format the Mac address in the standard way + if(#statistics >= 6) then + -- MAC prefixes are matched on the first three bytes, all uppercase + prefix = string.upper(string.format("%02x%02x%02x", statistics:byte(1), statistics:byte(2), statistics:byte(3))) + mac = { + address = ("%02x:%02x:%02x:%02x:%02x:%02x"):format( statistics:byte(1), statistics:byte(2), statistics:byte(3), statistics:byte(4), statistics:byte(5), statistics:byte(6) ), + manuf = mac_prefixes[prefix] or "unknown" + } + host.registry['nbstat'] = { + server_name = server_name, + mac = mac.address + } + -- Samba doesn't set the Mac address, and nmap-mac-prefixes shows that as Xerox + if(mac.address == "00:00:00:00:00:00") then + mac.address = "" + mac.manuf = "unknown" + end + else + mac = { + address = "", + manuf = "unknown" + } + end + setmetatable(mac, { + -- MAC is formatted as "00:11:22:33:44:55 (Manufacturer)" + __tostring=function(t) return string.format("%s (%s)", t.address, t.manuf) end + }) - -- Check if we actually got a username - if(user_name == nil) then - user_name = "" - end + -- Check if we actually got a username + if(user_name == nil) then + user_name = "" + end - response["server_name"] = server_name - response["user"] = user_name - response["mac"] = mac + response["server_name"] = server_name + response["user"] = user_name + response["mac"] = mac - local names_output = {} - for i = 1, #names, 1 do - local name = names[i] - setmetatable(name, { - __tostring = function(t) - -- Tabular format with padding - return string.format("%s<%02x>%sFlags: %s", - t['name'], t['suffix'], - string.rep(" ", 17 - #t['name']), - netbios.flags_to_string(t['flags'])) - end - }) - table.insert(names_output, name) - end - setmetatable(names_output, { - __tostring = function(t) - local ret = {} - for i,v in ipairs(t) do - table.insert(ret, tostring(v)) - end - -- Indent Names table by 2 spaces - return " " .. table.concat(ret, "\n ") - end - }) + local names_output = {} + for i = 1, #names, 1 do + local name = names[i] + setmetatable(name, { + __tostring = function(t) + -- Tabular format with padding + return string.format("%s<%02x>%sFlags: %s", + t['name'], t['suffix'], + string.rep(" ", 17 - #t['name']), + netbios.flags_to_string(t['flags'])) + end + }) + table.insert(names_output, name) + end + setmetatable(names_output, { + __tostring = function(t) + local ret = {} + for i,v in ipairs(t) do + table.insert(ret, tostring(v)) + end + -- Indent Names table by 2 spaces + return " " .. table.concat(ret, "\n ") + end + }) - response["names"] = names_output + response["names"] = names_output - local statistics_output = {} - for i = 1, #statistics, 16 do - --Format statistics as space-separated hex bytes, 16 columns - table.insert(statistics_output, - stdnse.tohex(string.sub(statistics,i,i+16), {separator = " "}) - ) - end - response["statistics"] = statistics_output + local statistics_output = {} + for i = 1, #statistics, 16 do + --Format statistics as space-separated hex bytes, 16 columns + table.insert(statistics_output, + stdnse.tohex(string.sub(statistics,i,i+16), {separator = " "}) + ) + end + response["statistics"] = statistics_output - setmetatable(response, { - __tostring = function(t) - -- Normal single-line result - local ret = {string.format("NetBIOS name: %s, NetBIOS user: %s, NetBIOS MAC: %s", t.server_name, t.user, t.mac)} - -- If verbosity is set, dump the whole list of names - if nmap.verbosity() >= 1 then - table.insert(ret, string.format("Names:\n%s",t.names)) - -- If super verbosity is set, print out the full statistics - if nmap.verbosity() >= 2 then - -- Indent Statistics table by 2 spaces - table.insert(ret, string.format("Statistics:\n %s",table.concat(t.statistics,"\n "))) - end - end - return table.concat(ret, "\n") - end - }) + setmetatable(response, { + __tostring = function(t) + -- Normal single-line result + local ret = {string.format("NetBIOS name: %s, NetBIOS user: %s, NetBIOS MAC: %s", t.server_name, t.user, t.mac)} + -- If verbosity is set, dump the whole list of names + if nmap.verbosity() >= 1 then + table.insert(ret, string.format("Names:\n%s",t.names)) + -- If super verbosity is set, print out the full statistics + if nmap.verbosity() >= 2 then + -- Indent Statistics table by 2 spaces + table.insert(ret, string.format("Statistics:\n %s",table.concat(t.statistics,"\n "))) + end + end + return table.concat(ret, "\n") + end + }) - return response + return response end diff --git a/scripts/nrpe-enum.nse b/scripts/nrpe-enum.nse index c058ca97e..5cf158dff 100644 --- a/scripts/nrpe-enum.nse +++ b/scripts/nrpe-enum.nse @@ -39,214 +39,214 @@ categories = {"discovery", "intrusive"} local NRPE_PROTOCOLS = { - "ssl", - "tcp" + "ssl", + "tcp" } local NRPE_STATES = { - [0] = "OK", - [1] = "WARNING", - [2] ="CRITICAL", - [3] = "UNKNOWN" + [0] = "OK", + [1] = "WARNING", + [2] ="CRITICAL", + [3] = "UNKNOWN" } local NRPE_COMMANDS = { - "check_hda1", - "check_load", - "check_total_procs", - "check_users", - "check_zombie_procs" + "check_hda1", + "check_load", + "check_total_procs", + "check_users", + "check_zombie_procs" } local CRC32_CONSTANTS = { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, - 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, - 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, - 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, - 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, - 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, - 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, - 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, - 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, - 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, - 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, - 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, - 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, - 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, - 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, - 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, - 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, - 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, - 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, - 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, - 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, - 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, - 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, - 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, - 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, - 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, - 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, + 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, + 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, + 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, + 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, + 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, + 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, + 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, + 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, + 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, + 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D } local crc32 = function(s) - local crc = 0xFFFFFFFF - for i = 1, #s do - local p1 = s:byte(i) - local p2 = bit.bxor(crc, p1) - local p3 = bit.band(p2, 0xFF) - local p4 = bit.band(p3) - local p5 = CRC32_CONSTANTS[p4 + 1] - local p6 = bit.rshift(crc, 8) + local crc = 0xFFFFFFFF + for i = 1, #s do + local p1 = s:byte(i) + local p2 = bit.bxor(crc, p1) + local p3 = bit.band(p2, 0xFF) + local p4 = bit.band(p3) + local p5 = CRC32_CONSTANTS[p4 + 1] + local p6 = bit.rshift(crc, 8) - crc = bit.bxor(p6, p5) - end + crc = bit.bxor(p6, p5) + end - return bit.bxor(crc, 0xFFFFFFFF) + return bit.bxor(crc, 0xFFFFFFFF) end local nrpe_open = function(host, port) - for _, proto in pairs(NRPE_PROTOCOLS) do - local sock = nmap.new_socket() - sock:set_timeout(2000) - local status, err = sock:connect(host, port, proto) - if status then - NRPE_PROTOCOLS = {proto} - return true, sock - end + for _, proto in pairs(NRPE_PROTOCOLS) do + local sock = nmap.new_socket() + sock:set_timeout(2000) + local status, err = sock:connect(host, port, proto) + if status then + NRPE_PROTOCOLS = {proto} + return true, sock + end - stdnse.print_debug(2, "Can't connect using %s: %s", proto, err) - sock:close() - end + stdnse.print_debug(2, "Can't connect using %s: %s", proto, err) + sock:close() + end - return false, nil + return false, nil end local nrpe_write = function(cmd) - -- Create request packet, before checksum. - local pkt = "" - pkt = pkt .. bin.pack(">S", 2) - pkt = pkt .. bin.pack(">S", 1) - pkt = pkt .. bin.pack(">I", 0) - pkt = pkt .. bin.pack(">S", 0) - pkt = pkt .. bin.pack("A", cmd) - pkt = pkt .. string.char(0x00):rep(1024 - #cmd) - pkt = pkt .. bin.pack(">S", 0) + -- Create request packet, before checksum. + local pkt = "" + pkt = pkt .. bin.pack(">S", 2) + pkt = pkt .. bin.pack(">S", 1) + pkt = pkt .. bin.pack(">I", 0) + pkt = pkt .. bin.pack(">S", 0) + pkt = pkt .. bin.pack("A", cmd) + pkt = pkt .. string.char(0x00):rep(1024 - #cmd) + pkt = pkt .. bin.pack(">S", 0) - -- Calculate the checksum, and insert it into the packet. - pkt = bin.pack( - "A>IA", - string.char(pkt:byte(1, 4)), - crc32(pkt), - string.char(pkt:byte(9, #pkt)) - ) + -- Calculate the checksum, and insert it into the packet. + pkt = bin.pack( + "A>IA", + string.char(pkt:byte(1, 4)), + crc32(pkt), + string.char(pkt:byte(9, #pkt)) + ) - return pkt + return pkt end local nrpe_read = function(pkt) - local i - local result = {} + local i + local result = {} - -- Parse packet. - i, result.version = bin.unpack(">S", pkt, i) - i, result.type = bin.unpack(">S", pkt, i) - i, result.crc32 = bin.unpack(">I", pkt, i) - i, result.state = bin.unpack(">S", pkt, i) - i, result.data = bin.unpack("z", pkt, i) + -- Parse packet. + i, result.version = bin.unpack(">S", pkt, i) + i, result.type = bin.unpack(">S", pkt, i) + i, result.crc32 = bin.unpack(">I", pkt, i) + i, result.state = bin.unpack(">S", pkt, i) + i, result.data = bin.unpack("z", pkt, i) - return result + return result end local nrpe_check = function(host, port, cmd) - -- Create connection. - local status, sock = nrpe_open(host, port) - if not status then - return false, nil - end + -- Create connection. + local status, sock = nrpe_open(host, port) + if not status then + return false, nil + end - -- Send query. - local status, err = sock:send(nrpe_write(cmd)) - if not status then - stdnse.print_debug(1, "Failed to send NRPE query for command %s: %s", cmd, err) - sock:close() - return false, nil - end + -- Send query. + local status, err = sock:send(nrpe_write(cmd)) + if not status then + stdnse.print_debug(1, "Failed to send NRPE query for command %s: %s", cmd, err) + sock:close() + return false, nil + end - -- Receive response. - local status, resp = sock:receive() - if not status then - stdnse.print_debug(1, "Can't read NRPE response: %s", resp) - sock:close() - return false, nil - end + -- Receive response. + local status, resp = sock:receive() + if not status then + stdnse.print_debug(1, "Can't read NRPE response: %s", resp) + sock:close() + return false, nil + end - sock:close() + sock:close() - return true, nrpe_read(resp) + return true, nrpe_read(resp) end portrule = shortport.port_or_service(5666, "nrpe") action = function(host, port) - -- Get script arguments. - local cmds = stdnse.get_script_args("nrpe-enum.cmds") - if cmds then - cmds = stdnse.strsplit(":", cmds) - else - cmds = NRPE_COMMANDS - end + -- Get script arguments. + local cmds = stdnse.get_script_args("nrpe-enum.cmds") + if cmds then + cmds = stdnse.strsplit(":", cmds) + else + cmds = NRPE_COMMANDS + end - -- Create results table. - local results = tab.new() - tab.addrow( - results, - "Command", - "State", - "Response" - ) + -- Create results table. + local results = tab.new() + tab.addrow( + results, + "Command", + "State", + "Response" + ) - -- Try each NRPE command, and collect the results. - for _, cmd in pairs(cmds) do - local status, result = nrpe_check(host, port, cmd) - if status then - tab.addrow( - results, - cmd, - NRPE_STATES[result.state], - result.data - ) - end - end + -- Try each NRPE command, and collect the results. + for _, cmd in pairs(cmds) do + local status, result = nrpe_check(host, port, cmd) + if status then + tab.addrow( + results, + cmd, + NRPE_STATES[result.state], + result.data + ) + end + end - -- If no queries generated responses, don't output anything. - if #results == 1 then - return - end + -- If no queries generated responses, don't output anything. + if #results == 1 then + return + end - -- Record service description. - port.version.name = "nrpe" - port.version.product = "Nagios Remote Plugin Executor" - nmap.set_port_version(host, port) + -- Record service description. + port.version.name = "nrpe" + port.version.product = "Nagios Remote Plugin Executor" + nmap.set_port_version(host, port) - -- Format table, without trailing newline. - results = tab.dump(results) - results = results:sub(1, #results - 1) + -- Format table, without trailing newline. + results = tab.dump(results) + results = results:sub(1, #results - 1) - return "\n" .. results + return "\n" .. results end diff --git a/scripts/openlookup-info.nse b/scripts/openlookup-info.nse index 0a57ce5d0..e936babf1 100644 --- a/scripts/openlookup-info.nse +++ b/scripts/openlookup-info.nse @@ -35,23 +35,23 @@ portrule = shortport.port_or_service(5850, "openlookup") -- parses a Netstring element local function parsechunk(data) - local parts = stdnse.strsplit(":", data) - if #parts < 2 then - return nil, data - end - local head = table.remove(parts, 1) - local size = tonumber(head) - if not size then - return nil, data - end - local body = stdnse.strjoin(":", parts) - if #body < size then - return nil, data - end - local chunk = string.sub(body, 1, size) - local skip = #chunk + string.len(",") - local rest = string.sub(body, skip + 1) - return chunk, rest + local parts = stdnse.strsplit(":", data) + if #parts < 2 then + return nil, data + end + local head = table.remove(parts, 1) + local size = tonumber(head) + if not size then + return nil, data + end + local body = stdnse.strjoin(":", parts) + if #body < size then + return nil, data + end + local chunk = string.sub(body, 1, size) + local skip = #chunk + string.len(",") + local rest = string.sub(body, skip + 1) + return chunk, rest end -- NSON helpers @@ -59,203 +59,203 @@ end -- parses an NSON int local function parseint(data) - if string.sub(data, 1, 1) ~= "i" then - return - end - local text = string.sub(data, 2) - local number = tonumber(text) - return number + if string.sub(data, 1, 1) ~= "i" then + return + end + local text = string.sub(data, 2) + local number = tonumber(text) + return number end -- parses an NSON float local function parsefloat(data) - if string.sub(data, 1, 1) ~= "f" then - return - end - local text = string.sub(data, 2) - local number = tonumber(text) - return number + if string.sub(data, 1, 1) ~= "f" then + return + end + local text = string.sub(data, 2) + local number = tonumber(text) + return number end -- parses an NSON string local function parsestring(data) - if string.sub(data, 1, 1) ~= "s" then - return - end - return string.sub(data, 2) + if string.sub(data, 1, 1) ~= "s" then + return + end + return string.sub(data, 2) end -- parses an NSON int, float, or string local function parsesimple(data) - local i = parseint(data) - local f = parsefloat(data) - local s = parsestring(data) - return i or f or s + local i = parseint(data) + local f = parsefloat(data) + local s = parsestring(data) + return i or f or s end -- parses an NSON dictionary local function parsedict(data) - if #data < 1 then - return - end - if string.sub(data, 1, 1) ~= "d" then - return - end - local rest = string.sub(data, 2) - local dict = {} - while #rest > 0 do - local chunk, key, value - chunk, rest = parsechunk(rest) - if not chunk then - return - end - key = parsestring(chunk) - value, rest = parsechunk(rest) - if not value then - return - end - dict[key] = value - end - return dict + if #data < 1 then + return + end + if string.sub(data, 1, 1) ~= "d" then + return + end + local rest = string.sub(data, 2) + local dict = {} + while #rest > 0 do + local chunk, key, value + chunk, rest = parsechunk(rest) + if not chunk then + return + end + key = parsestring(chunk) + value, rest = parsechunk(rest) + if not value then + return + end + dict[key] = value + end + return dict end -- parses an NSON array local function parsearray(data) - if #data < 1 then - return - end - if string.sub(data, 1, 1) ~= "a" then - return - end - local rest = string.sub(data, 2) - local array = {} - while #rest > 0 do - local value - value, rest = parsechunk(rest) - if not value then - return - end - table.insert(array, value) - end - return array + if #data < 1 then + return + end + if string.sub(data, 1, 1) ~= "a" then + return + end + local rest = string.sub(data, 2) + local array = {} + while #rest > 0 do + local value + value, rest = parsechunk(rest) + if not value then + return + end + table.insert(array, value) + end + return array end -- OpenLookup specific stuff local function formataddress(data) - local parts = parsearray(data) - if not parts then - return - end - if #parts < 2 then - return - end - local ip = parsestring(parts[1]) - if not ip then - return - end - local port = parseint(parts[2]) - if not port then - return - end - return ip .. ":" .. port + local parts = parsearray(data) + if not parts then + return + end + if #parts < 2 then + return + end + local ip = parsestring(parts[1]) + if not ip then + return + end + local port = parseint(parts[2]) + if not port then + return + end + return ip .. ":" .. port end local function formattime(data) - local time = parsefloat(data) - if not time then - return - end - local human = stdnse.format_timestamp(time) - return time .. " (" .. human .. ")" + local time = parsefloat(data) + if not time then + return + end + local human = stdnse.format_timestamp(time) + return time .. " (" .. human .. ")" end local function formatkey(key) - local parts = stdnse.strsplit("_", key) - return stdnse.strjoin(" ", parts) + local parts = stdnse.strsplit("_", key) + return stdnse.strjoin(" ", parts) end local function formatvalue(key, nson) - local value - if key == "your_address" then - value = formataddress(nson) - elseif key == "timestamp" then - value = formattime(nson) - else - value = parsesimple(nson) - end - if not value then - value = "<" .. #nson .. "B of data>" - end - return value + local value + if key == "your_address" then + value = formataddress(nson) + elseif key == "timestamp" then + value = formattime(nson) + else + value = parsesimple(nson) + end + if not value then + value = "<" .. #nson .. "B of data>" + end + return value end local function format(rawkey, nson) - local key = formatkey(rawkey) - local value = formatvalue(rawkey, nson) - return key .. ": " .. value + local key = formatkey(rawkey) + local value = formatvalue(rawkey, nson) + return key .. ": " .. value end function formatoptions(header) - local msg = parsedict(header) - if not msg then - return - end - local rawmeth = msg["method"] - if not rawmeth then - stdnse.print_debug(2, "header missing method field") - return - end - local method = parsestring(rawmeth) - if not method then - return - end - if method ~= "hello" then - stdnse.print_debug(1, "expecting hello, got " .. method .. " instead") - return - end - local rawopts = msg["options"] - if not rawopts then - return {} - end - local options = parsedict(rawopts) - if not options then - return - end - local formatted = {} - for key, nson in pairs(options) do - local tmp = format(key, nson) - if tmp then - table.insert(formatted, tmp) - end - end - return formatted + local msg = parsedict(header) + if not msg then + return + end + local rawmeth = msg["method"] + if not rawmeth then + stdnse.print_debug(2, "header missing method field") + return + end + local method = parsestring(rawmeth) + if not method then + return + end + if method ~= "hello" then + stdnse.print_debug(1, "expecting hello, got " .. method .. " instead") + return + end + local rawopts = msg["options"] + if not rawopts then + return {} + end + local options = parsedict(rawopts) + if not options then + return + end + local formatted = {} + for key, nson in pairs(options) do + local tmp = format(key, nson) + if tmp then + table.insert(formatted, tmp) + end + end + return formatted end action = function(host, port) - local status, banner = comm.get_banner(host, port) - if not status then - return - end - local header, _ = parsechunk(banner) - if not header then - return - end - local options = formatoptions(header) - if not options then - return - end - port.version.name = "openlookup" - local version = options["version"] - if version then - port.version.version = version - end - nmap.set_port_version(host, port) - if #options < 1 then - return - end - local response = {} - table.insert(response, options) - return stdnse.format_output(true, response) + local status, banner = comm.get_banner(host, port) + if not status then + return + end + local header, _ = parsechunk(banner) + if not header then + return + end + local options = formatoptions(header) + if not options then + return + end + port.version.name = "openlookup" + local version = options["version"] + if version then + port.version.version = version + end + nmap.set_port_version(host, port) + if #options < 1 then + return + end + local response = {} + table.insert(response, options) + return stdnse.format_output(true, response) end diff --git a/scripts/oracle-brute-stealth.nse b/scripts/oracle-brute-stealth.nse index 63e1539ee..fbb503e55 100644 --- a/scripts/oracle-brute-stealth.nse +++ b/scripts/oracle-brute-stealth.nse @@ -63,141 +63,141 @@ local johnfile Driver = { - new = function(self, host, port, sid ) - local o = { host = host, port = port, sid = sid } - setmetatable(o, self) - self.__index = self - return o - end, + new = function(self, host, port, sid ) + local o = { host = host, port = port, sid = sid } + setmetatable(o, self) + self.__index = self + return o + end, - --- Connects performs protocol negotiation - -- - -- @return true on success, false on failure - connect = function( self ) - local MAX_RETRIES = 10 - local tries = MAX_RETRIES + --- Connects performs protocol negotiation + -- + -- @return true on success, false on failure + connect = function( self ) + local MAX_RETRIES = 10 + local tries = MAX_RETRIES - self.helper = ConnectionPool[coroutine.running()] - if ( self.helper ) then return true end + self.helper = ConnectionPool[coroutine.running()] + if ( self.helper ) then return true end - self.helper = tns.Helper:new( self.host, self.port, self.sid ) + self.helper = tns.Helper:new( self.host, self.port, self.sid ) - -- This loop is intended for handling failed connections - -- A connection may fail for a number of different reasons. - -- For the moment, we're just handling the error code 12520 - -- - -- Error 12520 has been observed on Oracle XE and seems to - -- occur when a maximum connection count is reached. - local status, data - repeat - if ( tries < MAX_RETRIES ) then - stdnse.print_debug(2, "%s: Attempting to re-connect (attempt %d of %d)", SCRIPT_NAME, MAX_RETRIES - tries, MAX_RETRIES) - end - status, data = self.helper:Connect() - if ( not(status) ) then - stdnse.print_debug(2, "%s: ERROR: An Oracle %s error occured", SCRIPT_NAME, data) - self.helper:Close() - else - break - end - tries = tries - 1 - stdnse.sleep(1) - until( tries == 0 or data ~= "12520" ) + -- This loop is intended for handling failed connections + -- A connection may fail for a number of different reasons. + -- For the moment, we're just handling the error code 12520 + -- + -- Error 12520 has been observed on Oracle XE and seems to + -- occur when a maximum connection count is reached. + local status, data + repeat + if ( tries < MAX_RETRIES ) then + stdnse.print_debug(2, "%s: Attempting to re-connect (attempt %d of %d)", SCRIPT_NAME, MAX_RETRIES - tries, MAX_RETRIES) + end + status, data = self.helper:Connect() + if ( not(status) ) then + stdnse.print_debug(2, "%s: ERROR: An Oracle %s error occured", SCRIPT_NAME, data) + self.helper:Close() + else + break + end + tries = tries - 1 + stdnse.sleep(1) + until( tries == 0 or data ~= "12520" ) - if ( status ) then - ConnectionPool[coroutine.running()] = self.helper - end + if ( status ) then + ConnectionPool[coroutine.running()] = self.helper + end - return status, data - end, + return status, data + end, - --- Attempts to login to the Oracle server - -- - -- @param username string containing the login username - -- @param password string containing the login password - -- @return status, true on success, false on failure - -- @return brute.Error object on failure - -- brute.Account object on success - login = function( self, username, password ) - local status, data = self.helper:StealthLogin( username, password ) + --- Attempts to login to the Oracle server + -- + -- @param username string containing the login username + -- @param password string containing the login password + -- @return status, true on success, false on failure + -- @return brute.Error object on failure + -- brute.Account object on success + login = function( self, username, password ) + local status, data = self.helper:StealthLogin( username, password ) - if ( data["AUTH_VFR_DATA"] ) then - local hash = string.format("$o5logon$%s*%s", data["AUTH_SESSKEY"], data["AUTH_VFR_DATA"]) - if ( johnfile ) then - johnfile:write(("%s:%s\n"):format(username,hash)) - end - return true, brute.Account:new(username, hash, creds.State.HASHED) - else - return false, brute.Error:new( data ) - end + if ( data["AUTH_VFR_DATA"] ) then + local hash = string.format("$o5logon$%s*%s", data["AUTH_SESSKEY"], data["AUTH_VFR_DATA"]) + if ( johnfile ) then + johnfile:write(("%s:%s\n"):format(username,hash)) + end + return true, brute.Account:new(username, hash, creds.State.HASHED) + else + return false, brute.Error:new( data ) + end - end, + end, - --- Disconnects and terminates the Oracle TNS communication - disconnect = function( self ) - return true - end, + --- Disconnects and terminates the Oracle TNS communication + disconnect = function( self ) + return true + end, } action = function(host, port) - local DEFAULT_ACCOUNTS = "nselib/data/oracle-default-accounts.lst" - local sid = stdnse.get_script_args(SCRIPT_NAME .. '.sid') or stdnse.get_script_args('tns.sid') - local engine = brute.Engine:new(Driver, host, port, sid) - local arg_accounts = stdnse.get_script_args(SCRIPT_NAME .. '.accounts') - local mode = arg_accounts and "accounts" or "default" + local DEFAULT_ACCOUNTS = "nselib/data/oracle-default-accounts.lst" + local sid = stdnse.get_script_args(SCRIPT_NAME .. '.sid') or stdnse.get_script_args('tns.sid') + local engine = brute.Engine:new(Driver, host, port, sid) + local arg_accounts = stdnse.get_script_args(SCRIPT_NAME .. '.accounts') + local mode = arg_accounts and "accounts" or "default" - if ( not(sid) ) then - return "\n ERROR: Oracle instance not set (see oracle-brute-stealth.sid or tns.sid)" - end + if ( not(sid) ) then + return "\n ERROR: Oracle instance not set (see oracle-brute-stealth.sid or tns.sid)" + end - if ( arg_johnfile ) then - johnfile = io.open(arg_johnfile, "w") - if ( not(johnfile) ) then - return ("\n ERROR: Failed to open %s for writing"):format(johnfile) - end - end + if ( arg_johnfile ) then + johnfile = io.open(arg_johnfile, "w") + if ( not(johnfile) ) then + return ("\n ERROR: Failed to open %s for writing"):format(johnfile) + end + end - local helper = tns.Helper:new( host, port, sid ) - local status, result = helper:Connect() - if ( not(status) ) then - return "\n ERROR: Failed to connect to oracle server" - end - helper:Close() + local helper = tns.Helper:new( host, port, sid ) + local status, result = helper:Connect() + if ( not(status) ) then + return "\n ERROR: Failed to connect to oracle server" + end + helper:Close() - if ( stdnse.get_script_args('userdb') or - stdnse.get_script_args('passdb') or - stdnse.get_script_args('oracle-brute-stealth.nodefault') or - stdnse.get_script_args('brute.credfile') ) then - mode = nil - end + if ( stdnse.get_script_args('userdb') or + stdnse.get_script_args('passdb') or + stdnse.get_script_args('oracle-brute-stealth.nodefault') or + stdnse.get_script_args('brute.credfile') ) then + mode = nil + end - if ( mode == "default" ) then - local f = nmap.fetchfile(DEFAULT_ACCOUNTS) - if ( not(f) ) then - return ("\n ERROR: Failed to find %s"):format(DEFAULT_ACCOUNTS) - end + if ( mode == "default" ) then + local f = nmap.fetchfile(DEFAULT_ACCOUNTS) + if ( not(f) ) then + return ("\n ERROR: Failed to find %s"):format(DEFAULT_ACCOUNTS) + end - f = io.open(f) - if ( not(f) ) then - return ("\n ERROR: Failed to open %s"):format(DEFAULT_ACCOUNTS) - end + f = io.open(f) + if ( not(f) ) then + return ("\n ERROR: Failed to open %s"):format(DEFAULT_ACCOUNTS) + end - engine.iterator = brute.Iterators.credential_iterator(f) - elseif( "accounts" == mode ) then - engine.iterator = unpwdb.table_iterator(stdnse.strsplit(",%s*", arg_accounts)) - end + engine.iterator = brute.Iterators.credential_iterator(f) + elseif( "accounts" == mode ) then + engine.iterator = unpwdb.table_iterator(stdnse.strsplit(",%s*", arg_accounts)) + end - engine.options.useraspass = false - engine.options.mode = "user" - engine.options.script_name = SCRIPT_NAME - status, result = engine:start() + engine.options.useraspass = false + engine.options.mode = "user" + engine.options.script_name = SCRIPT_NAME + status, result = engine:start() - if ( johnfile ) then - johnfile:close() - end + if ( johnfile ) then + johnfile:close() + end - return result + return result end diff --git a/scripts/oracle-brute.nse b/scripts/oracle-brute.nse index 1dac17044..ac9d1ee13 100644 --- a/scripts/oracle-brute.nse +++ b/scripts/oracle-brute.nse @@ -52,13 +52,13 @@ result in a large number of accounts being locked out on the database server. -- Version 0.3 -- Created 07/12/2010 - v0.1 - created by Patrik Karlsson -- Revised 07/23/2010 - v0.2 - added script usage and output and --- - oracle-brute.sid argument +-- - oracle-brute.sid argument -- Revised 07/25/2011 - v0.3 - added support for guessing default accounts -- changed code to use ConnectionPool -- Revised 03/13/2012 - v0.4 - revised by László Tóth -- added support for SYSDBA accounts -- Revised 08/07/2012 - v0.5 - revised to suit the changes in brute --- library [Aleksandar Nikolic] +-- library [Aleksandar Nikolic] -- -- Summary @@ -79,147 +79,147 @@ local sysdba = {} Driver = { - new = function(self, host, port, sid ) - local o = { host = host, port = port, sid = sid } - setmetatable(o, self) - self.__index = self - return o - end, + new = function(self, host, port, sid ) + local o = { host = host, port = port, sid = sid } + setmetatable(o, self) + self.__index = self + return o + end, - --- Connects performs protocol negotiation - -- - -- @return true on success, false on failure - connect = function( self ) - local MAX_RETRIES = 10 - local tries = MAX_RETRIES + --- Connects performs protocol negotiation + -- + -- @return true on success, false on failure + connect = function( self ) + local MAX_RETRIES = 10 + local tries = MAX_RETRIES - self.helper = ConnectionPool[coroutine.running()] - if ( self.helper ) then return true end + self.helper = ConnectionPool[coroutine.running()] + if ( self.helper ) then return true end - self.helper = tns.Helper:new( self.host, self.port, self.sid ) + self.helper = tns.Helper:new( self.host, self.port, self.sid ) - -- This loop is intended for handling failed connections - -- A connection may fail for a number of different reasons. - -- For the moment, we're just handling the error code 12520 - -- - -- Error 12520 has been observed on Oracle XE and seems to - -- occur when a maximum connection count is reached. - local status, data - repeat - if ( tries < MAX_RETRIES ) then - stdnse.print_debug(2, "%s: Attempting to re-connect (attempt %d of %d)", SCRIPT_NAME, MAX_RETRIES - tries, MAX_RETRIES) - end - status, data = self.helper:Connect() - if ( not(status) ) then - stdnse.print_debug(2, "%s: ERROR: An Oracle %s error occured", SCRIPT_NAME, data) - self.helper:Close() - else - break - end - tries = tries - 1 - stdnse.sleep(1) - until( tries == 0 or data ~= "12520" ) + -- This loop is intended for handling failed connections + -- A connection may fail for a number of different reasons. + -- For the moment, we're just handling the error code 12520 + -- + -- Error 12520 has been observed on Oracle XE and seems to + -- occur when a maximum connection count is reached. + local status, data + repeat + if ( tries < MAX_RETRIES ) then + stdnse.print_debug(2, "%s: Attempting to re-connect (attempt %d of %d)", SCRIPT_NAME, MAX_RETRIES - tries, MAX_RETRIES) + end + status, data = self.helper:Connect() + if ( not(status) ) then + stdnse.print_debug(2, "%s: ERROR: An Oracle %s error occured", SCRIPT_NAME, data) + self.helper:Close() + else + break + end + tries = tries - 1 + stdnse.sleep(1) + until( tries == 0 or data ~= "12520" ) - if ( status ) then - ConnectionPool[coroutine.running()] = self.helper - end + if ( status ) then + ConnectionPool[coroutine.running()] = self.helper + end - return status, data - end, + return status, data + end, - --- Attempts to login to the Oracle server - -- - -- @param username string containing the login username - -- @param password string containing the login password - -- @return status, true on success, false on failure - -- @return brute.Error object on failure - -- brute.Account object on success - login = function( self, username, password ) - local status, data = self.helper:Login( username, password ) + --- Attempts to login to the Oracle server + -- + -- @param username string containing the login username + -- @param password string containing the login password + -- @return status, true on success, false on failure + -- @return brute.Error object on failure + -- brute.Account object on success + login = function( self, username, password ) + local status, data = self.helper:Login( username, password ) - if ( sysdba[username] ) then - return false, brute.Error:new("Account already discovered") - end + if ( sysdba[username] ) then + return false, brute.Error:new("Account already discovered") + end - if ( status ) then - self.helper:Close() - ConnectionPool[coroutine.running()] = nil - return true, brute.Account:new(username, password, creds.State.VALID) - -- Check for account locked message - elseif ( data:match("ORA[-]28000") ) then - return true, brute.Account:new(username, password, creds.State.LOCKED) - -- Check for account is SYSDBA message - elseif ( data:match("ORA[-]28009") ) then - sysdba[username] = true - return true, brute.Account:new(username .. " as sysdba", password, creds.State.VALID) - -- check for any other message - elseif ( data:match("ORA[-]%d+")) then - stdnse.print_debug(3, "username: %s, password: %s, error: %s", username, password, data ) - return false, brute.Error:new(data) - -- any other errors are likely communication related, attempt to re-try - else - self.helper:Close() - ConnectionPool[coroutine.running()] = nil - local err = brute.Error:new(data) - err:setRetry(true) - return false, err - end + if ( status ) then + self.helper:Close() + ConnectionPool[coroutine.running()] = nil + return true, brute.Account:new(username, password, creds.State.VALID) + -- Check for account locked message + elseif ( data:match("ORA[-]28000") ) then + return true, brute.Account:new(username, password, creds.State.LOCKED) + -- Check for account is SYSDBA message + elseif ( data:match("ORA[-]28009") ) then + sysdba[username] = true + return true, brute.Account:new(username .. " as sysdba", password, creds.State.VALID) + -- check for any other message + elseif ( data:match("ORA[-]%d+")) then + stdnse.print_debug(3, "username: %s, password: %s, error: %s", username, password, data ) + return false, brute.Error:new(data) + -- any other errors are likely communication related, attempt to re-try + else + self.helper:Close() + ConnectionPool[coroutine.running()] = nil + local err = brute.Error:new(data) + err:setRetry(true) + return false, err + end - return false, brute.Error:new( data ) + return false, brute.Error:new( data ) - end, + end, - --- Disconnects and terminates the Oracle TNS communication - disconnect = function( self ) - return true - end, + --- Disconnects and terminates the Oracle TNS communication + disconnect = function( self ) + return true + end, } action = function(host, port) - local DEFAULT_ACCOUNTS = "nselib/data/oracle-default-accounts.lst" - local sid = stdnse.get_script_args('oracle-brute.sid') or - stdnse.get_script_args('tns.sid') - local engine = brute.Engine:new(Driver, host, port, sid) - local mode = "default" + local DEFAULT_ACCOUNTS = "nselib/data/oracle-default-accounts.lst" + local sid = stdnse.get_script_args('oracle-brute.sid') or + stdnse.get_script_args('tns.sid') + local engine = brute.Engine:new(Driver, host, port, sid) + local mode = "default" - if ( not(sid) ) then - return "\n ERROR: Oracle instance not set (see oracle-brute.sid or tns.sid)" - end + if ( not(sid) ) then + return "\n ERROR: Oracle instance not set (see oracle-brute.sid or tns.sid)" + end - local helper = tns.Helper:new( host, port, sid ) - local status, result = helper:Connect() - if ( not(status) ) then - return "\n ERROR: Failed to connect to oracle server" - end - helper:Close() + local helper = tns.Helper:new( host, port, sid ) + local status, result = helper:Connect() + if ( not(status) ) then + return "\n ERROR: Failed to connect to oracle server" + end + helper:Close() - local f + local f - if ( stdnse.get_script_args('userdb') or - stdnse.get_script_args('passdb') or - stdnse.get_script_args('oracle-brute.nodefault') or - stdnse.get_script_args('brute.credfile') ) then - mode = nil - end + if ( stdnse.get_script_args('userdb') or + stdnse.get_script_args('passdb') or + stdnse.get_script_args('oracle-brute.nodefault') or + stdnse.get_script_args('brute.credfile') ) then + mode = nil + end - if ( mode == "default" ) then - f = nmap.fetchfile(DEFAULT_ACCOUNTS) - if ( not(f) ) then - return ("\n ERROR: Failed to find %s"):format(DEFAULT_ACCOUNTS) - end + if ( mode == "default" ) then + f = nmap.fetchfile(DEFAULT_ACCOUNTS) + if ( not(f) ) then + return ("\n ERROR: Failed to find %s"):format(DEFAULT_ACCOUNTS) + end - f = io.open(f) - if ( not(f) ) then - return ("\n ERROR: Failed to open %s"):format(DEFAULT_ACCOUNTS) - end + f = io.open(f) + if ( not(f) ) then + return ("\n ERROR: Failed to open %s"):format(DEFAULT_ACCOUNTS) + end - engine.iterator = brute.Iterators.credential_iterator(f) - end + engine.iterator = brute.Iterators.credential_iterator(f) + end - engine.options.script_name = SCRIPT_NAME - status, result = engine:start() + engine.options.script_name = SCRIPT_NAME + status, result = engine:start() - return result + return result end diff --git a/scripts/quake3-info.nse b/scripts/quake3-info.nse index 5fe89e49c..cc6dd5122 100644 --- a/scripts/quake3-info.nse +++ b/scripts/quake3-info.nse @@ -69,188 +69,188 @@ categories = {"default", "discovery", "safe", "version"} local function range(first, last) - local list = {} - for i = first, last do - table.insert(list, i) - end - return list + local list = {} + for i = first, last do + table.insert(list, i) + end + return list end portrule = shortport.port_or_service(range(27960, 27970), {'quake3'}, 'udp') local function parsefields(data) - local fields = {} - local parts = stdnse.strsplit("\\", data) - local nullprefix = table.remove(parts, 1) - if nullprefix ~= "" then - stdnse.print_debug(2, "unrecognized field format, skipping options") - return {} - end - for i = 1, #parts, 2 do - local key = parts[i] - local value = parts[i + 1] - fields[key] = value - end - return fields + local fields = {} + local parts = stdnse.strsplit("\\", data) + local nullprefix = table.remove(parts, 1) + if nullprefix ~= "" then + stdnse.print_debug(2, "unrecognized field format, skipping options") + return {} + end + for i = 1, #parts, 2 do + local key = parts[i] + local value = parts[i + 1] + fields[key] = value + end + return fields end local function parsename(data) - local parts = stdnse.strsplit('"', data) - if #parts ~= 3 then - return nil - end - local e1 = parts[1] - local name = parts[2] - local e2 = parts[3] - local extra = e1 .. e2 - if extra ~= "" then - return nil - end - return name + local parts = stdnse.strsplit('"', data) + if #parts ~= 3 then + return nil + end + local e1 = parts[1] + local name = parts[2] + local e2 = parts[3] + local extra = e1 .. e2 + if extra ~= "" then + return nil + end + return name end local function parseplayer(data) - local parts = stdnse.strsplit(" ", data) - if #parts < 3 then - stdnse.print_debug(2, "player info line is missing elements, skipping a player") - return nil - end - if #parts > 3 then - stdnse.print_debug(2, "player info line has unknown elements, skipping a player") - return nil - end - local player = {} - player.frags = parts[1] - player.ping = parts[2] - player.name = parsename(parts[3]) - if player.name == nil then - stdnse.print_debug(2, "invalid player name serialization, skipping a player") - return nil - end - return player + local parts = stdnse.strsplit(" ", data) + if #parts < 3 then + stdnse.print_debug(2, "player info line is missing elements, skipping a player") + return nil + end + if #parts > 3 then + stdnse.print_debug(2, "player info line has unknown elements, skipping a player") + return nil + end + local player = {} + player.frags = parts[1] + player.ping = parts[2] + player.name = parsename(parts[3]) + if player.name == nil then + stdnse.print_debug(2, "invalid player name serialization, skipping a player") + return nil + end + return player end local function parseplayers(data) - local players = {} - for _, p in ipairs(data) do - local player = parseplayer(p) - if player then - table.insert(players, player) - end - end - return players + local players = {} + for _, p in ipairs(data) do + local player = parseplayer(p) + if player then + table.insert(players, player) + end + end + return players end local function is_leader(a, b) - local collide = a.name == b.name - local even = a.frags == b.frags - local leads = a.frags > b.frags - local alphab = a.name > b.name - local faster = a.ping > b.ping - return leads or (even and alphab) or (even and collide and faster) + local collide = a.name == b.name + local even = a.frags == b.frags + local leads = a.frags > b.frags + local alphab = a.name > b.name + local faster = a.ping > b.ping + return leads or (even and alphab) or (even and collide and faster) end local function formatplayers(players, fraglimit) - table.sort(players, is_leader) - local printable = {} - for i, player in ipairs(players) do - local name = player.name - local ping = player.ping - local frags = player.frags - if fraglimit then - frags = string.format("%s/%s", frags, fraglimit) - end - table.insert(printable, string.format("%d. %s (frags: %s, ping: %s)", i, name, frags, ping)) - end - printable["name"] = "PLAYERS:" - return printable + table.sort(players, is_leader) + local printable = {} + for i, player in ipairs(players) do + local name = player.name + local ping = player.ping + local frags = player.frags + if fraglimit then + frags = string.format("%s/%s", frags, fraglimit) + end + table.insert(printable, string.format("%d. %s (frags: %s, ping: %s)", i, name, frags, ping)) + end + printable["name"] = "PLAYERS:" + return printable end local function formatfields(fields, title) - local printable = {} - for key, value in pairs(fields) do - local kv = string.format("%s: %s", key, value) - table.insert(printable, kv) - end - table.sort(printable) - printable["name"] = title - return printable + local printable = {} + for key, value in pairs(fields) do + local kv = string.format("%s: %s", key, value) + table.insert(printable, kv) + end + table.sort(printable) + printable["name"] = title + return printable end local function assorted(fields) - local basic = {} - local other = {} - for key, value in pairs(fields) do - if string.find(key, "_") == nil then - basic[key] = value - else - other[key] = value - end - end - return basic, other + local basic = {} + local other = {} + for key, value in pairs(fields) do + if string.find(key, "_") == nil then + basic[key] = value + else + other[key] = value + end + end + return basic, other end action = function(host, port) - local GETSTATUS = bin.pack("CCCCA", 0xff, 0xff, 0xff, 0xff, "getstatus\n") - local STATUSRESP = bin.pack("CCCCA", 0xff, 0xff, 0xff, 0xff, "statusResponse") + local GETSTATUS = bin.pack("CCCCA", 0xff, 0xff, 0xff, 0xff, "getstatus\n") + local STATUSRESP = bin.pack("CCCCA", 0xff, 0xff, 0xff, 0xff, "statusResponse") - local status, data = comm.exchange(host, port, GETSTATUS, {["proto"] = "udp"}) - if not status then - return - end - local parts = stdnse.strsplit("\n", data) - local header = table.remove(parts, 1) - if header ~= STATUSRESP then - return - end - if #parts < 2 then - stdnse.print_debug(2, "incomplete status response, script abort") - return - end - local nullend = table.remove(parts) - if nullend ~= "" then - stdnse.print_debug(2, "missing terminating endline, script abort") - return - end - local field_data = table.remove(parts, 1) - local player_data = parts + local status, data = comm.exchange(host, port, GETSTATUS, {["proto"] = "udp"}) + if not status then + return + end + local parts = stdnse.strsplit("\n", data) + local header = table.remove(parts, 1) + if header ~= STATUSRESP then + return + end + if #parts < 2 then + stdnse.print_debug(2, "incomplete status response, script abort") + return + end + local nullend = table.remove(parts) + if nullend ~= "" then + stdnse.print_debug(2, "missing terminating endline, script abort") + return + end + local field_data = table.remove(parts, 1) + local player_data = parts - local fields = parsefields(field_data) - local players = parseplayers(player_data) + local fields = parsefields(field_data) + local players = parseplayers(player_data) - local basic, other = assorted(fields) + local basic, other = assorted(fields) - -- Previously observed version strings: - -- "tremulous 1.1.0 linux-x86_64 Aug  5 2010" - -- "ioq3 1.36+svn1933-1/Ubuntu linux-x86_64 Apr  4 2011" - local versionline = basic["version"] - if versionline then - local fields = stdnse.strsplit(" ", versionline) - local product = fields[1] - local version = fields[2] - local osline = fields[3] - port.version.name = "quake3" - port.version.product = product - port.version.version = version - if string.find(osline, "linux") then - port.version.ostype = "Linux" - end - if string.find(osline, "win") then - port.version.ostype = "Windows" - end - nmap.set_port_version(host, port) - end + -- Previously observed version strings: + -- "tremulous 1.1.0 linux-x86_64 Aug  5 2010" + -- "ioq3 1.36+svn1933-1/Ubuntu linux-x86_64 Apr  4 2011" + local versionline = basic["version"] + if versionline then + local fields = stdnse.strsplit(" ", versionline) + local product = fields[1] + local version = fields[2] + local osline = fields[3] + port.version.name = "quake3" + port.version.product = product + port.version.version = version + if string.find(osline, "linux") then + port.version.ostype = "Linux" + end + if string.find(osline, "win") then + port.version.ostype = "Windows" + end + nmap.set_port_version(host, port) + end - local fraglimit = fields["fraglimit"] - if not fraglimit then - fraglimit = "?" - end + local fraglimit = fields["fraglimit"] + if not fraglimit then + fraglimit = "?" + end - local response = {} - table.insert(response, formatplayers(players, fraglimit)) - table.insert(response, formatfields(basic, "BASIC OPTIONS:")) - if nmap.verbosity() > 0 then - table.insert(response, formatfields(other, "OTHER OPTIONS:")) - end - return stdnse.format_output(true, response) + local response = {} + table.insert(response, formatplayers(players, fraglimit)) + table.insert(response, formatfields(basic, "BASIC OPTIONS:")) + if nmap.verbosity() > 0 then + table.insert(response, formatfields(other, "OTHER OPTIONS:")) + end + return stdnse.format_output(true, response) end diff --git a/scripts/quake3-master-getservers.nse b/scripts/quake3-master-getservers.nse index 8da55e537..481fbed96 100644 --- a/scripts/quake3-master-getservers.nse +++ b/scripts/quake3-master-getservers.nse @@ -30,7 +30,7 @@ categories = {"default", "discovery", "safe"} portrule = shortport.port_or_service ({20110, 20510, 27950, 30710}, "quake3-master", {"udp"}) postrule = function() - return (nmap.registry.q3m_servers ~= nil) + return (nmap.registry.q3m_servers ~= nil) end -- There are various sources for this information. These include: @@ -41,213 +41,213 @@ end -- - scanning master servers -- - looking at game traffic with Wireshark local KNOWN_PROTOCOLS = { - ["5"] = "Call of Duty", - ["10"] = "unknown", - ["43"] = "unknown", - ["48"] = "unknown", - ["50"] = "Return to Castle Wolfenstein", - ["57"] = "unknown", - ["59"] = "Return to Castle Wolfenstein", - ["60"] = "Return to Castle Wolfenstein", - ["66"] = "Quake III Arena", - ["67"] = "Quake III Arena", - ["68"] = "Quake III Arena, or Urban Terror", - ["69"] = "OpenArena, or Tremulous", - ["70"] = "unknown", - ["71"] = "OpenArena", - ["72"] = "Wolfenstein: Enemy Territory", - ["80"] = "Wolfenstein: Enemy Territory", - ["83"] = "Wolfenstein: Enemy Territory", - ["84"] = "Wolfenstein: Enemy Territory", - ["2003"] = "Soldier of Fortune II: Double Helix", - ["2004"] = "Soldier of Fortune II: Double Helix", - ["DarkPlaces-Quake 3"] = "DarkPlaces Quake", - ["Nexuiz 3"] = "Nexuiz", - ["Transfusion 3"] = "Transfusion", - ["Warsow 8"] = "Warsow", - ["Xonotic 3"] = "Xonotic", + ["5"] = "Call of Duty", + ["10"] = "unknown", + ["43"] = "unknown", + ["48"] = "unknown", + ["50"] = "Return to Castle Wolfenstein", + ["57"] = "unknown", + ["59"] = "Return to Castle Wolfenstein", + ["60"] = "Return to Castle Wolfenstein", + ["66"] = "Quake III Arena", + ["67"] = "Quake III Arena", + ["68"] = "Quake III Arena, or Urban Terror", + ["69"] = "OpenArena, or Tremulous", + ["70"] = "unknown", + ["71"] = "OpenArena", + ["72"] = "Wolfenstein: Enemy Territory", + ["80"] = "Wolfenstein: Enemy Territory", + ["83"] = "Wolfenstein: Enemy Territory", + ["84"] = "Wolfenstein: Enemy Territory", + ["2003"] = "Soldier of Fortune II: Double Helix", + ["2004"] = "Soldier of Fortune II: Double Helix", + ["DarkPlaces-Quake 3"] = "DarkPlaces Quake", + ["Nexuiz 3"] = "Nexuiz", + ["Transfusion 3"] = "Transfusion", + ["Warsow 8"] = "Warsow", + ["Xonotic 3"] = "Xonotic", } local function getservers(host, port, q3protocol) - local socket = nmap.new_socket() - socket:set_timeout(10000) - local status, err = socket:connect(host.ip, port.number, "udp") - if not status then - return {} - end - local probe = bin.pack("CCCCA", 0xff, 0xff, 0xff, 0xff, string.format("getservers %s empty full\n", q3protocol)) - socket:send(probe) + local socket = nmap.new_socket() + socket:set_timeout(10000) + local status, err = socket:connect(host.ip, port.number, "udp") + if not status then + return {} + end + local probe = bin.pack("CCCCA", 0xff, 0xff, 0xff, 0xff, string.format("getservers %s empty full\n", q3protocol)) + socket:send(probe) local data - status, data = socket:receive() -- get some data - if not status then - return {} - end - nmap.set_port_state(host, port, "open") + status, data = socket:receive() -- get some data + if not status then + return {} + end + nmap.set_port_state(host, port, "open") - local magic = bin.pack("CCCCA", 0xff, 0xff, 0xff, 0xff, "getserversResponse") - local tmp - while #data < #magic do -- get header - status, tmp = socket:receive() - if status then - data = data .. tmp - end - end - if string.sub(data, 1, #magic) ~= magic then -- no match - return {} - end + local magic = bin.pack("CCCCA", 0xff, 0xff, 0xff, 0xff, "getserversResponse") + local tmp + while #data < #magic do -- get header + status, tmp = socket:receive() + if status then + data = data .. tmp + end + end + if string.sub(data, 1, #magic) ~= magic then -- no match + return {} + end - port.version.name = "quake3-master" - nmap.set_port_version(host, port) + port.version.name = "quake3-master" + nmap.set_port_version(host, port) - local EOT = bin.pack("ACCC", "EOT", 0, 0, 0) - local pieces = stdnse.strsplit("\\", data) - while pieces[#pieces] ~= EOT do -- get all data - status, tmp = socket:receive() - if status then - data = data .. tmp - pieces = stdnse.strsplit("\\", data) - end - end + local EOT = bin.pack("ACCC", "EOT", 0, 0, 0) + local pieces = stdnse.strsplit("\\", data) + while pieces[#pieces] ~= EOT do -- get all data + status, tmp = socket:receive() + if status then + data = data .. tmp + pieces = stdnse.strsplit("\\", data) + end + end - table.remove(pieces, 1) --remove magic - table.remove(pieces, #pieces) --remove EOT + table.remove(pieces, 1) --remove magic + table.remove(pieces, #pieces) --remove EOT - local servers = {} - for _, value in ipairs(pieces) do - local parts = {bin.unpack("CCCC>S", value)} - if #parts > 5 then - local o1 = parts[2] - local o2 = parts[3] - local o3 = parts[4] - local o4 = parts[5] - local p = parts[6] - table.insert(servers, {string.format("%d.%d.%d.%d", o1, o2, o3, o4), p}) - end - end - socket:close() - return servers + local servers = {} + for _, value in ipairs(pieces) do + local parts = {bin.unpack("CCCC>S", value)} + if #parts > 5 then + local o1 = parts[2] + local o2 = parts[3] + local o3 = parts[4] + local o4 = parts[5] + local p = parts[6] + table.insert(servers, {string.format("%d.%d.%d.%d", o1, o2, o3, o4), p}) + end + end + socket:close() + return servers end local function formatresult(servers, outputlimit, protocols) - local t = tab.new() + local t = tab.new() - if not outputlimit then - outputlimit = #servers - end - for i = 1, outputlimit do - if not servers[i] then - break - end - local node = servers[i] - local protocol = node.protocol - local ip = node.ip - local portnum = node.port - tab.addrow(t, string.format('%s:%d', ip, portnum), string.format('%s (%s)', protocols[protocol], protocol)) - end + if not outputlimit then + outputlimit = #servers + end + for i = 1, outputlimit do + if not servers[i] then + break + end + local node = servers[i] + local protocol = node.protocol + local ip = node.ip + local portnum = node.port + tab.addrow(t, string.format('%s:%d', ip, portnum), string.format('%s (%s)', protocols[protocol], protocol)) + end - return tab.dump(t) + return tab.dump(t) end local function dropdupes(tables, stringify) - local unique = {} - local dupe = {} - local s - for _, v in ipairs(tables) do - s = stringify(v) - if not dupe[s] then - table.insert(unique, v) - dupe[s] = true - end - end - return unique + local unique = {} + local dupe = {} + local s + for _, v in ipairs(tables) do + s = stringify(v) + if not dupe[s] then + table.insert(unique, v) + dupe[s] = true + end + end + return unique end local function scan(host, port, protocols) - local discovered = {} - for protocol, _ in pairs(protocols) do - for _, node in ipairs(getservers(host, port, protocol)) do - local entry = { - protocol = protocol, - ip = node[1], - port = node[2], - masterip = host.ip, - masterport = port.number - } - table.insert(discovered, entry) - end - end - return discovered + local discovered = {} + for protocol, _ in pairs(protocols) do + for _, node in ipairs(getservers(host, port, protocol)) do + local entry = { + protocol = protocol, + ip = node[1], + port = node[2], + masterip = host.ip, + masterport = port.number + } + table.insert(discovered, entry) + end + end + return discovered end local function store(servers) - if not nmap.registry.q3m_servers then - nmap.registry.q3m_servers = {} - end - for _, server in ipairs(servers) do - table.insert(nmap.registry.q3m_servers, server) - end + if not nmap.registry.q3m_servers then + nmap.registry.q3m_servers = {} + end + for _, server in ipairs(servers) do + table.insert(nmap.registry.q3m_servers, server) + end end local function protocols() - local filter = {} - local count = {} - for _, advert in ipairs(nmap.registry.q3m_servers) do - local key = stdnse.strjoin(":", {advert.ip, advert.port, advert.protocol}) - if filter[key] == nil then - if count[advert.protocol] == nil then - count[advert.protocol] = 0 - end - count[advert.protocol] = count[advert.protocol] + 1 - filter[key] = true - end - local mkey = stdnse.strjoin(":", {advert.masterip, advert.masterport}) - end - local sortable = {} - for k, v in pairs(count) do - table.insert(sortable, {k, v}) - end - table.sort(sortable, function(a, b) return a[2] > b[2] or (a[2] == b[2] and a[1] > b[1]) end) - local t = tab.new() - tab.addrow(t, '#', 'PROTOCOL', 'GAME', 'SERVERS') - for i, p in ipairs(sortable) do - local pos = i .. '.' - local protocol = p[1] - count = p[2] - local game = KNOWN_PROTOCOLS[protocol] - if game == "unknown" then - game = "" - end - tab.addrow(t, pos, protocol, game, count) - end - return '\n' .. tab.dump(t) + local filter = {} + local count = {} + for _, advert in ipairs(nmap.registry.q3m_servers) do + local key = stdnse.strjoin(":", {advert.ip, advert.port, advert.protocol}) + if filter[key] == nil then + if count[advert.protocol] == nil then + count[advert.protocol] = 0 + end + count[advert.protocol] = count[advert.protocol] + 1 + filter[key] = true + end + local mkey = stdnse.strjoin(":", {advert.masterip, advert.masterport}) + end + local sortable = {} + for k, v in pairs(count) do + table.insert(sortable, {k, v}) + end + table.sort(sortable, function(a, b) return a[2] > b[2] or (a[2] == b[2] and a[1] > b[1]) end) + local t = tab.new() + tab.addrow(t, '#', 'PROTOCOL', 'GAME', 'SERVERS') + for i, p in ipairs(sortable) do + local pos = i .. '.' + local protocol = p[1] + count = p[2] + local game = KNOWN_PROTOCOLS[protocol] + if game == "unknown" then + game = "" + end + tab.addrow(t, pos, protocol, game, count) + end + return '\n' .. tab.dump(t) end action = function(host, port) - if SCRIPT_TYPE == "postrule" then - return protocols() - end - local outputlimit = nmap.registry.args[SCRIPT_NAME .. ".outputlimit"] - if not outputlimit then - outputlimit = 10 - else - outputlimit = tonumber(outputlimit) - end - if outputlimit < 1 then - outputlimit = nil - end - local servers = scan(host, port, KNOWN_PROTOCOLS) - store(servers) - local unique = dropdupes(servers, function(t) return string.format("%s: %s:%d", t.protocol, t.ip, t.port) end) - local formatted = formatresult(unique, outputlimit, KNOWN_PROTOCOLS) - if #formatted < 1 then - return - end - local response = {} - table.insert(response, formatted) - if outputlimit and outputlimit < #servers then - table.insert(response, string.format('Only %d/%d shown. Use --script-args %s.outputlimit=-1 to see all.', outputlimit, #servers, SCRIPT_NAME)) - end - return stdnse.format_output(true, response) + if SCRIPT_TYPE == "postrule" then + return protocols() + end + local outputlimit = nmap.registry.args[SCRIPT_NAME .. ".outputlimit"] + if not outputlimit then + outputlimit = 10 + else + outputlimit = tonumber(outputlimit) + end + if outputlimit < 1 then + outputlimit = nil + end + local servers = scan(host, port, KNOWN_PROTOCOLS) + store(servers) + local unique = dropdupes(servers, function(t) return string.format("%s: %s:%d", t.protocol, t.ip, t.port) end) + local formatted = formatresult(unique, outputlimit, KNOWN_PROTOCOLS) + if #formatted < 1 then + return + end + local response = {} + table.insert(response, formatted) + if outputlimit and outputlimit < #servers then + table.insert(response, string.format('Only %d/%d shown. Use --script-args %s.outputlimit=-1 to see all.', outputlimit, #servers, SCRIPT_NAME)) + end + return stdnse.format_output(true, response) end diff --git a/scripts/rdp-vuln-ms12-020.nse b/scripts/rdp-vuln-ms12-020.nse index efe40b456..331633be5 100644 --- a/scripts/rdp-vuln-ms12-020.nse +++ b/scripts/rdp-vuln-ms12-020.nse @@ -72,152 +72,152 @@ categories = {"intrusive", "vuln"} portrule = shortport.port_or_service({3389},{"ms-wbt-server"}) action = function(host, port) - local socket = nmap.new_socket() - local status, err,response + local socket = nmap.new_socket() + local status, err,response - -- see http://msdn.microsoft.com/en-us/library/cc240836%28v=prot.10%29.aspx for more info - local connectionRequestStr = "0300" -- TPKT Header version 03, reserved 0 - .. "000b" -- Length - .. "06" -- X.224 Data TPDU length - .. "e0" -- X.224 Type (Connection request) - .. "0000" -- dst reference - .. "0000" -- src reference - .. "00" -- class and options - local connectionRequest = bin.pack("H",connectionRequestStr) + -- see http://msdn.microsoft.com/en-us/library/cc240836%28v=prot.10%29.aspx for more info + local connectionRequestStr = "0300" -- TPKT Header version 03, reserved 0 + .. "000b" -- Length + .. "06" -- X.224 Data TPDU length + .. "e0" -- X.224 Type (Connection request) + .. "0000" -- dst reference + .. "0000" -- src reference + .. "00" -- class and options + local connectionRequest = bin.pack("H",connectionRequestStr) - -- see http://msdn.microsoft.com/en-us/library/cc240836%28v=prot.10%29.aspx - local connectInitialStr = "03000065" -- TPKT Header - .. "02f080" -- Data TPDU, EOT - .. "7f655b" -- Connect-Initial - .. "040101" -- callingDomainSelector - .. "040101" -- calledDomainSelector - .. "0101ff" -- upwardFlag - .. "3019" -- targetParams + size - .. "020122" -- maxChannelIds - .. "020120" -- maxUserIds - .. "020100" -- maxTokenIds - .. "020101" -- numPriorities - .. "020100" -- minThroughput - .. "020101" -- maxHeight - .. "0202ffff" -- maxMCSPDUSize - .. "020102" -- protocolVersion - .. "3018" -- minParams + size - .. "020101" -- maxChannelIds - .. "020101" -- maxUserIds - .. "020101" -- maxTokenIds - .. "020101" -- numPriorities - .. "020100" -- minThroughput - .. "020101" -- maxHeight - .. "0201ff" -- maxMCSPDUSize - .. "020102" -- protocolVersion - .. "3019" -- maxParams + size - .. "0201ff" -- maxChannelIds - .. "0201ff" -- maxUserIds - .. "0201ff" -- maxTokenIds - .. "020101" -- numPriorities - .. "020100" -- minThroughput - .. "020101" -- maxHeight - .. "0202ffff" -- maxMCSPDUSize - .. "020102" -- protocolVersion - .. "0400" -- userData - local connectInitial = bin.pack("H",connectInitialStr) + -- see http://msdn.microsoft.com/en-us/library/cc240836%28v=prot.10%29.aspx + local connectInitialStr = "03000065" -- TPKT Header + .. "02f080" -- Data TPDU, EOT + .. "7f655b" -- Connect-Initial + .. "040101" -- callingDomainSelector + .. "040101" -- calledDomainSelector + .. "0101ff" -- upwardFlag + .. "3019" -- targetParams + size + .. "020122" -- maxChannelIds + .. "020120" -- maxUserIds + .. "020100" -- maxTokenIds + .. "020101" -- numPriorities + .. "020100" -- minThroughput + .. "020101" -- maxHeight + .. "0202ffff" -- maxMCSPDUSize + .. "020102" -- protocolVersion + .. "3018" -- minParams + size + .. "020101" -- maxChannelIds + .. "020101" -- maxUserIds + .. "020101" -- maxTokenIds + .. "020101" -- numPriorities + .. "020100" -- minThroughput + .. "020101" -- maxHeight + .. "0201ff" -- maxMCSPDUSize + .. "020102" -- protocolVersion + .. "3019" -- maxParams + size + .. "0201ff" -- maxChannelIds + .. "0201ff" -- maxUserIds + .. "0201ff" -- maxTokenIds + .. "020101" -- numPriorities + .. "020100" -- minThroughput + .. "020101" -- maxHeight + .. "0202ffff" -- maxMCSPDUSize + .. "020102" -- protocolVersion + .. "0400" -- userData + local connectInitial = bin.pack("H",connectInitialStr) - -- see http://msdn.microsoft.com/en-us/library/cc240835%28v=prot.10%29.aspx - local userRequestStr = "0300" -- header - .. "0008" -- length - .. "02f080" -- X.224 Data TPDU (2 bytes: 0xf0 = Data TPDU, 0x80 = EOT, end of transmission) - .. "28" -- PER encoded PDU contents - local userRequest = bin.pack("H",userRequestStr) + -- see http://msdn.microsoft.com/en-us/library/cc240835%28v=prot.10%29.aspx + local userRequestStr = "0300" -- header + .. "0008" -- length + .. "02f080" -- X.224 Data TPDU (2 bytes: 0xf0 = Data TPDU, 0x80 = EOT, end of transmission) + .. "28" -- PER encoded PDU contents + local userRequest = bin.pack("H",userRequestStr) - local user1,user2 - local pos + local user1,user2 + local pos - local rdp_vuln_0152 = { - title = "MS12-020 Remote Desktop Protocol Denial Of Service Vulnerability", - IDS = {CVE = 'CVE-2012-0152'}, - risk_factor = "Medium", - scores = { - CVSSv2 = "4.3 (MEDIUM) (AV:N/AC:M/Au:N/C:N/I:N/A:P)", - }, - description = [[ - Remote Desktop Protocol vulnerability that could allow remote attackers to cause a denial of service. - ]], - references = { - 'http://technet.microsoft.com/en-us/security/bulletin/ms12-020', - }, - dates = { - disclosure = {year = '2012', month = '03', day = '13'}, - }, - exploit_results = {}, - } + local rdp_vuln_0152 = { + title = "MS12-020 Remote Desktop Protocol Denial Of Service Vulnerability", + IDS = {CVE = 'CVE-2012-0152'}, + risk_factor = "Medium", + scores = { + CVSSv2 = "4.3 (MEDIUM) (AV:N/AC:M/Au:N/C:N/I:N/A:P)", + }, + description = [[ + Remote Desktop Protocol vulnerability that could allow remote attackers to cause a denial of service. + ]], + references = { + 'http://technet.microsoft.com/en-us/security/bulletin/ms12-020', + }, + dates = { + disclosure = {year = '2012', month = '03', day = '13'}, + }, + exploit_results = {}, + } - local rdp_vuln_0002 = { - title = "MS12-020 Remote Desktop Protocol Remote Code Execution Vulnerability", - IDS = {CVE = 'CVE-2012-0002'}, - risk_factor = "High", - scores = { - CVSSv2 = "9.3 (HIGH) (AV:N/AC:M/Au:N/C:C/I:C/A:C)", - }, - description = [[ - Remote Desktop Protocol vulnerability that could allow remote attackers to execute arbitrary code on the targeted system. - ]], - references = { - 'http://technet.microsoft.com/en-us/security/bulletin/ms12-020', - }, - dates = { - disclosure = {year = '2012', month = '03', day = '13'}, - }, - exploit_results = {}, - } + local rdp_vuln_0002 = { + title = "MS12-020 Remote Desktop Protocol Remote Code Execution Vulnerability", + IDS = {CVE = 'CVE-2012-0002'}, + risk_factor = "High", + scores = { + CVSSv2 = "9.3 (HIGH) (AV:N/AC:M/Au:N/C:C/I:C/A:C)", + }, + description = [[ + Remote Desktop Protocol vulnerability that could allow remote attackers to execute arbitrary code on the targeted system. + ]], + references = { + 'http://technet.microsoft.com/en-us/security/bulletin/ms12-020', + }, + dates = { + disclosure = {year = '2012', month = '03', day = '13'}, + }, + exploit_results = {}, + } - local report = vulns.Report:new(SCRIPT_NAME, host, port) - rdp_vuln_0152.state = vulns.STATE.NOT_VULN - rdp_vuln_0002.state = vulns.STATE.NOT_VULN + local report = vulns.Report:new(SCRIPT_NAME, host, port) + rdp_vuln_0152.state = vulns.STATE.NOT_VULN + rdp_vuln_0002.state = vulns.STATE.NOT_VULN - -- Sleep for 0.2 seconds to make sure the script works even with SYN scan. - -- Posible reason for this is that Windows resets the connection if we try to - -- reconect too fast to the same port after doing a SYN scan and not completing the - -- handshake. In my tests, sleep values above 0.1s prevent the connection reset. - stdnse.sleep(0.2) + -- Sleep for 0.2 seconds to make sure the script works even with SYN scan. + -- Posible reason for this is that Windows resets the connection if we try to + -- reconect too fast to the same port after doing a SYN scan and not completing the + -- handshake. In my tests, sleep values above 0.1s prevent the connection reset. + stdnse.sleep(0.2) - socket:connect(host.ip, port) - status, err = socket:send(connectionRequest) + socket:connect(host.ip, port) + status, err = socket:send(connectionRequest) - status, response = socket:receive_bytes(0) - if response ~= bin.pack("H","0300000b06d00000123400") then - --probably not rdp at all - stdnse.print_debug(1, "%s: not RDP", SCRIPT_NAME) - return nil - end - status, err = socket:send(connectInitial) - status, err = socket:send(userRequest) -- send attach user request - status, response = socket:receive_bytes(0) -- recieve attach user confirm - pos,user1 = bin.unpack(">S",response:sub(10,11)) -- user_channel-1001 - see http://msdn.microsoft.com/en-us/library/cc240918%28v=prot.10%29.aspx + status, response = socket:receive_bytes(0) + if response ~= bin.pack("H","0300000b06d00000123400") then + --probably not rdp at all + stdnse.print_debug(1, "%s: not RDP", SCRIPT_NAME) + return nil + end + status, err = socket:send(connectInitial) + status, err = socket:send(userRequest) -- send attach user request + status, response = socket:receive_bytes(0) -- recieve attach user confirm + pos,user1 = bin.unpack(">S",response:sub(10,11)) -- user_channel-1001 - see http://msdn.microsoft.com/en-us/library/cc240918%28v=prot.10%29.aspx - status, err = socket:send(userRequest) -- send another attach user request - status, response = socket:receive_bytes(0) -- recieve another attach user confirm - pos,user2 = bin.unpack(">S",response:sub(10,11)) -- second user's channel - 1001 - user2 = user2+1001 -- second user's channel - local data4 = bin.pack(">SS",user1,user2) - local data5 = bin.pack("H","0300000c02f08038") -- channel join request TPDU - local channelJoinRequest = data5 .. data4 - status, err = socket:send(channelJoinRequest) -- bogus channel join request user1 requests channel of user2 - status, response = socket:receive_bytes(0) - if response:sub(8,9) == bin.pack("H","3e00") then - -- 3e00 indicates a successfull join - -- see http://msdn.microsoft.com/en-us/library/cc240911%28v=prot.10%29.aspx - -- service is vulnerable - -- send a valid request to prevent the BSoD - data4 = bin.pack(">SS",user2-1001,user2) - channelJoinRequest = data5 .. data4 -- valid join request - status, err = socket:send(channelJoinRequest) - status, response = socket:receive_bytes(0) - socket:close() - rdp_vuln_0152.state = vulns.STATE.VULN - rdp_vuln_0002.state = vulns.STATE.VULN - return report:make_output(rdp_vuln_0152,rdp_vuln_0002) - end - --service is not vulnerable - socket:close() - return report:make_output(rdp_vuln_0152,rdp_vuln_0002) + status, err = socket:send(userRequest) -- send another attach user request + status, response = socket:receive_bytes(0) -- recieve another attach user confirm + pos,user2 = bin.unpack(">S",response:sub(10,11)) -- second user's channel - 1001 + user2 = user2+1001 -- second user's channel + local data4 = bin.pack(">SS",user1,user2) + local data5 = bin.pack("H","0300000c02f08038") -- channel join request TPDU + local channelJoinRequest = data5 .. data4 + status, err = socket:send(channelJoinRequest) -- bogus channel join request user1 requests channel of user2 + status, response = socket:receive_bytes(0) + if response:sub(8,9) == bin.pack("H","3e00") then + -- 3e00 indicates a successfull join + -- see http://msdn.microsoft.com/en-us/library/cc240911%28v=prot.10%29.aspx + -- service is vulnerable + -- send a valid request to prevent the BSoD + data4 = bin.pack(">SS",user2-1001,user2) + channelJoinRequest = data5 .. data4 -- valid join request + status, err = socket:send(channelJoinRequest) + status, response = socket:receive_bytes(0) + socket:close() + rdp_vuln_0152.state = vulns.STATE.VULN + rdp_vuln_0002.state = vulns.STATE.VULN + return report:make_output(rdp_vuln_0152,rdp_vuln_0002) + end + --service is not vulnerable + socket:close() + return report:make_output(rdp_vuln_0152,rdp_vuln_0002) end diff --git a/scripts/rmi-dumpregistry.nse b/scripts/rmi-dumpregistry.nse index 647d09eba..1cd66b2d5 100644 --- a/scripts/rmi-dumpregistry.nse +++ b/scripts/rmi-dumpregistry.nse @@ -155,20 +155,20 @@ portrule = shortport.port_or_service({1098, 1099, 1090, 8901, 8902, 8903}, {"jav -- Some lazy shortcuts local function dbg(str,...) - stdnse.print_debug(3,"RMI-DUMPREG:"..str, ...) + stdnse.print_debug(3,"RMI-DUMPREG:"..str, ...) end local function dbg_err(str, ... ) - stdnse.print_debug("RMI-DUMPREG-ERR:"..str, ...) + stdnse.print_debug("RMI-DUMPREG-ERR:"..str, ...) end -- Function to split a string local function split(str, sep) - local sep, fields = sep or "; ", {} - local pattern = string.format("([^%s]+)", sep) - str:gsub(pattern, function(c) fields[#fields+1] = c end) - return fields - end + local sep, fields = sep or "; ", {} + local pattern = string.format("([^%s]+)", sep) + str:gsub(pattern, function(c) fields[#fields+1] = c end) + return fields +end --This is a customData formatter. In some cases, the RMI library finds 'custom data' which belongs to an object. @@ -180,57 +180,57 @@ local function split(str, sep) -- of the returned RMI object. -- @return title, data function customDataFormatter(className, customData) - if customData == nil then return nil end - if #customData ==0 then return nil end + if customData == nil then return nil end + if #customData ==0 then return nil end - local retData = {} - for k,v in ipairs(customData) do - if v:find("file:/") == 1 then - -- This is a classpath - local cp = split(v, "; ") -- Splits into table - table.insert(retData, "Classpath") - table.insert(retData, cp) - else - table.insert(retData[v]) - end - end + local retData = {} + for k,v in ipairs(customData) do + if v:find("file:/") == 1 then + -- This is a classpath + local cp = split(v, "; ") -- Splits into table + table.insert(retData, "Classpath") + table.insert(retData, cp) + else + table.insert(retData[v]) + end + end - return "Custom data", retData + return "Custom data", retData end function action(host,port, args) - local registry= rmi.Registry:new( host.ip, port.number) + local registry= rmi.Registry:new( host.ip, port.number) - local status, j_array = registry:list() - local output = {} - if not status then - return false, ("Registry listing failed (%s)"):format(tostring(j_array)) - end - -- It's definitely RMI! - port.version.name ='java-rmi' - port.version.product='Java RMI Registry' - nmap.set_port_version(host,port) + local status, j_array = registry:list() + local output = {} + if not status then + return false, ("Registry listing failed (%s)"):format(tostring(j_array)) + end + -- It's definitely RMI! + port.version.name ='java-rmi' + port.version.product='Java RMI Registry' + nmap.set_port_version(host,port) - -- Monkey patch the java-class in rmi, to set our own custom data formatter - -- for classpaths - rmi.JavaClass.customDataFormatter = customDataFormatter + -- Monkey patch the java-class in rmi, to set our own custom data formatter + -- for classpaths + rmi.JavaClass.customDataFormatter = customDataFormatter - -- We expect an array of strings to be the return data - local data = j_array:getValues() - for i,name in ipairs( data ) do - --print(data) - table.insert(output, name) - dbg("Querying object %s", name) - local status, j_object= registry:lookup(name) + -- We expect an array of strings to be the return data + local data = j_array:getValues() + for i,name in ipairs( data ) do + --print(data) + table.insert(output, name) + dbg("Querying object %s", name) + local status, j_object= registry:lookup(name) - if status then - table.insert(output, j_object:toTable()) - end + if status then + table.insert(output, j_object:toTable()) + end - end - return stdnse.format_output(true, output) + end + return stdnse.format_output(true, output) end diff --git a/scripts/rpc-grind.nse b/scripts/rpc-grind.nse index 0edf88dee..ea6df1feb 100644 --- a/scripts/rpc-grind.nse +++ b/scripts/rpc-grind.nse @@ -44,16 +44,16 @@ categories = {"version"} portrule = function(host, port) - -- Do not run for excluded ports - if (nmap.port_is_excluded(port.number, port.protocol)) then - return false - end - if port.service ~= nil and port.version.service_dtype ~= "table" and port.service ~= 'rpcbind' then - -- Exclude services that have already been detected as something - -- different than rpcbind. - return false - end - return true + -- Do not run for excluded ports + if (nmap.port_is_excluded(port.number, port.protocol)) then + return false + end + if port.service ~= nil and port.version.service_dtype ~= "table" and port.service ~= 'rpcbind' then + -- Exclude services that have already been detected as something + -- different than rpcbind. + return false + end + return true end --- Function that determines if the target port of host uses RPC protocol. @@ -61,57 +61,57 @@ end --@param port Port table as commonly used in Nmap. --@return status boolean True if target port uses RPC protocol, false else. local isRPC = function(host, port) - -- If rpcbind is already set up by -sV - -- which does practically the same check as in the "else" part. - -- The nmap-services-probe entry "rpcbind" is not correctly true, and should - -- be changed to something like "sunrpc" - if port.service == 'rpcbind' then - return true - else - -- this check is important if we didn't run the scan with -sV. - -- If we run the scan with -sV, this check shouldn't return true as it is pretty much similar - -- to the "rpcbind" service probe in nmap-service-probes. - local rpcConn, status, err, data, rxid, msgtype, _ + -- If rpcbind is already set up by -sV + -- which does practically the same check as in the "else" part. + -- The nmap-services-probe entry "rpcbind" is not correctly true, and should + -- be changed to something like "sunrpc" + if port.service == 'rpcbind' then + return true + else + -- this check is important if we didn't run the scan with -sV. + -- If we run the scan with -sV, this check shouldn't return true as it is pretty much similar + -- to the "rpcbind" service probe in nmap-service-probes. + local rpcConn, status, err, data, rxid, msgtype, _ - -- Create new socket - -- rpcbind is not really important, we could have used another protocol from rpc.lua - -- such as nfs or mountd. Same thing for version 2. - rpcConn = rpc.Comm:new("rpcbind", 2) - status, err = rpcConn:Connect(host, port) - if not status then - stdnse.print_debug("%s: %s", SCRIPT_NAME, err) - return - end - - -- Send packet - local xid = math.random(1234567890) - data = rpcConn:EncodePacket(xid) - status, err = rpcConn:SendPacket(data) - if not status then - stdnse.print_debug("%s SendPacket(): %s", SCRIPT_NAME, err) - return - end - - -- And check response - status, data = rpcConn:ReceivePacket() - if not status then - stdnse.print_debug("%s: isRPC didn't receive response.", SCRIPT_NAME) - return - else - -- If we got response, set port to open - nmap.set_port_state(host, port, "open") - - _, rxid = bin.unpack(">I", data, 1) - _, msgtype = bin.unpack(">I", data, 5) - -- If response XID does match request XID - -- and message type equals 1 (REPLY) then - -- it is a RPC port. - if rxid == xid and msgtype == 1 then - return true - end - end + -- Create new socket + -- rpcbind is not really important, we could have used another protocol from rpc.lua + -- such as nfs or mountd. Same thing for version 2. + rpcConn = rpc.Comm:new("rpcbind", 2) + status, err = rpcConn:Connect(host, port) + if not status then + stdnse.print_debug("%s: %s", SCRIPT_NAME, err) + return end - stdnse.print_debug("%s: RPC checking function response data is not RPC.", SCRIPT_NAME) + + -- Send packet + local xid = math.random(1234567890) + data = rpcConn:EncodePacket(xid) + status, err = rpcConn:SendPacket(data) + if not status then + stdnse.print_debug("%s SendPacket(): %s", SCRIPT_NAME, err) + return + end + + -- And check response + status, data = rpcConn:ReceivePacket() + if not status then + stdnse.print_debug("%s: isRPC didn't receive response.", SCRIPT_NAME) + return + else + -- If we got response, set port to open + nmap.set_port_state(host, port, "open") + + _, rxid = bin.unpack(">I", data, 1) + _, msgtype = bin.unpack(">I", data, 5) + -- If response XID does match request XID + -- and message type equals 1 (REPLY) then + -- it is a RPC port. + if rxid == xid and msgtype == 1 then + return true + end + end + end + stdnse.print_debug("%s: RPC checking function response data is not RPC.", SCRIPT_NAME) end -- Function that iterates over the nmap-rpc file and @@ -119,34 +119,34 @@ end -- @return name Name of the RPC service. -- @return number RPC number of the matching service name. local rpcIterator = function() - -- Check if nmap-rpc file is present. - local path = nmap.fetchfile("nmap-rpc") - if not path then - stdnse.print_debug("%s: Could not find nmap-rpc file.", SCRIPT_NAME) - return false - end + -- Check if nmap-rpc file is present. + local path = nmap.fetchfile("nmap-rpc") + if not path then + stdnse.print_debug("%s: Could not find nmap-rpc file.", SCRIPT_NAME) + return false + end - -- And is readable - local nmaprpc, _, _ = io.open( path, "r" ) - if not nmaprpc then - stdnse.print_debug("%s: Could not open nmap-rpc for reading.", SCRIPT_NAME) - return false - end + -- And is readable + local nmaprpc, _, _ = io.open( path, "r" ) + if not nmaprpc then + stdnse.print_debug("%s: Could not open nmap-rpc for reading.", SCRIPT_NAME) + return false + end - return function() - while true do - local line = nmaprpc:read() - if not line then - break - end - -- Now, we parse lines for meaningful ones - local name, number = line:match("^%s*([^%s#]+)%s+(%d+)") - -- And return program name and number - if name and number then - return name, tonumber(number) - end - end + return function() + while true do + local line = nmaprpc:read() + if not line then + break + end + -- Now, we parse lines for meaningful ones + local name, number = line:match("^%s*([^%s#]+)%s+(%d+)") + -- And return program name and number + if name and number then + return name, tonumber(number) + end end + end end --- Function that sends RPC null commands with a random version number and @@ -157,113 +157,113 @@ end -- @param iterator Iterator function that returns program name and number pairs. -- @param result table to put result into. local rpcGrinder = function(host, port, iterator, result) - local condvar = nmap.condvar(result) - local rpcConn, version, xid, status, response, packet, err, data, _ + local condvar = nmap.condvar(result) + local rpcConn, version, xid, status, response, packet, err, data, _ - xid = math.random(123456789) - -- We use a random, most likely unsupported version so that - -- we also trigger min and max version disclosure for the target service. - version = math.random(12345, 123456789) - rpcConn = rpc.Comm:new("rpcbind", version) - rpcConn:SetCheckProgVer(false) - status, err = rpcConn:Connect(host, port) + xid = math.random(123456789) + -- We use a random, most likely unsupported version so that + -- we also trigger min and max version disclosure for the target service. + version = math.random(12345, 123456789) + rpcConn = rpc.Comm:new("rpcbind", version) + rpcConn:SetCheckProgVer(false) + status, err = rpcConn:Connect(host, port) - if not status then - stdnse.print_debug("%s Connect(): %s", SCRIPT_NAME, err) - condvar "signal"; - return - end - for program, number in iterator do - -- No need to continue further if we found the matching service. - if #result > 0 then - break - end - - xid = xid + 1 -- XiD increased by 1 each time (from old RPC grind) <= Any important reason for that? - rpcConn:SetProgID(number) - packet = rpcConn:EncodePacket(xid) - status, err = rpcConn:SendPacket(packet) - if not status then - stdnse.print_debug("%s SendPacket(): %s", SCRIPT_NAME, err) - condvar "signal"; - return - end - - status, data = rpcConn:ReceivePacket() - if not status then - stdnse.print_debug("%s ReceivePacket(): %s", SCRIPT_NAME, data) - condvar "signal"; - return - end - - _,response = rpcConn:DecodeHeader(data, 1) - if type(response) == 'table' then - if xid ~= response.xid then - -- Shouldn't happen. - stdnse.print_debug("%s: XID mismtach.", SCRIPT_NAME) - end - -- Look at accept state - -- Not supported version means that we used the right program number - if response.accept_state == rpc.Portmap.AcceptState.PROG_MISMATCH then - result.program = program - result.number = number - _, result.highver = bin.unpack(">I", data, #data - 3) - _, result.lowver = bin.unpack(">I", data, #data - 7) - table.insert(result, true) -- To make #result > 1 - - -- Otherwise, an Accept state other than Program unavailable is not normal behaviour. - elseif response.accept_state ~= rpc.Portmap.AcceptState.PROG_UNAVAIL then - stdnse.print_debug("%s: returned %s accept state for %s program number.",SCRIPT_NAME, response.accept_state, number) - end - end - end + if not status then + stdnse.print_debug("%s Connect(): %s", SCRIPT_NAME, err) condvar "signal"; - return result + return + end + for program, number in iterator do + -- No need to continue further if we found the matching service. + if #result > 0 then + break + end + + xid = xid + 1 -- XiD increased by 1 each time (from old RPC grind) <= Any important reason for that? + rpcConn:SetProgID(number) + packet = rpcConn:EncodePacket(xid) + status, err = rpcConn:SendPacket(packet) + if not status then + stdnse.print_debug("%s SendPacket(): %s", SCRIPT_NAME, err) + condvar "signal"; + return + end + + status, data = rpcConn:ReceivePacket() + if not status then + stdnse.print_debug("%s ReceivePacket(): %s", SCRIPT_NAME, data) + condvar "signal"; + return + end + + _,response = rpcConn:DecodeHeader(data, 1) + if type(response) == 'table' then + if xid ~= response.xid then + -- Shouldn't happen. + stdnse.print_debug("%s: XID mismtach.", SCRIPT_NAME) + end + -- Look at accept state + -- Not supported version means that we used the right program number + if response.accept_state == rpc.Portmap.AcceptState.PROG_MISMATCH then + result.program = program + result.number = number + _, result.highver = bin.unpack(">I", data, #data - 3) + _, result.lowver = bin.unpack(">I", data, #data - 7) + table.insert(result, true) -- To make #result > 1 + + -- Otherwise, an Accept state other than Program unavailable is not normal behaviour. + elseif response.accept_state ~= rpc.Portmap.AcceptState.PROG_UNAVAIL then + stdnse.print_debug("%s: returned %s accept state for %s program number.",SCRIPT_NAME, response.accept_state, number) + end + end + end + condvar "signal"; + return result end action = function(host, port) - local result, lthreads = {}, {} + local result, lthreads = {}, {} - if not isRPC(host, port) then - stdnse.print_debug("Target port %s is not a RPC port.", port.number) - return + if not isRPC(host, port) then + stdnse.print_debug("Target port %s is not a RPC port.", port.number) + return + end + local threads = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".threads")) or 4 + + local iterator = rpcIterator() + if not iterator then + return + end + -- And now, exec our grinder + for i = 1,threads do + local co = stdnse.new_thread(rpcGrinder, host, port, iterator, result) + lthreads[co] = true + end + + local condvar = nmap.condvar(result) + repeat + for thread in pairs(lthreads) do + if coroutine.status(thread) == "dead" then + lthreads[thread] = nil + end end - local threads = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".threads")) or 4 - - local iterator = rpcIterator() - if not iterator then - return - end - -- And now, exec our grinder - for i = 1,threads do - local co = stdnse.new_thread(rpcGrinder, host, port, iterator, result) - lthreads[co] = true + if ( next(lthreads) ) then + condvar "wait"; end + until next(lthreads) == nil; - local condvar = nmap.condvar(result) - repeat - for thread in pairs(lthreads) do - if coroutine.status(thread) == "dead" then - lthreads[thread] = nil - end - end - if ( next(lthreads) ) then - condvar "wait"; - end - until next(lthreads) == nil; - - -- Check the result and set the port version. - if #result > 0 then - port.version.name = result.program - port.version.extrainfo = "RPC #" .. result.number - if result.highver ~= result.lowver then - port.version.version = ("%s-%s"):format(result.lowver, result.highver) - else - port.version.version = result.highver - end - nmap.set_port_version(host, port, "hardmatched") + -- Check the result and set the port version. + if #result > 0 then + port.version.name = result.program + port.version.extrainfo = "RPC #" .. result.number + if result.highver ~= result.lowver then + port.version.version = ("%s-%s"):format(result.lowver, result.highver) else - stdnse.print_debug("Couldn't determine the target RPC service. Running a service not in nmap-rpc ?") + port.version.version = result.highver end - return nil + nmap.set_port_version(host, port, "hardmatched") + else + stdnse.print_debug("Couldn't determine the target RPC service. Running a service not in nmap-rpc ?") + end + return nil end diff --git a/scripts/sip-enum-users.nse b/scripts/sip-enum-users.nse index 8f504cade..356d5fdf5 100644 --- a/scripts/sip-enum-users.nse +++ b/scripts/sip-enum-users.nse @@ -73,14 +73,14 @@ portrule = shortport.port_or_service(5060, "sip", {"tcp", "udp"}) -- @return status true on success, false on failure. -- @return Response instance on success, error string on failure. local registerext = function(sess, ext) - -- set session values - local request = sip.Request:new(sip.Method.REGISTER) + -- set session values + local request = sip.Request:new(sip.Method.REGISTER) - request:setUri("sip:" .. sess.sessdata:getServer()) - sess.sessdata:setUsername(ext) - request:setSessionData(sess.sessdata) + request:setUri("sip:" .. sess.sessdata:getServer()) + sess.sessdata:setUsername(ext) + request:setSessionData(sess.sessdata) - return sess:exch(request) + return sess:exch(request) end --- Function that returns a number as string with a number of zeroes padded to @@ -89,14 +89,14 @@ end -- @arg padding number of digits to pad up to. -- @return string of padded number. local padnum = function(num, padding) - -- How many zeroes do we need to add - local n = #tostring(num) - if n >= padding then - return tostring(num) - end - n = padding - n + -- How many zeroes do we need to add + local n = #tostring(num) + if n >= padding then + return tostring(num) + end + n = padding - n - return string.rep(tostring(0), n) .. tostring(num) + return string.rep(tostring(0), n) .. tostring(num) end --- Iterator function that returns values from a lower value up to a greater @@ -106,11 +106,11 @@ end -- @arg padding number of digits to pad up to. -- @return string current value. local numiterator = function(minval, maxval, padding) - local i = minval - 1 - return function() - i = i + 1 - if i <= maxval then return padnum(i, padding), '' end - end + local i = minval - 1 + return function() + i = i + 1 + if i <= maxval then return padnum(i, padding), '' end + end end --- Iterator function that returns lines from a file @@ -118,19 +118,19 @@ end -- @return status false if error. -- @return string current line. local useriterator = function(list) - local f = nmap.fetchfile(list) or list - if not f then - return false, ("\n ERROR: Couldn't find %s"):format(list) - end - f = io.open(f) - if ( not(f) ) then - return false, ("\n ERROR: Failed to open %s"):format(list) - end - return function() - for line in f:lines() do - return line - end + local f = nmap.fetchfile(list) or list + if not f then + return false, ("\n ERROR: Couldn't find %s"):format(list) + end + f = io.open(f) + if ( not(f) ) then + return false, ("\n ERROR: Failed to open %s"):format(list) + end + return function() + for line in f:lines() do + return line end + end end --- function that tests for 404 status code when sending a REGISTER request @@ -138,128 +138,128 @@ end -- @arg host Target host table. -- @arg port Target port table. local test404 = function(host, port) - local session, status, randext, response - -- Random extension - randext = math.random(1234567,987654321) + local session, status, randext, response + -- Random extension + randext = math.random(1234567,987654321) - session = sip.Session:new(host, port) - status = session:connect() - if not status then - return false, "ERROR: Failed to connect to the SIP server." - end + session = sip.Session:new(host, port) + status = session:connect() + if not status then + return false, "ERROR: Failed to connect to the SIP server." + end - status, response = registerext(session, randext) - if not status then - return false, "ERROR: No response from the SIP server." - end - if response:getErrorCode() ~= 404 then - return false, "Server not returning 404 for random extension." - end - return true + status, response = registerext(session, randext) + if not status then + return false, "ERROR: No response from the SIP server." + end + if response:getErrorCode() ~= 404 then + return false, "Server not returning 404 for random extension." + end + return true end Driver = { - new = function(self, host, port) - local o = {} - setmetatable(o, self) - self.__index = self - o.host = host - o.port = port - return o - end, + new = function(self, host, port) + local o = {} + setmetatable(o, self) + self.__index = self + o.host = host + o.port = port + return o + end, - connect = function( self ) - self.session = sip.Session:new(self.host, self.port) - local status = self.session:connect() - if ( not(status) ) then - return false, brute.Error:new( "Couldn't connect to host" ) - end - return true - end, + connect = function( self ) + self.session = sip.Session:new(self.host, self.port) + local status = self.session:connect() + if ( not(status) ) then + return false, brute.Error:new( "Couldn't connect to host" ) + end + return true + end, - login = function( self, username, password) - -- We are using the "password" values instead of the "username" so we - -- could benifit from brute.lua passonly option and setPasswordIterator - -- function, as we are doing usernames enumeration only and not - -- credentials brute forcing. - local status, response, responsecode - -- Send REGISTER request for each extension - status, response = registerext(self.session, password) - if status then - responsecode = response:getErrorCode() - -- If response status code is 401 or 407, then extension exists but - -- requires authentication - if responsecode == sip.Error.UNAUTHORIZED or - responsecode == sip.Error.PROXY_AUTH_REQUIRED then - return true, brute.Account:new(password, " Auth required", '') + login = function( self, username, password) + -- We are using the "password" values instead of the "username" so we + -- could benifit from brute.lua passonly option and setPasswordIterator + -- function, as we are doing usernames enumeration only and not + -- credentials brute forcing. + local status, response, responsecode + -- Send REGISTER request for each extension + status, response = registerext(self.session, password) + if status then + responsecode = response:getErrorCode() + -- If response status code is 401 or 407, then extension exists but + -- requires authentication + if responsecode == sip.Error.UNAUTHORIZED or + responsecode == sip.Error.PROXY_AUTH_REQUIRED then + return true, brute.Account:new(password, " Auth required", '') - -- If response status code is 200, then extension exists - -- and requires no authentication - elseif responsecode == sip.Error.OK then - return true, brute.Account:new(password, " No auth", '') - -- If response status code is 200, then extension exists - -- but access is forbidden. + -- If response status code is 200, then extension exists + -- and requires no authentication + elseif responsecode == sip.Error.OK then + return true, brute.Account:new(password, " No auth", '') + -- If response status code is 200, then extension exists + -- but access is forbidden. - elseif responsecode == sip.Error.FORBIDDEN then - return true, brute.Account:new(password, " Forbidden", '') - end - return false,brute.Error:new( "Not found" ) - else - return false,brute.Error:new( "No response" ) - end - end, + elseif responsecode == sip.Error.FORBIDDEN then + return true, brute.Account:new(password, " Forbidden", '') + end + return false,brute.Error:new( "Not found" ) + else + return false,brute.Error:new( "No response" ) + end + end, - disconnect = function(self) - self.session:close() - return true - end, + disconnect = function(self) + self.session:close() + return true + end, } action = function(host, port) - local result, lthreads = {}, {} - local status, err - local minext = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".minext")) or 0 - local minext = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".minext")) or 0 - local maxext = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".maxext")) or 999 - local padding = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".padding")) or 0 - local users = stdnse.get_script_args(SCRIPT_NAME .. ".users") - local usersfile = stdnse.get_script_args(SCRIPT_NAME .. ".userslist") - or "nselib/data/usernames.lst" + local result, lthreads = {}, {} + local status, err + local minext = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".minext")) or 0 + local minext = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".minext")) or 0 + local maxext = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".maxext")) or 999 + local padding = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".padding")) or 0 + local users = stdnse.get_script_args(SCRIPT_NAME .. ".users") + local usersfile = stdnse.get_script_args(SCRIPT_NAME .. ".userslist") + or "nselib/data/usernames.lst" - -- min extension should be less than max extension. - if minext > maxext then - return "ERROR: maxext should be greater or equal than minext." - end - -- If not set to zero, number of digits to pad up to should have less or - -- equal the number of digits of max extension. - if padding ~= 0 and #tostring(maxext) > padding then - return "ERROR: padding should be greater or equal to number of digits of maxext." + -- min extension should be less than max extension. + if minext > maxext then + return "ERROR: maxext should be greater or equal than minext." + end + -- If not set to zero, number of digits to pad up to should have less or + -- equal the number of digits of max extension. + if padding ~= 0 and #tostring(maxext) > padding then + return "ERROR: padding should be greater or equal to number of digits of maxext." + end + + -- We test for false positives by sending a request for a random extension + -- and checking if it did return a 404. + status, err = test404(host, port) + if not status then + return err + end + + local engine = brute.Engine:new(Driver, host, port) + engine.options.script_name = SCRIPT_NAME + + local iterator = numiterator(minext, maxext, padding) + if users then + local usernames, err = useriterator(usersfile) + if not usernames then + return err end + -- Concat numbers and users iterators + iterator = unpwdb.concat_iterators(iterator, usernames) + end + engine:setPasswordIterator(iterator) + engine.options.passonly = true + status, result = engine:start() - -- We test for false positives by sending a request for a random extension - -- and checking if it did return a 404. - status, err = test404(host, port) - if not status then - return err - end - - local engine = brute.Engine:new(Driver, host, port) - engine.options.script_name = SCRIPT_NAME - - local iterator = numiterator(minext, maxext, padding) - if users then - local usernames, err = useriterator(usersfile) - if not usernames then - return err - end - -- Concat numbers and users iterators - iterator = unpwdb.concat_iterators(iterator, usernames) - end - engine:setPasswordIterator(iterator) - engine.options.passonly = true - status, result = engine:start() - - return result + return result end diff --git a/scripts/smb-enum-users.nse b/scripts/smb-enum-users.nse index fb7c404d9..cc6bbe8fd 100644 --- a/scripts/smb-enum-users.nse +++ b/scripts/smb-enum-users.nse @@ -146,120 +146,120 @@ dependencies = {"smb-brute"} hostrule = function(host) - return smb.get_port(host) ~= nil + return smb.get_port(host) ~= nil end action = function(host) - local i, j - local samr_status = false - local lsa_status = false - local samr_result = "Didn't run" - local lsa_result = "Didn't run" - local names = {} - local names_lookup = {} - local response = {} - local samronly = nmap.registry.args.samronly - local lsaonly = nmap.registry.args.lsaonly - local do_samr = samronly ~= nil or (samronly == nil and lsaonly == nil) - local do_lsa = lsaonly ~= nil or (samronly == nil and lsaonly == nil) + local i, j + local samr_status = false + local lsa_status = false + local samr_result = "Didn't run" + local lsa_result = "Didn't run" + local names = {} + local names_lookup = {} + local response = {} + local samronly = nmap.registry.args.samronly + local lsaonly = nmap.registry.args.lsaonly + local do_samr = samronly ~= nil or (samronly == nil and lsaonly == nil) + local do_lsa = lsaonly ~= nil or (samronly == nil and lsaonly == nil) - -- Try enumerating through SAMR. This is the better source of information, if we can get it. - if(do_samr) then - samr_status, samr_result = msrpc.samr_enum_users(host) + -- Try enumerating through SAMR. This is the better source of information, if we can get it. + if(do_samr) then + samr_status, samr_result = msrpc.samr_enum_users(host) - if(samr_status) then - -- Copy the returned array into the names[] table - stdnse.print_debug(2, "EnumUsers: Received %d names from SAMR", #samr_result) - for i = 1, #samr_result, 1 do - -- Insert the full info into the names list - table.insert(names, samr_result[i]) - -- Set the names_lookup value to 'true' to avoid duplicates - names_lookup[samr_result[i]['name']] = true - end - end - end + if(samr_status) then + -- Copy the returned array into the names[] table + stdnse.print_debug(2, "EnumUsers: Received %d names from SAMR", #samr_result) + for i = 1, #samr_result, 1 do + -- Insert the full info into the names list + table.insert(names, samr_result[i]) + -- Set the names_lookup value to 'true' to avoid duplicates + names_lookup[samr_result[i]['name']] = true + end + end + end - -- Try enumerating through LSA. - if(do_lsa) then - lsa_status, lsa_result = msrpc.lsa_enum_users(host) - if(lsa_status) then - -- Copy the returned array into the names[] table - stdnse.print_debug(2, "EnumUsers: Received %d names from LSA", #lsa_result) - for i = 1, #lsa_result, 1 do - if(lsa_result[i]['name'] ~= nil) then - -- Check if the name already exists - if(not(names_lookup[lsa_result[i]['name']])) then - table.insert(names, lsa_result[i]) - end - end - end - end - end + -- Try enumerating through LSA. + if(do_lsa) then + lsa_status, lsa_result = msrpc.lsa_enum_users(host) + if(lsa_status) then + -- Copy the returned array into the names[] table + stdnse.print_debug(2, "EnumUsers: Received %d names from LSA", #lsa_result) + for i = 1, #lsa_result, 1 do + if(lsa_result[i]['name'] ~= nil) then + -- Check if the name already exists + if(not(names_lookup[lsa_result[i]['name']])) then + table.insert(names, lsa_result[i]) + end + end + end + end + end - -- Check if both failed - if(samr_status == false and lsa_status == false) then - if(string.find(lsa_result, 'ACCESS_DENIED')) then - return stdnse.format_output(false, "Access denied while trying to enumerate users; except against Windows 2000, Guest or better is typically required") - end + -- Check if both failed + if(samr_status == false and lsa_status == false) then + if(string.find(lsa_result, 'ACCESS_DENIED')) then + return stdnse.format_output(false, "Access denied while trying to enumerate users; except against Windows 2000, Guest or better is typically required") + end - return stdnse.format_output(false, {"Couldn't enumerate users", "SAMR returned " .. samr_result, "LSA returned " .. lsa_result}) - end + return stdnse.format_output(false, {"Couldn't enumerate users", "SAMR returned " .. samr_result, "LSA returned " .. lsa_result}) + end - -- Sort them - table.sort(names, function (a, b) return string.lower(a.name) < string.lower(b.name) end) + -- Sort them + table.sort(names, function (a, b) return string.lower(a.name) < string.lower(b.name) end) - -- Break them out by domain - local domains = {} - for _, name in ipairs(names) do - local domain = name['domain'] + -- Break them out by domain + local domains = {} + for _, name in ipairs(names) do + local domain = name['domain'] - -- Make sure the entry in the domains table exists - if(not(domains[domain])) then - domains[domain] = {} - end + -- Make sure the entry in the domains table exists + if(not(domains[domain])) then + domains[domain] = {} + end - table.insert(domains[domain], name) - end + table.insert(domains[domain], name) + end - -- Check if we actually got any names back - if(#names == 0) then - table.insert(response, "Couldn't find any account names, sorry!") - else - -- If we're not verbose, just print out the names. Otherwise, print out everything we can - if(nmap.verbosity() < 1) then - for domain, domain_users in pairs(domains) do - -- Make an impromptu list of users - local names = {} - for _, info in ipairs(domain_users) do - table.insert(names, info['name']) - end + -- Check if we actually got any names back + if(#names == 0) then + table.insert(response, "Couldn't find any account names, sorry!") + else + -- If we're not verbose, just print out the names. Otherwise, print out everything we can + if(nmap.verbosity() < 1) then + for domain, domain_users in pairs(domains) do + -- Make an impromptu list of users + local names = {} + for _, info in ipairs(domain_users) do + table.insert(names, info['name']) + end - -- Add this domain to the response - table.insert(response, string.format("Domain: %s; Users: %s", domain, stdnse.strjoin(", ", names))) - end - else - for domain, domain_users in pairs(domains) do - for _, info in ipairs(domain_users) do - local response_part = {} - response_part['name'] = string.format("%s\\%s (RID: %d)", domain, info['name'], info['rid']) + -- Add this domain to the response + table.insert(response, string.format("Domain: %s; Users: %s", domain, stdnse.strjoin(", ", names))) + end + else + for domain, domain_users in pairs(domains) do + for _, info in ipairs(domain_users) do + local response_part = {} + response_part['name'] = string.format("%s\\%s (RID: %d)", domain, info['name'], info['rid']) - if(info['fullname']) then - table.insert(response_part, string.format("Full name: %s", info['fullname'])) - end - if(info['description']) then - table.insert(response_part, string.format("Description: %s", info['description'])) - end - if(info['flags']) then - table.insert(response_part, string.format("Flags: %s", stdnse.strjoin(", ", info['flags']))) - end + if(info['fullname']) then + table.insert(response_part, string.format("Full name: %s", info['fullname'])) + end + if(info['description']) then + table.insert(response_part, string.format("Description: %s", info['description'])) + end + if(info['flags']) then + table.insert(response_part, string.format("Flags: %s", stdnse.strjoin(", ", info['flags']))) + end - table.insert(response, response_part) - end - end - end - end + table.insert(response, response_part) + end + end + end + end - return stdnse.format_output(true, response) + return stdnse.format_output(true, response) end diff --git a/scripts/smb-mbenum.nse b/scripts/smb-mbenum.nse index d00f75dc8..84abbbd2d 100644 --- a/scripts/smb-mbenum.nse +++ b/scripts/smb-mbenum.nse @@ -42,13 +42,13 @@ Queries information managed by the Windows Master Browser. -- |_ WIN2K3-EPI-1 5.2 EPiServer 2003 frontend server -- -- @args smb-mbenum.format (optional) if set, changes the format of the result --- returned by the script. There are three possible formats: --- 1. Ordered by type horizontally --- 2. Ordered by type vertically --- 3. Ordered by type vertically with details (default) +-- returned by the script. There are three possible formats: +-- 1. Ordered by type horizontally +-- 2. Ordered by type vertically +-- 3. Ordered by type vertically with details (default) -- -- @args smb-mbenum.filter (optional) if set, queries the browser for a --- specific type of server (@see ServerTypes) +-- specific type of server (@see ServerTypes) -- -- @args smb-mbenum.domain (optional) if not specified, lists the domain of the queried browser -- @@ -67,167 +67,167 @@ hostrule = function(host) return smb.get_port(host) ~= nil end local function log(msg) stdnse.print_debug(3, msg) end ServerTypes = { - SV_TYPE_WORKSTATION = 0x00000001, - SV_TYPE_SERVER = 0x00000002, - SV_TYPE_SQLSERVER = 0x00000004, - SV_TYPE_DOMAIN_CTRL = 0x00000008, - SV_TYPE_DOMAIN_BAKCTRL = 0x00000010, - SV_TYPE_TIME_SOURCE = 0x00000020, - SV_TYPE_AFP = 0x00000040, - SV_TYPE_NOVELL = 0x00000080, - SV_TYPE_DOMAIN_MEMBER = 0x00000100, - SV_TYPE_PRINTQ_SERVER = 0x00000200, - SV_TYPE_DIALIN_SERVER = 0x00000400, - SV_TYPE_SERVER_UNIX = 0x00000800, - SV_TYPE_NT = 0x00001000, - SV_TYPE_WFW = 0x00002000, - SV_TYPE_SERVER_MFPN = 0x00004000, - SV_TYPE_SERVER_NT = 0x00008000, - SV_TYPE_POTENTIAL_BROWSER = 0x00010000, - SV_TYPE_BACKUP_BROWSER = 0x00020000, - SV_TYPE_MASTER_BROWSER = 0x00040000, - SV_TYPE_DOMAIN_MASTER = 0x00080000, - SV_TYPE_WINDOWS = 0x00400000, - SV_TYPE_DFS = 0x00800000, - SV_TYPE_CLUSTER_NT = 0x01000000, - SV_TYPE_TERMINALSERVER = 0x02000000, - SV_TYPE_CLUSTER_VS_NT = 0x04000000, - SV_TYPE_DCE = 0x10000000, - SV_TYPE_ALTERNATE_XPORT = 0x20000000, - SV_TYPE_LOCAL_LIST_ONLY = 0x40000000, - SV_TYPE_DOMAIN_ENUM = 0x80000000, - SV_TYPE_ALL = 0xFFFFFFFF + SV_TYPE_WORKSTATION = 0x00000001, + SV_TYPE_SERVER = 0x00000002, + SV_TYPE_SQLSERVER = 0x00000004, + SV_TYPE_DOMAIN_CTRL = 0x00000008, + SV_TYPE_DOMAIN_BAKCTRL = 0x00000010, + SV_TYPE_TIME_SOURCE = 0x00000020, + SV_TYPE_AFP = 0x00000040, + SV_TYPE_NOVELL = 0x00000080, + SV_TYPE_DOMAIN_MEMBER = 0x00000100, + SV_TYPE_PRINTQ_SERVER = 0x00000200, + SV_TYPE_DIALIN_SERVER = 0x00000400, + SV_TYPE_SERVER_UNIX = 0x00000800, + SV_TYPE_NT = 0x00001000, + SV_TYPE_WFW = 0x00002000, + SV_TYPE_SERVER_MFPN = 0x00004000, + SV_TYPE_SERVER_NT = 0x00008000, + SV_TYPE_POTENTIAL_BROWSER = 0x00010000, + SV_TYPE_BACKUP_BROWSER = 0x00020000, + SV_TYPE_MASTER_BROWSER = 0x00040000, + SV_TYPE_DOMAIN_MASTER = 0x00080000, + SV_TYPE_WINDOWS = 0x00400000, + SV_TYPE_DFS = 0x00800000, + SV_TYPE_CLUSTER_NT = 0x01000000, + SV_TYPE_TERMINALSERVER = 0x02000000, + SV_TYPE_CLUSTER_VS_NT = 0x04000000, + SV_TYPE_DCE = 0x10000000, + SV_TYPE_ALTERNATE_XPORT = 0x20000000, + SV_TYPE_LOCAL_LIST_ONLY = 0x40000000, + SV_TYPE_DOMAIN_ENUM = 0x80000000, + SV_TYPE_ALL = 0xFFFFFFFF } TypeNames = { - SV_TYPE_WORKSTATION = { long = "Workstation", short = "WKS" }, - SV_TYPE_SERVER = { long = "Server service", short = "SRVSVC" }, - SV_TYPE_SQLSERVER = { long = "SQL Server", short = "MSSQL" }, - SV_TYPE_DOMAIN_CTRL = { long = "Domain Controller", short = "DC" }, - SV_TYPE_DOMAIN_BAKCTRL = { long = "Backup Domain Controller", short = "BDC" }, - SV_TYPE_TIME_SOURCE = { long = "Time Source", short = "TIME" }, - SV_TYPE_AFP = { long = "Apple File Protocol Server", short = "AFP" }, - SV_TYPE_NOVELL = { long = "Novell Server", short = "NOVELL" }, - SV_TYPE_DOMAIN_MEMBER = { long = "LAN Manager Domain Member", short = "MEMB" }, - SV_TYPE_PRINTQ_SERVER = { long = "Print server", short = "PRINT" }, - SV_TYPE_DIALIN_SERVER = { long = "Dial-in server", short = "DIALIN" }, - SV_TYPE_SERVER_UNIX = { long = "Unix server", short = "UNIX" }, - SV_TYPE_NT = { long = "Windows NT/2000/XP/2003 server", short = "NT" }, - SV_TYPE_WFW = { long = "Windows for workgroups", short = "WFW" }, - SV_TYPE_SERVER_MFPN = { long = "Microsoft File and Print for Netware", short="MFPN" }, - SV_TYPE_SERVER_NT = { long = "Server", short = "SRV" }, - SV_TYPE_POTENTIAL_BROWSER = { long = "Potential Browser", short = "POTBRWS" }, - SV_TYPE_BACKUP_BROWSER = { long = "Backup Browser", short = "BCKBRWS"}, - SV_TYPE_MASTER_BROWSER = { long = "Master Browser", short = "MBRWS"}, - SV_TYPE_DOMAIN_MASTER = { long = "Domain Master Browser", short = "DOMBRWS"}, - SV_TYPE_WINDOWS = { long = "Windows 95/98/ME", short="WIN95"}, - SV_TYPE_DFS = { long = "DFS Root", short = "DFS"}, - SV_TYPE_TERMINALSERVER = { long = "Terminal Server", short = "TS" }, + SV_TYPE_WORKSTATION = { long = "Workstation", short = "WKS" }, + SV_TYPE_SERVER = { long = "Server service", short = "SRVSVC" }, + SV_TYPE_SQLSERVER = { long = "SQL Server", short = "MSSQL" }, + SV_TYPE_DOMAIN_CTRL = { long = "Domain Controller", short = "DC" }, + SV_TYPE_DOMAIN_BAKCTRL = { long = "Backup Domain Controller", short = "BDC" }, + SV_TYPE_TIME_SOURCE = { long = "Time Source", short = "TIME" }, + SV_TYPE_AFP = { long = "Apple File Protocol Server", short = "AFP" }, + SV_TYPE_NOVELL = { long = "Novell Server", short = "NOVELL" }, + SV_TYPE_DOMAIN_MEMBER = { long = "LAN Manager Domain Member", short = "MEMB" }, + SV_TYPE_PRINTQ_SERVER = { long = "Print server", short = "PRINT" }, + SV_TYPE_DIALIN_SERVER = { long = "Dial-in server", short = "DIALIN" }, + SV_TYPE_SERVER_UNIX = { long = "Unix server", short = "UNIX" }, + SV_TYPE_NT = { long = "Windows NT/2000/XP/2003 server", short = "NT" }, + SV_TYPE_WFW = { long = "Windows for workgroups", short = "WFW" }, + SV_TYPE_SERVER_MFPN = { long = "Microsoft File and Print for Netware", short="MFPN" }, + SV_TYPE_SERVER_NT = { long = "Server", short = "SRV" }, + SV_TYPE_POTENTIAL_BROWSER = { long = "Potential Browser", short = "POTBRWS" }, + SV_TYPE_BACKUP_BROWSER = { long = "Backup Browser", short = "BCKBRWS"}, + SV_TYPE_MASTER_BROWSER = { long = "Master Browser", short = "MBRWS"}, + SV_TYPE_DOMAIN_MASTER = { long = "Domain Master Browser", short = "DOMBRWS"}, + SV_TYPE_WINDOWS = { long = "Windows 95/98/ME", short="WIN95"}, + SV_TYPE_DFS = { long = "DFS Root", short = "DFS"}, + SV_TYPE_TERMINALSERVER = { long = "Terminal Server", short = "TS" }, } OutputFormat = { - BY_TYPE_H = 1, - BY_TYPE_V = 2, - BY_TYPE_V_DETAILED = 3, + BY_TYPE_H = 1, + BY_TYPE_V = 2, + BY_TYPE_V_DETAILED = 3, } action = function(host, port) - local status, smbstate = smb.start(host) - local err, entries - local path = ("\\\\%s\\IPC$"):format(host.ip) - local detail_level = 1 - local format = stdnse.get_script_args("smb-mbenum.format") or OutputFormat.BY_TYPE_V_DETAILED - local filter = stdnse.get_script_args("smb-mbenum.filter") or ServerTypes.SV_TYPE_ALL - local domain = stdnse.get_script_args("smb-mbenum.domain") + local status, smbstate = smb.start(host) + local err, entries + local path = ("\\\\%s\\IPC$"):format(host.ip) + local detail_level = 1 + local format = stdnse.get_script_args("smb-mbenum.format") or OutputFormat.BY_TYPE_V_DETAILED + local filter = stdnse.get_script_args("smb-mbenum.filter") or ServerTypes.SV_TYPE_ALL + local domain = stdnse.get_script_args("smb-mbenum.domain") - filter = tonumber(filter) or ServerTypes[filter] - format = tonumber(format) + filter = tonumber(filter) or ServerTypes[filter] + format = tonumber(format) - if ( not(filter) ) then - return "\n The argument smb-mbenum.filter contained an invalid value." - end + if ( not(filter) ) then + return "\n The argument smb-mbenum.filter contained an invalid value." + end - if ( not(format) ) then - return "\n The argument smb-mbenum.format contained an invalid value." - end + if ( not(format) ) then + return "\n The argument smb-mbenum.format contained an invalid value." + end - status, err = smb.negotiate_protocol(smbstate, {}) - if ( not(status) ) then - log("ERROR: smb.negotiate_protocol failed") - return "\n ERROR: Failed to connect to browser service" - end + status, err = smb.negotiate_protocol(smbstate, {}) + if ( not(status) ) then + log("ERROR: smb.negotiate_protocol failed") + return "\n ERROR: Failed to connect to browser service" + end - status, err = smb.start_session(smbstate, {}) - if ( not(status) ) then - log("ERROR: smb.negotiate_protocol failed") - return "\n ERROR: Failed to connect to browser service" - end + status, err = smb.start_session(smbstate, {}) + if ( not(status) ) then + log("ERROR: smb.negotiate_protocol failed") + return "\n ERROR: Failed to connect to browser service" + end - status, err = smb.tree_connect(smbstate, path, {}) - if ( not(status) ) then - log("ERROR: smb.negotiate_protocol failed") - return "\n ERROR: Failed to connect to browser service" - end + status, err = smb.tree_connect(smbstate, path, {}) + if ( not(status) ) then + log("ERROR: smb.negotiate_protocol failed") + return "\n ERROR: Failed to connect to browser service" + end - status, entries = msrpc.rap_netserverenum2(smbstate, domain, filter, detail_level) - if ( not(status) ) then - log("ERROR: msrpc.call_lanmanapi failed") - return "\n ERROR: " .. entries - end + status, entries = msrpc.rap_netserverenum2(smbstate, domain, filter, detail_level) + if ( not(status) ) then + log("ERROR: msrpc.call_lanmanapi failed") + return "\n ERROR: " .. entries + end - status, err = smb.tree_disconnect(smbstate) - if ( not(status) ) then log("ERROR: smb.tree_disconnect failed") end + status, err = smb.tree_disconnect(smbstate) + if ( not(status) ) then log("ERROR: smb.tree_disconnect failed") end - status, err = smb.logoff(smbstate) - if ( not(status) ) then log("ERROR: smb.logoff failed") end + status, err = smb.logoff(smbstate) + if ( not(status) ) then log("ERROR: smb.logoff failed") end - status, err = smb.stop(smbstate) - if ( not(status) ) then log("ERROR: smb.stop failed") end + status, err = smb.stop(smbstate) + if ( not(status) ) then log("ERROR: smb.stop failed") end - local results, output = {}, {} - for k, _ in pairs(ServerTypes) do - for _, server in ipairs(entries) do - if ( TypeNames[k] and bit.band(server.type,ServerTypes[k]) == ServerTypes[k] ) then - results[TypeNames[k].long] = results[TypeNames[k].long] or {} - if ( format == OutputFormat.BY_TYPE_V_DETAILED ) then - table.insert(results[TypeNames[k].long], server) - else - table.insert(results[TypeNames[k].long], server.name) - end - end - end - end + local results, output = {}, {} + for k, _ in pairs(ServerTypes) do + for _, server in ipairs(entries) do + if ( TypeNames[k] and bit.band(server.type,ServerTypes[k]) == ServerTypes[k] ) then + results[TypeNames[k].long] = results[TypeNames[k].long] or {} + if ( format == OutputFormat.BY_TYPE_V_DETAILED ) then + table.insert(results[TypeNames[k].long], server) + else + table.insert(results[TypeNames[k].long], server.name) + end + end + end + end - if ( format == OutputFormat.BY_TYPE_H ) then - for k, v in pairs(results) do - local row = ("%s: %s"):format( k, stdnse.strjoin(",", v) ) - table.insert(output, row) - end - table.sort(output) - elseif( format == OutputFormat.BY_TYPE_V ) then - for k, v in pairs(results) do - v.name = k - table.insert(output, v) - end - table.sort(output, function(a,b) return a.name < b.name end) - elseif( format == OutputFormat.BY_TYPE_V_DETAILED ) then - for k, v in pairs(results) do - local cat_tab = tab.new(3) - table.sort(v, function(a,b) return a.name < b.name end ) - for _, server in pairs(v) do - tab.addrow( - cat_tab, - server.name, - ("%d.%d"):format(server.version.major,server.version.minor), - server.comment - ) - end - table.insert(output, { name = k, tab.dump(cat_tab) } ) - end - table.sort(output, function(a,b) return a.name < b.name end) - end + if ( format == OutputFormat.BY_TYPE_H ) then + for k, v in pairs(results) do + local row = ("%s: %s"):format( k, stdnse.strjoin(",", v) ) + table.insert(output, row) + end + table.sort(output) + elseif( format == OutputFormat.BY_TYPE_V ) then + for k, v in pairs(results) do + v.name = k + table.insert(output, v) + end + table.sort(output, function(a,b) return a.name < b.name end) + elseif( format == OutputFormat.BY_TYPE_V_DETAILED ) then + for k, v in pairs(results) do + local cat_tab = tab.new(3) + table.sort(v, function(a,b) return a.name < b.name end ) + for _, server in pairs(v) do + tab.addrow( + cat_tab, + server.name, + ("%d.%d"):format(server.version.major,server.version.minor), + server.comment + ) + end + table.insert(output, { name = k, tab.dump(cat_tab) } ) + end + table.sort(output, function(a,b) return a.name < b.name end) + end - return stdnse.format_output(true, output) + return stdnse.format_output(true, output) end diff --git a/scripts/smb-system-info.nse b/scripts/smb-system-info.nse index cc3bcc97b..383ae3690 100644 --- a/scripts/smb-system-info.nse +++ b/scripts/smb-system-info.nse @@ -61,7 +61,7 @@ dependencies = {"smb-brute"} -- TODO: This script needs some love hostrule = function(host) - return smb.get_port(host) ~= nil + return smb.get_port(host) ~= nil end ---Retrieves the requested value from the registry. @@ -72,178 +72,178 @@ end --@return Status (true or false). --@return The value (if status is true) or an error string (if status is false). local function reg_get_value(smbstate, handle, key, value) - -- Open the key - local status, openkey_result = msrpc.winreg_openkey(smbstate, handle, key) - if(status == false) then - return false, openkey_result - end + -- Open the key + local status, openkey_result = msrpc.winreg_openkey(smbstate, handle, key) + if(status == false) then + return false, openkey_result + end - -- Query the value - local status, queryvalue_result = msrpc.winreg_queryvalue(smbstate, openkey_result['handle'], value) - if(status == false) then - return false, queryvalue_result - end + -- Query the value + local status, queryvalue_result = msrpc.winreg_queryvalue(smbstate, openkey_result['handle'], value) + if(status == false) then + return false, queryvalue_result + end - -- Close the key - local status, closekey_result = msrpc.winreg_closekey(smbstate, openkey_result['handle'], value) - if(status == false) then - return false, closekey_result - end + -- Close the key + local status, closekey_result = msrpc.winreg_closekey(smbstate, openkey_result['handle'], value) + if(status == false) then + return false, closekey_result + end - return true, queryvalue_result['value'] + return true, queryvalue_result['value'] end local function get_info_registry(host) - local result = {} + local result = {} - -- Create the SMB session - local status, smbstate = msrpc.start_smb(host, msrpc.WINREG_PATH) - if(status == false) then - return false, smbstate - end + -- Create the SMB session + local status, smbstate = msrpc.start_smb(host, msrpc.WINREG_PATH) + if(status == false) then + return false, smbstate + end - -- Bind to WINREG service - local status, bind_result = msrpc.bind(smbstate, msrpc.WINREG_UUID, msrpc.WINREG_VERSION, nil) - if(status == false) then - msrpc.stop_smb(smbstate) - return false, bind_result - end + -- Bind to WINREG service + local status, bind_result = msrpc.bind(smbstate, msrpc.WINREG_UUID, msrpc.WINREG_VERSION, nil) + if(status == false) then + msrpc.stop_smb(smbstate) + return false, bind_result + end - -- Open HKEY_LOCAL_MACHINE - local status, openhklm_result = msrpc.winreg_openhklm(smbstate) - if(status == false) then - msrpc.stop_smb(smbstate) - return false, openhklm_result - end + -- Open HKEY_LOCAL_MACHINE + local status, openhklm_result = msrpc.winreg_openhklm(smbstate) + if(status == false) then + msrpc.stop_smb(smbstate) + return false, openhklm_result + end - -- Processor information - result['status-number_of_processors'], result['number_of_processors'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", "NUMBER_OF_PROCESSORS") - if(result['status-number_of_processors'] == false) then - result['number_of_processors'] = 0 - end - result['status-os'], result['os'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", "OS") - result['status-path'], result['path'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", "Path") - result['status-processor_architecture'], result['processor_architecture'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", "PROCESSOR_ARCHITECTURE") - result['status-processor_identifier'], result['processor_identifier'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", "PROCESSOR_IDENTIFIER") - result['status-processor_level'], result['processor_level'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", "PROCESSOR_LEVEL") - result['status-processor_revision'], result['processor_revision'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", "PROCESSOR_REVISION") + -- Processor information + result['status-number_of_processors'], result['number_of_processors'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", "NUMBER_OF_PROCESSORS") + if(result['status-number_of_processors'] == false) then + result['number_of_processors'] = 0 + end + result['status-os'], result['os'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", "OS") + result['status-path'], result['path'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", "Path") + result['status-processor_architecture'], result['processor_architecture'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", "PROCESSOR_ARCHITECTURE") + result['status-processor_identifier'], result['processor_identifier'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", "PROCESSOR_IDENTIFIER") + result['status-processor_level'], result['processor_level'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", "PROCESSOR_LEVEL") + result['status-processor_revision'], result['processor_revision'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", "PROCESSOR_REVISION") - -- remove trailing zero terminator - local num_procs = result['number_of_processors']:match("^[^%z]*") + -- remove trailing zero terminator + local num_procs = result['number_of_processors']:match("^[^%z]*") - for i = 0, tonumber(num_procs) - 1, 1 do - result['status-~mhz'..i], result['~mhz' .. i] = reg_get_value(smbstate, openhklm_result['handle'], "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\" .. i, "~MHz") - result['status-identifier'..i], result['identifier' .. i] = reg_get_value(smbstate, openhklm_result['handle'], "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\" .. i, "Identifier") - result['status-processornamestring'..i], result['processornamestring' .. i] = reg_get_value(smbstate, openhklm_result['handle'], "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\" .. i, "ProcessorNameString") - result['status-vendoridentifier'..i], result['vendoridentifier' .. i] = reg_get_value(smbstate, openhklm_result['handle'], "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\" .. i, "VendorIdentifier") - end --- status, result['physicalmemory'] = reg_get_value(smbstate, openhklm_result['handle'], "HARDWARE\\ResourceMap\\System Resources\\Physical Memory", ".Translated") + for i = 0, tonumber(num_procs) - 1, 1 do + result['status-~mhz'..i], result['~mhz' .. i] = reg_get_value(smbstate, openhklm_result['handle'], "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\" .. i, "~MHz") + result['status-identifier'..i], result['identifier' .. i] = reg_get_value(smbstate, openhklm_result['handle'], "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\" .. i, "Identifier") + result['status-processornamestring'..i], result['processornamestring' .. i] = reg_get_value(smbstate, openhklm_result['handle'], "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\" .. i, "ProcessorNameString") + result['status-vendoridentifier'..i], result['vendoridentifier' .. i] = reg_get_value(smbstate, openhklm_result['handle'], "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\" .. i, "VendorIdentifier") + end + -- status, result['physicalmemory'] = reg_get_value(smbstate, openhklm_result['handle'], "HARDWARE\\ResourceMap\\System Resources\\Physical Memory", ".Translated") - -- TODO: Known DLLs? + -- TODO: Known DLLs? - -- Paging file - result['status-pagingfiles'], result['pagingfiles'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management", "PagingFiles") - result['status-clearpagefileatshutdown'], result['clearpagefileatshutdown'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management", "ClearPageFileAtShutdown") + -- Paging file + result['status-pagingfiles'], result['pagingfiles'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management", "PagingFiles") + result['status-clearpagefileatshutdown'], result['clearpagefileatshutdown'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management", "ClearPageFileAtShutdown") - -- OS Information - result['status-csdversion'], result['csdversion'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "CSDVersion") - if(result['status-csdversion'] == false) then - result['csdversion'] = "(no service packs)" - end - result['status-currentbuildnumber'], result['currentbuildnumber'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "CurrentBuildNumber") - result['status-currenttype'], result['currenttype'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "CurrentType") - result['status-currentversion'], result['currentversion'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "CurrentVersion") - result['status-installdate'], result['installdate'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "InstallDate") - if(result['status-installdate'] ~= false) then - result['installdate'] = os.date("%Y-%m-%d %H:%M:%S", result['installdate']) - end + -- OS Information + result['status-csdversion'], result['csdversion'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "CSDVersion") + if(result['status-csdversion'] == false) then + result['csdversion'] = "(no service packs)" + end + result['status-currentbuildnumber'], result['currentbuildnumber'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "CurrentBuildNumber") + result['status-currenttype'], result['currenttype'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "CurrentType") + result['status-currentversion'], result['currentversion'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "CurrentVersion") + result['status-installdate'], result['installdate'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "InstallDate") + if(result['status-installdate'] ~= false) then + result['installdate'] = os.date("%Y-%m-%d %H:%M:%S", result['installdate']) + end - result['status-productname'], result['productname'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "Productname") - result['status-registeredowner'], result['registeredowner'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "RegisteredOwner") - result['status-registeredorganization'], result['registeredorganization'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "RegisteredOrganization") - result['status-systemroot'], result['systemroot'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "SystemRoot") - result['status-producttype'], result['producttype'] = reg_get_value(smbstate, openhklm_result['handle'], "System\\CurrentControlSet\\Control\\ProductOptions", "ProductType") - result['status-productsuite'], result['productsuite'] = reg_get_value(smbstate, openhklm_result['handle'], "System\\CurrentControlSet\\Control\\ProductOptions", "ProductSuite") + result['status-productname'], result['productname'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "Productname") + result['status-registeredowner'], result['registeredowner'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "RegisteredOwner") + result['status-registeredorganization'], result['registeredorganization'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "RegisteredOrganization") + result['status-systemroot'], result['systemroot'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Windows NT\\CurrentVersion", "SystemRoot") + result['status-producttype'], result['producttype'] = reg_get_value(smbstate, openhklm_result['handle'], "System\\CurrentControlSet\\Control\\ProductOptions", "ProductType") + result['status-productsuite'], result['productsuite'] = reg_get_value(smbstate, openhklm_result['handle'], "System\\CurrentControlSet\\Control\\ProductOptions", "ProductSuite") - -- Driver information - result['status-video_driverdesc'], result['video_driverdesc'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000", "DriverDesc") + -- Driver information + result['status-video_driverdesc'], result['video_driverdesc'] = reg_get_value(smbstate, openhklm_result['handle'], "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000", "DriverDesc") - -- Software versions - result['status-ie_version'], result['ie_version'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Internet Explorer\\Version Vector", "IE") - result['status-ff_version'], result['ff_version'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Mozilla\\Mozilla Firefox", "CurrentVersion") - if(result['status-ff_version'] == false) then - result['ff_version'] = "" - end + -- Software versions + result['status-ie_version'], result['ie_version'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Microsoft\\Internet Explorer\\Version Vector", "IE") + result['status-ff_version'], result['ff_version'] = reg_get_value(smbstate, openhklm_result['handle'], "Software\\Mozilla\\Mozilla Firefox", "CurrentVersion") + if(result['status-ff_version'] == false) then + result['ff_version'] = "" + end - msrpc.stop_smb(smbstate) + msrpc.stop_smb(smbstate) - return true, result + return true, result end action = function(host) - local status, result = get_info_registry(host) + local status, result = get_info_registry(host) - if(status == false) then - return stdnse.format_output(false, result) - end + if(status == false) then + return stdnse.format_output(false, result) + end - local response = {} + local response = {} - if(result['status-os'] == true) then - local osdetails = {} - osdetails['name'] = "OS Details" - table.insert(osdetails, string.format("%s %s (%s %s build %s)", result['productname'], result['csdversion'], result['producttype'], result['currentversion'], result['currentbuildnumber'])) - table.insert(osdetails, string.format("Installed on %s", result['installdate'])) - table.insert(osdetails, string.format("Registered to %s (organization: %s)", result['registeredowner'], result['registeredorganization'])) - table.insert(osdetails, string.format("Path: %s", result['path'])) - table.insert(osdetails, string.format("Systemroot: %s", result['systemroot'])) - table.insert(osdetails, string.format("Page files: %s (cleared at shutdown => %s)", result['pagingfiles'], result['clearpagefileatshutdown'])) - table.insert(response, osdetails) + if(result['status-os'] == true) then + local osdetails = {} + osdetails['name'] = "OS Details" + table.insert(osdetails, string.format("%s %s (%s %s build %s)", result['productname'], result['csdversion'], result['producttype'], result['currentversion'], result['currentbuildnumber'])) + table.insert(osdetails, string.format("Installed on %s", result['installdate'])) + table.insert(osdetails, string.format("Registered to %s (organization: %s)", result['registeredowner'], result['registeredorganization'])) + table.insert(osdetails, string.format("Path: %s", result['path'])) + table.insert(osdetails, string.format("Systemroot: %s", result['systemroot'])) + table.insert(osdetails, string.format("Page files: %s (cleared at shutdown => %s)", result['pagingfiles'], result['clearpagefileatshutdown'])) + table.insert(response, osdetails) - local hardware = {} - hardware['name'] = "Hardware" - -- remove trailing zero terminator - local num_procs = result['number_of_processors']:match("^[^%z]*") - for i = 0, tonumber(num_procs) - 1, 1 do - if(result['status-processornamestring'..i] == false) then - result['status-processornamestring'..i] = "Unknown" - end + local hardware = {} + hardware['name'] = "Hardware" + -- remove trailing zero terminator + local num_procs = result['number_of_processors']:match("^[^%z]*") + for i = 0, tonumber(num_procs) - 1, 1 do + if(result['status-processornamestring'..i] == false) then + result['status-processornamestring'..i] = "Unknown" + end - local processor = {} - processor['name'] = string.format("CPU %d: %s [%dmhz %s]", i, string.gsub(result['processornamestring'..i], ' ', ''), result['~mhz'..i], result['vendoridentifier'..i]) - table.insert(processor, string.format("Identifier %d: %s", i, result['identifier'..i])) - table.insert(hardware, processor) - end - table.insert(hardware, string.format("Video driver: %s", result['video_driverdesc'])) - table.insert(response, hardware) + local processor = {} + processor['name'] = string.format("CPU %d: %s [%dmhz %s]", i, string.gsub(result['processornamestring'..i], ' ', ''), result['~mhz'..i], result['vendoridentifier'..i]) + table.insert(processor, string.format("Identifier %d: %s", i, result['identifier'..i])) + table.insert(hardware, processor) + end + table.insert(hardware, string.format("Video driver: %s", result['video_driverdesc'])) + table.insert(response, hardware) - local browsers = {} - browsers['name'] = "Browsers" - table.insert(browsers, string.format("Internet Explorer %s", result['ie_version'])) - if(result['status-ff_version']) then - table.insert(browsers, string.format("Firefox %s", result['ff_version'])) - end - table.insert(response, browsers) + local browsers = {} + browsers['name'] = "Browsers" + table.insert(browsers, string.format("Internet Explorer %s", result['ie_version'])) + if(result['status-ff_version']) then + table.insert(browsers, string.format("Firefox %s", result['ff_version'])) + end + table.insert(response, browsers) - return stdnse.format_output(true, response) - elseif(result['status-productname'] == true) then + return stdnse.format_output(true, response) + elseif(result['status-productname'] == true) then - local osdetails = {} - osdetails['name'] = 'OS Details' - osdetails['warning'] = "Access was denied for certain values; try an administrative account for more complete information" + local osdetails = {} + osdetails['name'] = 'OS Details' + osdetails['warning'] = "Access was denied for certain values; try an administrative account for more complete information" - table.insert(osdetails, string.format("%s %s (%s %s build %s)", result['productname'], result['csdversion'], result['producttype'], result['currentversion'], result['currentbuildnumber'])) - table.insert(osdetails, string.format("Installed on %s", result['installdate'])) - table.insert(osdetails, string.format("Registered to %s (organization: %s)", result['registeredowner'], result['registeredorganization'])) - table.insert(osdetails, string.format("Systemroot: %s", result['systemroot'])) - table.insert(response, osdetails) + table.insert(osdetails, string.format("%s %s (%s %s build %s)", result['productname'], result['csdversion'], result['producttype'], result['currentversion'], result['currentbuildnumber'])) + table.insert(osdetails, string.format("Installed on %s", result['installdate'])) + table.insert(osdetails, string.format("Registered to %s (organization: %s)", result['registeredowner'], result['registeredorganization'])) + table.insert(osdetails, string.format("Systemroot: %s", result['systemroot'])) + table.insert(response, osdetails) - return stdnse.format_output(true, response) - end + return stdnse.format_output(true, response) + end - return stdnse.format_output(false, "Account being used was unable to probe for information, try using an administrative account") + return stdnse.format_output(false, "Account being used was unable to probe for information, try using an administrative account") end diff --git a/scripts/snmp-ios-config.nse b/scripts/snmp-ios-config.nse index d9956c47d..67b0f4b02 100644 --- a/scripts/snmp-ios-config.nse +++ b/scripts/snmp-ios-config.nse @@ -49,163 +49,163 @@ portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"}) local try local function sendrequest(socket, oid, setparam) - local payload - local options = {} - options.reqId = 28428 -- unnecessary? - payload = snmp.encode(snmp.buildPacket(snmp.buildSetRequest(options, oid,setparam))) + local payload + local options = {} + options.reqId = 28428 -- unnecessary? + payload = snmp.encode(snmp.buildPacket(snmp.buildSetRequest(options, oid,setparam))) - try(socket:send(payload)) + try(socket:send(payload)) - -- read in any response we might get - local status, response = socket:receive() - if ( not(status) ) then return status, response end + -- read in any response we might get + local status, response = socket:receive() + if ( not(status) ) then return status, response end - local result = snmp.fetchFirst(response) - return true + local result = snmp.fetchFirst(response) + return true end --- -- Sends SNMP packets to host and reads responses action = function(host, port) - local tftproot = stdnse.get_script_args("snmp-ios-config.tftproot") + local tftproot = stdnse.get_script_args("snmp-ios-config.tftproot") - if ( tftproot and not( tftproot:match("[\\/]+$") ) ) then - return "ERROR: tftproot needs to end with slash" - end + if ( tftproot and not( tftproot:match("[\\/]+$") ) ) then + return "ERROR: tftproot needs to end with slash" + end -- create the socket used for our connection - local socket = nmap.new_socket() + local socket = nmap.new_socket() - -- set a reasonable timeout value - socket:set_timeout(5000) + -- set a reasonable timeout value + socket:set_timeout(5000) -- do some exception handling / cleanup local catch = function() socket:close() end try = nmap.new_try(catch) - -- connect to the potential SNMP system - try(socket:connect(host.ip, port.number, "udp")) + -- connect to the potential SNMP system + try(socket:connect(host.ip, port.number, "udp")) - local status, tftpserver, _, _, _ = socket:get_info() - if( not(status) ) then - return "ERROR: Failed to determin local ip" - end + local status, tftpserver, _, _, _ = socket:get_info() + if( not(status) ) then + return "ERROR: Failed to determin local ip" + end - -- build a SNMP v1 packet - -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.2.9999 (ConfigCopyProtocol is set to TFTP [1] ) + -- build a SNMP v1 packet + -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.2.9999 (ConfigCopyProtocol is set to TFTP [1] ) - local request = sendrequest(socket, ".1.3.6.1.4.1.9.9.96.1.1.1.1.2.9999",1) + local request = sendrequest(socket, ".1.3.6.1.4.1.9.9.96.1.1.1.1.2.9999",1) - -- Fail silently if the first request doesn't get a proper response - if ( not(request) ) then return end + -- Fail silently if the first request doesn't get a proper response + if ( not(request) ) then return end - -- since we got something back, the port is definitely open - nmap.set_port_state(host, port, "open") + -- since we got something back, the port is definitely open + nmap.set_port_state(host, port, "open") - ------------------------------------------------- - -- build a SNMP v1 packet - -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.3 (SourceFileType is set to running-config [4] ) + ------------------------------------------------- + -- build a SNMP v1 packet + -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.3 (SourceFileType is set to running-config [4] ) - request = sendrequest(socket, ".1.3.6.1.4.1.9.9.96.1.1.1.1.3.9999",4) + request = sendrequest(socket, ".1.3.6.1.4.1.9.9.96.1.1.1.1.3.9999",4) - ------------------------------------------------- - -- build a SNMP v1 packet - -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.4 (DestinationFileType is set to networkfile [1] ) + ------------------------------------------------- + -- build a SNMP v1 packet + -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.4 (DestinationFileType is set to networkfile [1] ) - request = sendrequest(socket, ".1.3.6.1.4.1.9.9.96.1.1.1.1.4.9999",1) + request = sendrequest(socket, ".1.3.6.1.4.1.9.9.96.1.1.1.1.4.9999",1) - ------------------------------------------------- - -- build a SNMP v1 packet - -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.15 (ServerAddress is set to the IP address of the TFTP server ) + ------------------------------------------------- + -- build a SNMP v1 packet + -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.15 (ServerAddress is set to the IP address of the TFTP server ) - local tbl = {} - tbl._snmp = '40' - for octet in tftpserver:gmatch("%d+") do - table.insert(tbl, octet) - end + local tbl = {} + tbl._snmp = '40' + for octet in tftpserver:gmatch("%d+") do + table.insert(tbl, octet) + end - request = sendrequest(socket, nil, { { snmp.str2oid(".1.3.6.1.4.1.9.9.96.1.1.1.1.5.9999"), tbl } } ) - -- request = sendrequest(".1.3.6.1.4.1.9.9.96.1.1.1.1.5.9999",tftpserver) + request = sendrequest(socket, nil, { { snmp.str2oid(".1.3.6.1.4.1.9.9.96.1.1.1.1.5.9999"), tbl } } ) + -- request = sendrequest(".1.3.6.1.4.1.9.9.96.1.1.1.1.5.9999",tftpserver) - ------------------------------------------------- - -- build a SNMP v1 packet - -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.15 (ServerAddressType is set 1 for ipv4 ) - -- more options - 1:ipv4, 2:ipv6, 3:ipv4z, 4:ipv6z, 16:dns + ------------------------------------------------- + -- build a SNMP v1 packet + -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.15 (ServerAddressType is set 1 for ipv4 ) + -- more options - 1:ipv4, 2:ipv6, 3:ipv4z, 4:ipv6z, 16:dns - request = sendrequest(socket, ".1.3.6.1.4.1.9.9.96.1.1.1.1.15.9999",1) + request = sendrequest(socket, ".1.3.6.1.4.1.9.9.96.1.1.1.1.15.9999",1) - ------------------------------------------------- - -- build a SNMP v1 packet - -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.16 (ServerAddress is set to the IP address of the TFTP server ) + ------------------------------------------------- + -- build a SNMP v1 packet + -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.16 (ServerAddress is set to the IP address of the TFTP server ) - request = sendrequest(socket, ".1.3.6.1.4.1.9.9.96.1.1.1.1.16.9999",tftpserver) + request = sendrequest(socket, ".1.3.6.1.4.1.9.9.96.1.1.1.1.16.9999",tftpserver) - ------------------------------------------------- - -- build a SNMP v1 packet - -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.6 (CopyFilename is set to IP-config) + ------------------------------------------------- + -- build a SNMP v1 packet + -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.6 (CopyFilename is set to IP-config) - request = sendrequest(socket, ".1.3.6.1.4.1.9.9.96.1.1.1.1.6.9999",host.ip .. "-config") + request = sendrequest(socket, ".1.3.6.1.4.1.9.9.96.1.1.1.1.6.9999",host.ip .. "-config") - ------------------------------------------------- - -- build a SNMP v1 packet - -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.14 (Start copying by setting CopyStatus to active [1]) - -- more options: 1:active, 2:notInService, 3:notReady, 4:createAndGo, 5:createAndWait, 6:destroy + ------------------------------------------------- + -- build a SNMP v1 packet + -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.14 (Start copying by setting CopyStatus to active [1]) + -- more options: 1:active, 2:notInService, 3:notReady, 4:createAndGo, 5:createAndWait, 6:destroy - request = sendrequest(socket, ".1.3.6.1.4.1.9.9.96.1.1.1.1.14.9999",1) + request = sendrequest(socket, ".1.3.6.1.4.1.9.9.96.1.1.1.1.14.9999",1) - -- wait for sometime and print the status of filetransfer - tftp.start() - local status, infile = tftp.waitFile(host.ip .. "-config", 10) + -- wait for sometime and print the status of filetransfer + tftp.start() + local status, infile = tftp.waitFile(host.ip .. "-config", 10) - -- build a SNMP v1 packet - -- get value: .1.3.6.1.4.1.9.9.96.1.1.1.1.10 (Check the status of filetransfer) 1:waiting, 2:running, 3:successful, 4:failed + -- build a SNMP v1 packet + -- get value: .1.3.6.1.4.1.9.9.96.1.1.1.1.10 (Check the status of filetransfer) 1:waiting, 2:running, 3:successful, 4:failed - local options = {} - options.reqId = 28428 - local payload = snmp.encode(snmp.buildPacket(snmp.buildGetRequest(options, ".1.3.6.1.4.1.9.9.96.1.1.1.1.10.9999"))) + local options = {} + options.reqId = 28428 + local payload = snmp.encode(snmp.buildPacket(snmp.buildGetRequest(options, ".1.3.6.1.4.1.9.9.96.1.1.1.1.10.9999"))) - try(socket:send(payload)) + try(socket:send(payload)) - local status - local response - -- read in any response we might get - status, response = socket:receive() + local status + local response + -- read in any response we might get + status, response = socket:receive() - if (not status) or (response == "TIMEOUT") then - return "\n ERROR: Failed to receive cisco configuration file" - end + if (not status) or (response == "TIMEOUT") then + return "\n ERROR: Failed to receive cisco configuration file" + end - local result - result = snmp.fetchFirst(response) + local result + result = snmp.fetchFirst(response) - if result == 3 then - result = ( infile and infile:getContent() ) + if result == 3 then + result = ( infile and infile:getContent() ) - if ( tftproot ) then - local fname = tftproot .. stdnse.filename_escape(host.ip .. "-config") - local file, err = io.open(fname, "w") - if ( file ) then - file:write(result) - file:close() - else - return "\n ERROR: " .. file - end - result = ("\n Configuration saved to (%s)"):format(fname) - end - else - result = "Not successful! error code: " .. result .. " (1:waiting, 2:running, 3:successful, 4:failed)" - end + if ( tftproot ) then + local fname = tftproot .. stdnse.filename_escape(host.ip .. "-config") + local file, err = io.open(fname, "w") + if ( file ) then + file:write(result) + file:close() + else + return "\n ERROR: " .. file + end + result = ("\n Configuration saved to (%s)"):format(fname) + end + else + result = "Not successful! error code: " .. result .. " (1:waiting, 2:running, 3:successful, 4:failed)" + end - ------------------------------------------------- - -- build a SNMP v1 packet - -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.14 (Destroy settings by setting CopyStatus to destroy [6]) + ------------------------------------------------- + -- build a SNMP v1 packet + -- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.14 (Destroy settings by setting CopyStatus to destroy [6]) - request = sendrequest(socket, ".1.3.6.1.4.1.9.9.96.1.1.1.1.14.9999",6) + request = sendrequest(socket, ".1.3.6.1.4.1.9.9.96.1.1.1.1.14.9999",6) - try(socket:close()) + try(socket:close()) - return result + return result end diff --git a/scripts/socks-open-proxy.nse b/scripts/socks-open-proxy.nse index 2fa5eec60..56218a204 100644 --- a/scripts/socks-open-proxy.nse +++ b/scripts/socks-open-proxy.nse @@ -35,7 +35,7 @@ argument. -- --@usage -- nmap --script=socks-open-proxy \ --- --script-args proxy.url=,proxy.pattern= +-- --script-args proxy.url=,proxy.pattern= author = "Joao Correa" license = "Same as Nmap--See http://nmap.org/book/man-legal.html" @@ -159,7 +159,7 @@ local function default_test(host, port) end portrule = shortport.port_or_service({1080, 9050}, - {"socks", "socks4", "socks5", "tor-socks"}) + {"socks", "socks4", "socks5", "tor-socks"}) action = function(host, port) local supported_versions diff --git a/scripts/ssh2-enum-algos.nse b/scripts/ssh2-enum-algos.nse index 30102c261..d03053c2f 100644 --- a/scripts/ssh2-enum-algos.nse +++ b/scripts/ssh2-enum-algos.nse @@ -108,36 +108,36 @@ portrule = shortport.port_or_service(22, "ssh") -- algorithm name-lists are identical between the server-to-client and -- client-to-server types. Note that this simply modifies the passed tables. local combine_types = function(parsed, lists) - local doubles = { - "encryption_algorithms", - "mac_algorithms", - "compression_algorithms" - } + local doubles = { + "encryption_algorithms", + "mac_algorithms", + "compression_algorithms" + } - for _, i in ipairs(doubles) do - local c2s = i .. "_client_to_server" - local s2c = i .. "_server_to_client" + for _, i in ipairs(doubles) do + local c2s = i .. "_client_to_server" + local s2c = i .. "_server_to_client" - if parsed[c2s] == parsed[s2c] then - parsed[i] = parsed[c2s] - parsed[c2s] = nil - parsed[s2c] = nil - table.insert(lists, i) - else - table.insert(lists, c2s) - table.insert(lists, s2c) - end - end + if parsed[c2s] == parsed[s2c] then + parsed[i] = parsed[c2s] + parsed[c2s] = nil + parsed[s2c] = nil + table.insert(lists, i) + else + table.insert(lists, c2s) + table.insert(lists, s2c) + end + end end -- Build and return the output table local output = function(parsed, lists) - local out = stdnse.output_table() + local out = stdnse.output_table() - for _, l in ipairs(lists) do - local v = parsed[l] - local a = v:len() > 0 and stdnse.strsplit(",", v) or {} - if nmap.verbosity() > 0 then + for _, l in ipairs(lists) do + local v = parsed[l] + local a = v:len() > 0 and stdnse.strsplit(",", v) or {} + if nmap.verbosity() > 0 then setmetatable(a, { __tostring = function(t) return string.format("(%d)\n %s", #t, table.concat(t, "\n ")) @@ -149,70 +149,70 @@ local output = function(parsed, lists) return string.format("(%d)", #t) end }) - end + end out[l] = a - end + end - return out + return out end action = function(host, port) - local sock = nmap.new_socket() - local status = sock:connect(host, port) + local sock = nmap.new_socket() + local status = sock:connect(host, port) - if not status then - return - end + if not status then + return + end - status = sock:receive_lines(1) - if not status then - sock:close() - return - end + status = sock:receive_lines(1) + if not status then + sock:close() + return + end - status = sock:send("SSH-2.0-Nmap-SSH2-Enum-Algos\r\n") - if not status then - sock:close() - return - end + status = sock:send("SSH-2.0-Nmap-SSH2-Enum-Algos\r\n") + if not status then + sock:close() + return + end - local ssh = ssh2.transport + local ssh = ssh2.transport - -- I would think that the server would send its kex data right after - -- receiving and verifying our protocol id string above, then we could - -- just use it here, but I've seen no definitive documentation saying - -- that we don't ever send ours first. All I've seen is that if the - -- server doesn't care about compatibility with older clients then it - -- MAY send its kex data after the protocol id string. So I guess I'll - -- send it here until I know for sure (removing this send works against - -- OpenSSH though). - local pkt = ssh.build(ssh.kex_init()) + -- I would think that the server would send its kex data right after + -- receiving and verifying our protocol id string above, then we could + -- just use it here, but I've seen no definitive documentation saying + -- that we don't ever send ours first. All I've seen is that if the + -- server doesn't care about compatibility with older clients then it + -- MAY send its kex data after the protocol id string. So I guess I'll + -- send it here until I know for sure (removing this send works against + -- OpenSSH though). + local pkt = ssh.build(ssh.kex_init()) - status = sock:send(pkt) - if not status then - sock:close() - return - end + status = sock:send(pkt) + if not status then + sock:close() + return + end - local status, response = ssh.receive_packet(sock) + local status, response = ssh.receive_packet(sock) - sock:close() + sock:close() - if not status then - return - end + if not status then + return + end - local parsed = ssh.parse_kex_init(ssh.payload(response)) + local parsed = ssh.parse_kex_init(ssh.payload(response)) - local lists = { - "kex_algorithms", - "server_host_key_algorithms" - -- Other types will be added below in combine_types() - } + local lists = { + "kex_algorithms", + "server_host_key_algorithms" + -- Other types will be added below in combine_types() + } - -- Modifies tables - combine_types(parsed, lists) + -- Modifies tables + combine_types(parsed, lists) - return output(parsed, lists) + return output(parsed, lists) end diff --git a/scripts/sslv2.nse b/scripts/sslv2.nse index 0b56ce3e8..7a575259b 100644 --- a/scripts/sslv2.nse +++ b/scripts/sslv2.nse @@ -46,193 +46,193 @@ portrule = shortport.ssl local hex2dec = function(hex) - local byte1, byte2; + local byte1, byte2; - byte1 = string.byte(hex, 1); - byte2 = string.byte(hex, 2); + byte1 = string.byte(hex, 1); + byte2 = string.byte(hex, 2); - if (byte1 == nil or byte2 == nil) then return 0; end; + if (byte1 == nil or byte2 == nil) then return 0; end; - return (byte1 * 256) + byte2; + return (byte1 * 256) + byte2; end local ciphers = function(cipher_list, len) --- returns names of ciphers supported by the server + -- returns names of ciphers supported by the server local seen = {} - local available_ciphers = {} - local idx = 0; + local available_ciphers = {} + local idx = 0; - local ssl_ciphers = { --- (cut down) table of codes with their corresponding ciphers. --- inspired by Wireshark's 'epan/dissectors/packet-ssl-utils.h' - [0x010080] = "SSL2_RC4_128_WITH_MD5", - [0x020080] = "SSL2_RC4_128_EXPORT40_WITH_MD5", - [0x030080] = "SSL2_RC2_CBC_128_CBC_WITH_MD5", - [0x040080] = "SSL2_RC2_CBC_128_CBC_WITH_MD5", - [0x050080] = "SSL2_IDEA_128_CBC_WITH_MD5", - [0x060040] = "SSL2_DES_64_CBC_WITH_MD5", - [0x0700c0] = "SSL2_DES_192_EDE3_CBC_WITH_MD5", - [0x080080] = "SSL2_RC4_64_WITH_MD5", - }; + local ssl_ciphers = { + -- (cut down) table of codes with their corresponding ciphers. + -- inspired by Wireshark's 'epan/dissectors/packet-ssl-utils.h' + [0x010080] = "SSL2_RC4_128_WITH_MD5", + [0x020080] = "SSL2_RC4_128_EXPORT40_WITH_MD5", + [0x030080] = "SSL2_RC2_CBC_128_CBC_WITH_MD5", + [0x040080] = "SSL2_RC2_CBC_128_CBC_WITH_MD5", + [0x050080] = "SSL2_IDEA_128_CBC_WITH_MD5", + [0x060040] = "SSL2_DES_64_CBC_WITH_MD5", + [0x0700c0] = "SSL2_DES_192_EDE3_CBC_WITH_MD5", + [0x080080] = "SSL2_RC4_64_WITH_MD5", + }; - if (len == 0) then return "none"; end --- something's got broken along the way if these aren't equal - if (len ~= #cipher_list) then - return nil - end + if (len == 0) then return "none"; end + -- something's got broken along the way if these aren't equal + if (len ~= #cipher_list) then + return nil + end - for idx = 1, len, 3 do - local _, cipher = bin.unpack(">I", "\x00" .. string.sub(cipher_list, idx, idx + 2)) - local cipher_name = ssl_ciphers[cipher]; + for idx = 1, len, 3 do + local _, cipher = bin.unpack(">I", "\x00" .. string.sub(cipher_list, idx, idx + 2)) + local cipher_name = ssl_ciphers[cipher]; - if (cipher_name == nil) then - cipher_name = string.format("0x%06x", cipher) - end + if (cipher_name == nil) then + cipher_name = string.format("0x%06x", cipher) + end - -- Check for duplicate ciphers - if not seen[cipher] then - table.insert(available_ciphers, cipher_name) + -- Check for duplicate ciphers + if not seen[cipher] then + table.insert(available_ciphers, cipher_name) seen[cipher] = true - end - end + end + end - return available_ciphers + return available_ciphers end local give_n_bytes = function(idx, n, str) --- returns the next n bytes of a string + -- returns the next n bytes of a string - if (idx + (n - 1) > #str) then - return (idx + n), string.rep(string.char(0x00), n); - end + if (idx + (n - 1) > #str) then + return (idx + n), string.rep(string.char(0x00), n); + end - return (idx + n), string.sub(str, idx, (idx + (n - 1)) ); + return (idx + n), string.sub(str, idx, (idx + (n - 1)) ); end action = function(host, port) - local socket = nmap.new_socket(); - local status = true; + local socket = nmap.new_socket(); + local status = true; - local tmp; + local tmp; - local idx = 3; -- start reading after the end of the length record + local idx = 3; -- start reading after the end of the length record - local return_string = ""; - local available_ciphers; + local return_string = ""; + local available_ciphers; - local ssl_v2_hello; - local server_hello; + local ssl_v2_hello; + local server_hello; - local server_hello_len; - local message_type; - local SID_hit; - local certificate_type; - local ssl_version; - local certificate_len; - local ciphers_len; - local certificate; - local connection_ID_len; - local cipher_list; - local connection_ID; + local server_hello_len; + local message_type; + local SID_hit; + local certificate_type; + local ssl_version; + local certificate_len; + local ciphers_len; + local certificate; + local connection_ID_len; + local cipher_list; + local connection_ID; --- build client hello packet (contents inspired by --- http://mail.nessus.org/pipermail/plugins-writers/2004-October/msg00041.html ) - local t = {}; - table.insert(t, string.char(0x80, 0x31)); - table.insert(t, string.char(0x01)); - table.insert(t, string.char(0x00, 0x02)); - table.insert(t, string.char(0x00, 0x18)); - table.insert(t, string.char(0x00, 0x00)); - table.insert(t, string.char(0x00, 0x10)); - table.insert(t, string.char(0x07, 0x00, 0xc0)); - table.insert(t, string.char(0x05, 0x00, 0x80)); - table.insert(t, string.char(0x03, 0x00, 0x80)); - table.insert(t, string.char(0x01, 0x00, 0x80)); - table.insert(t, string.char(0x08, 0x00, 0x80)); - table.insert(t, string.char(0x06, 0x00, 0x40)); - table.insert(t, string.char(0x04, 0x00, 0x80)); - table.insert(t, string.char(0x02, 0x00, 0x80)); - table.insert(t, string.char(0xe4, 0xbd, 0x00, 0x00)); - table.insert(t, string.char(0xa4, 0x41, 0xb6, 0x74)); - table.insert(t, string.char(0x71, 0x2b, 0x27, 0x95)); - table.insert(t, string.char(0x44, 0xc0, 0x3d, 0xc0)); - ssl_v2_hello = table.concat(t, "") + -- build client hello packet (contents inspired by + -- http://mail.nessus.org/pipermail/plugins-writers/2004-October/msg00041.html ) + local t = {}; + table.insert(t, string.char(0x80, 0x31)); + table.insert(t, string.char(0x01)); + table.insert(t, string.char(0x00, 0x02)); + table.insert(t, string.char(0x00, 0x18)); + table.insert(t, string.char(0x00, 0x00)); + table.insert(t, string.char(0x00, 0x10)); + table.insert(t, string.char(0x07, 0x00, 0xc0)); + table.insert(t, string.char(0x05, 0x00, 0x80)); + table.insert(t, string.char(0x03, 0x00, 0x80)); + table.insert(t, string.char(0x01, 0x00, 0x80)); + table.insert(t, string.char(0x08, 0x00, 0x80)); + table.insert(t, string.char(0x06, 0x00, 0x40)); + table.insert(t, string.char(0x04, 0x00, 0x80)); + table.insert(t, string.char(0x02, 0x00, 0x80)); + table.insert(t, string.char(0xe4, 0xbd, 0x00, 0x00)); + table.insert(t, string.char(0xa4, 0x41, 0xb6, 0x74)); + table.insert(t, string.char(0x71, 0x2b, 0x27, 0x95)); + table.insert(t, string.char(0x44, 0xc0, 0x3d, 0xc0)); + ssl_v2_hello = table.concat(t, "") - socket:connect(host, port, "tcp"); - socket:send(ssl_v2_hello); + socket:connect(host, port, "tcp"); + socket:send(ssl_v2_hello); - status, server_hello = socket:receive_bytes(2); + status, server_hello = socket:receive_bytes(2); - if (not status) then - socket:close(); - return; - end + if (not status) then + socket:close(); + return; + end - server_hello_len = string.sub(server_hello, 1, 2); - server_hello_len = hex2dec(server_hello_len); --- length record doesn't include its own length, and is "broken". - server_hello_len = server_hello_len - (128 * 256) + 2; + server_hello_len = string.sub(server_hello, 1, 2); + server_hello_len = hex2dec(server_hello_len); + -- length record doesn't include its own length, and is "broken". + server_hello_len = server_hello_len - (128 * 256) + 2; --- the hello needs to be at least 13 bytes long to be of any use - if (server_hello_len < 13) then - socket:close(); - return; - end ---try to get entire hello, if we don't already - if (#server_hello < server_hello_len) then - status, tmp = socket:receive_bytes(server_hello_len - #server_hello); + -- the hello needs to be at least 13 bytes long to be of any use + if (server_hello_len < 13) then + socket:close(); + return; + end + --try to get entire hello, if we don't already + if (#server_hello < server_hello_len) then + status, tmp = socket:receive_bytes(server_hello_len - #server_hello); - if (not status) then - socket:close(); - return; - end + if (not status) then + socket:close(); + return; + end - server_hello = server_hello .. tmp; - end; + server_hello = server_hello .. tmp; + end; - socket:close(); + socket:close(); --- split up server hello into components - idx, message_type = give_n_bytes(idx, 1, server_hello); - idx, SID_hit = give_n_bytes(idx, 1, server_hello); - idx, certificate_type = give_n_bytes(idx, 1, server_hello); - idx, ssl_version = give_n_bytes(idx, 2, server_hello); - idx, certificate_len = give_n_bytes(idx, 2, server_hello); - certificate_len = hex2dec(certificate_len); - idx, ciphers_len = give_n_bytes(idx, 2, server_hello); - ciphers_len = hex2dec(ciphers_len); - idx, connection_ID_len = give_n_bytes(idx, 2, server_hello); - connection_ID_len = hex2dec(connection_ID_len); - idx, certificate = give_n_bytes(idx, certificate_len, server_hello); - idx, cipher_list = give_n_bytes(idx, ciphers_len, server_hello); - idx, connection_ID = give_n_bytes(idx, connection_ID_len, server_hello); + -- split up server hello into components + idx, message_type = give_n_bytes(idx, 1, server_hello); + idx, SID_hit = give_n_bytes(idx, 1, server_hello); + idx, certificate_type = give_n_bytes(idx, 1, server_hello); + idx, ssl_version = give_n_bytes(idx, 2, server_hello); + idx, certificate_len = give_n_bytes(idx, 2, server_hello); + certificate_len = hex2dec(certificate_len); + idx, ciphers_len = give_n_bytes(idx, 2, server_hello); + ciphers_len = hex2dec(ciphers_len); + idx, connection_ID_len = give_n_bytes(idx, 2, server_hello); + connection_ID_len = hex2dec(connection_ID_len); + idx, certificate = give_n_bytes(idx, certificate_len, server_hello); + idx, cipher_list = give_n_bytes(idx, ciphers_len, server_hello); + idx, connection_ID = give_n_bytes(idx, connection_ID_len, server_hello); --- some sanity checks: --- is response a server hello? - if (message_type ~= string.char(0x04)) then - return; - end --- is certificate in X.509 format? - if (certificate_type ~= string.char(0x01)) then - return; - end + -- some sanity checks: + -- is response a server hello? + if (message_type ~= string.char(0x04)) then + return; + end + -- is certificate in X.509 format? + if (certificate_type ~= string.char(0x01)) then + return; + end --- get a list of ciphers offered - available_ciphers = ciphers(cipher_list, ciphers_len); + -- get a list of ciphers offered + available_ciphers = ciphers(cipher_list, ciphers_len); --- actually run some tests: + -- actually run some tests: local o = stdnse.output_table() - if (ssl_version == string.char(0x00, 0x02)) then + if (ssl_version == string.char(0x00, 0x02)) then table.insert(o, "SSLv2 supported") o["ciphers"] = available_ciphers - end + end - return o; + return o; end diff --git a/scripts/svn-brute.nse b/scripts/svn-brute.nse index fe8f77f80..bef622054 100644 --- a/scripts/svn-brute.nse +++ b/scripts/svn-brute.nse @@ -46,227 +46,227 @@ portrule = shortport.port_or_service(3690, "svnserve", "tcp", "open") svn = { - svn_client = "nmap-brute v0.1", + svn_client = "nmap-brute v0.1", - new = function(self, host, port, repo) - local o = {} - setmetatable(o, self) - self.__index = self - o.host = host - o.port = port - o.repo = repo - o.invalid_users = {} - return o - end, + new = function(self, host, port, repo) + local o = {} + setmetatable(o, self) + self.__index = self + o.host = host + o.port = port + o.repo = repo + o.invalid_users = {} + return o + end, - --- Connects to the SVN - repository - -- - -- @return status true on success, false on failure - -- @return err string containing an error message on failure - connect = function(self) - local repo_url = ( "svn://%s/%s" ):format(self.host.ip, self.repo) - local status, msg + --- Connects to the SVN - repository + -- + -- @return status true on success, false on failure + -- @return err string containing an error message on failure + connect = function(self) + local repo_url = ( "svn://%s/%s" ):format(self.host.ip, self.repo) + local status, msg - self.socket = nmap.new_socket() + self.socket = nmap.new_socket() - local result - status, result = self.socket:connect(self.host.ip, self.port.number, "tcp") - if( not(status) ) then - return false, result - end + local result + status, result = self.socket:connect(self.host.ip, self.port.number, "tcp") + if( not(status) ) then + return false, result + end - status, msg = self.socket:receive_bytes(1) - if ( not(status) or not( msg:match("^%( success") ) ) then - return false, "Banner reports failure" - end + status, msg = self.socket:receive_bytes(1) + if ( not(status) or not( msg:match("^%( success") ) ) then + return false, "Banner reports failure" + end - msg = ("( 2 ( edit-pipeline svndiff1 absent-entries depth mergeinfo log-revprops ) %d:%s %d:%s ( ) ) "):format( #repo_url, repo_url, #self.svn_client, self.svn_client ) - status = self.socket:send( msg ) - if ( not(status) ) then - return false, "Send failed" - end + msg = ("( 2 ( edit-pipeline svndiff1 absent-entries depth mergeinfo log-revprops ) %d:%s %d:%s ( ) ) "):format( #repo_url, repo_url, #self.svn_client, self.svn_client ) + status = self.socket:send( msg ) + if ( not(status) ) then + return false, "Send failed" + end - status, msg = self.socket:receive_bytes(1) - if ( not(status) ) then - return false, "Receive failed" - end + status, msg = self.socket:receive_bytes(1) + if ( not(status) ) then + return false, "Receive failed" + end - if ( msg:match("%( success") ) then - local tmp = msg:match("%( success %( %( ([%S+%s*]-) %)") - if ( not(tmp) ) then return false, "Failed to detect authentication" end - tmp = stdnse.strsplit(" ", tmp) - self.auth_mech = {} - for _, v in pairs(tmp) do self.auth_mech[v] = true end - elseif ( msg:match("%( failure") ) then - return false - end + if ( msg:match("%( success") ) then + local tmp = msg:match("%( success %( %( ([%S+%s*]-) %)") + if ( not(tmp) ) then return false, "Failed to detect authentication" end + tmp = stdnse.strsplit(" ", tmp) + self.auth_mech = {} + for _, v in pairs(tmp) do self.auth_mech[v] = true end + elseif ( msg:match("%( failure") ) then + return false + end - return true - end, + return true + end, - --- Attempts to login to the SVN server - -- - -- @param username string containing the login username - -- @param password string containing the login password - -- @return status, true on success, false on failure - -- @return err string containing error message on failure - login = function( self, username, password ) - local status, msg - local challenge, digest + --- Attempts to login to the SVN server + -- + -- @param username string containing the login username + -- @param password string containing the login password + -- @return status, true on success, false on failure + -- @return err string containing error message on failure + login = function( self, username, password ) + local status, msg + local challenge, digest - if ( self.auth_mech["CRAM-MD5"] ) then - msg = "( CRAM-MD5 ( ) ) " - status = self.socket:send( msg ) + if ( self.auth_mech["CRAM-MD5"] ) then + msg = "( CRAM-MD5 ( ) ) " + status = self.socket:send( msg ) - status, msg = self.socket:receive_bytes(1) - if ( not(status) ) then - return false, "error" - end + status, msg = self.socket:receive_bytes(1) + if ( not(status) ) then + return false, "error" + end - challenge = msg:match("<.+>") + challenge = msg:match("<.+>") - if ( not(challenge) ) then - return false, "Failed to read challenge" - end + if ( not(challenge) ) then + return false, "Failed to read challenge" + end - digest = stdnse.tohex(openssl.hmac('md5', password, challenge)) - msg = ("%d:%s %s "):format(#username + 1 + #digest, username, digest) - self.socket:send( msg ) + digest = stdnse.tohex(openssl.hmac('md5', password, challenge)) + msg = ("%d:%s %s "):format(#username + 1 + #digest, username, digest) + self.socket:send( msg ) - status, msg = self.socket:receive_bytes(1) - if ( not(status) ) then - return false, "error" - end + status, msg = self.socket:receive_bytes(1) + if ( not(status) ) then + return false, "error" + end - if ( msg:match("Username not found") ) then - return false, "Username not found" - elseif ( msg:match("success") ) then - return true, "Authentication success" - else - return false, "Authentication failed" - end - else - return false, "Unsupported auth-mechanism" - end + if ( msg:match("Username not found") ) then + return false, "Username not found" + elseif ( msg:match("success") ) then + return true, "Authentication success" + else + return false, "Authentication failed" + end + else + return false, "Unsupported auth-mechanism" + end - end, + end, - --- Close the SVN connection - -- - -- @return status true on success, false on failure - close = function(self) - return self.socket:close() - end, + --- Close the SVN connection + -- + -- @return status true on success, false on failure + close = function(self) + return self.socket:close() + end, } Driver = { - new = function(self, host, port, invalid_users ) - local o = {} - setmetatable(o, self) - self.__index = self - o.host = host - o.port = port - o.repo = stdnse.get_script_args('svn-brute.repo') - o.invalid_users = invalid_users - return o - end, + new = function(self, host, port, invalid_users ) + local o = {} + setmetatable(o, self) + self.__index = self + o.host = host + o.port = port + o.repo = stdnse.get_script_args('svn-brute.repo') + o.invalid_users = invalid_users + return o + end, - connect = function( self ) - local status, msg + connect = function( self ) + local status, msg - self.svn = svn:new( self.host, self.port, self.repo ) - status, msg = self.svn:connect() - if ( not(status) ) then - local err = brute.Error:new( "Failed to connect to SVN server" ) - -- This might be temporary, set the retry flag - err:setRetry( true ) - return false, err - end + self.svn = svn:new( self.host, self.port, self.repo ) + status, msg = self.svn:connect() + if ( not(status) ) then + local err = brute.Error:new( "Failed to connect to SVN server" ) + -- This might be temporary, set the retry flag + err:setRetry( true ) + return false, err + end - return true - end, + return true + end, - disconnect = function( self ) - self.svn:close() - end, + disconnect = function( self ) + self.svn:close() + end, - --- Attempts to login to the SVN server - -- - -- @param username string containing the login username - -- @param password string containing the login password - -- @return status, true on success, false on failure - -- @return brute.Error object on failure - -- brute.Account object on success - login = function( self, username, password ) - local status, msg + --- Attempts to login to the SVN server + -- + -- @param username string containing the login username + -- @param password string containing the login password + -- @return status, true on success, false on failure + -- @return brute.Error object on failure + -- brute.Account object on success + login = function( self, username, password ) + local status, msg - if ( self.invalid_users[username] ) then - return false, brute.Error:new( "User is invalid" ) - end + if ( self.invalid_users[username] ) then + return false, brute.Error:new( "User is invalid" ) + end - status, msg = self.svn:login( username, password ) + status, msg = self.svn:login( username, password ) - if ( not(status) and msg:match("Username not found") ) then - self.invalid_users[username] = true - return false, brute.Error:new("Username not found") - elseif ( status and msg:match("success") ) then - return true, brute.Account:new(username, password, creds.State.VALID) - else - return false, brute.Error:new( "Incorrect password" ) - end - end, + if ( not(status) and msg:match("Username not found") ) then + self.invalid_users[username] = true + return false, brute.Error:new("Username not found") + elseif ( status and msg:match("success") ) then + return true, brute.Account:new(username, password, creds.State.VALID) + else + return false, brute.Error:new( "Incorrect password" ) + end + end, - --- Verifies whether the repository is valid - -- - -- @return status, true on success, false on failure - -- @return err string containing an error message on failure - check = function( self ) - local svn = svn:new( self.host, self.port, self.repo ) - local status = svn:connect() + --- Verifies whether the repository is valid + -- + -- @return status, true on success, false on failure + -- @return err string containing an error message on failure + check = function( self ) + local svn = svn:new( self.host, self.port, self.repo ) + local status = svn:connect() - svn:close() + svn:close() - if ( status ) then - return true - else - return false, ("Failed to connect to SVN repository (%s)"):format(self.repo) - end - end, + if ( status ) then + return true + else + return false, ("Failed to connect to SVN repository (%s)"):format(self.repo) + end + end, } action = function(host, port) - local status, accounts + local status, accounts - local repo = stdnse.get_script_args('svn-brute.repo') - local force = stdnse.get_script_args('svn-brute.force') + local repo = stdnse.get_script_args('svn-brute.repo') + local force = stdnse.get_script_args('svn-brute.force') - if ( not(repo) ) then - return "No repository specified (see svn-brute.repo)" - end + if ( not(repo) ) then + return "No repository specified (see svn-brute.repo)" + end - local svn = svn:new( host, port, repo ) - local status = svn:connect() + local svn = svn:new( host, port, repo ) + local status = svn:connect() - if ( status and svn.auth_mech["ANONYMOUS"] and not(force) ) then - return " \n Anonymous SVN detected, no authentication needed" - end + if ( status and svn.auth_mech["ANONYMOUS"] and not(force) ) then + return " \n Anonymous SVN detected, no authentication needed" + end - if ( not(svn.auth_mech) or not( svn.auth_mech["CRAM-MD5"] ) ) then - return " \n No supported authentication mechanisms detected" - end + if ( not(svn.auth_mech) or not( svn.auth_mech["CRAM-MD5"] ) ) then + return " \n No supported authentication mechanisms detected" + end - local invalid_users = {} - local engine = brute.Engine:new(Driver, host, port, invalid_users) - engine.options.script_name = SCRIPT_NAME - status, accounts = engine:start() - if( not(status) ) then - return accounts - end + local invalid_users = {} + local engine = brute.Engine:new(Driver, host, port, invalid_users) + engine.options.script_name = SCRIPT_NAME + status, accounts = engine:start() + if( not(status) ) then + return accounts + end - return accounts + return accounts end diff --git a/scripts/targets-ipv6-multicast-invalid-dst.nse b/scripts/targets-ipv6-multicast-invalid-dst.nse index 964f042ca..891083258 100644 --- a/scripts/targets-ipv6-multicast-invalid-dst.nse +++ b/scripts/targets-ipv6-multicast-invalid-dst.nse @@ -34,169 +34,169 @@ categories = {"discovery","broadcast"} prerule = function() - return nmap.is_privileged() + return nmap.is_privileged() end --- Build an IPv6 invalid extension header. -- @param nxt_hdr integer that stands for next header's type local function build_invalid_extension_header(nxt_hdr) - -- RFC 2640, section 4.2 defines the TLV format of options headers. - -- It is important that the first byte have 10 in the most significant - -- bits; that instructs the receiver to send a Parameter Problem. - -- Option type 0x80 is unallocated; see - -- http://www.iana.org/assignments/ipv6-parameters/. - local ex_invalid_opt = string.char(0x80,0x01,0x00,0x00,0x00,0x00) - local ext_header = - string.char(nxt_hdr) .. --next header - string.char(0) .. -- length 8 - ex_invalid_opt - return ext_header + -- RFC 2640, section 4.2 defines the TLV format of options headers. + -- It is important that the first byte have 10 in the most significant + -- bits; that instructs the receiver to send a Parameter Problem. + -- Option type 0x80 is unallocated; see + -- http://www.iana.org/assignments/ipv6-parameters/. + local ex_invalid_opt = string.char(0x80,0x01,0x00,0x00,0x00,0x00) + local ext_header = + string.char(nxt_hdr) .. --next header + string.char(0) .. -- length 8 + ex_invalid_opt + return ext_header end local function get_interfaces() - local interface_name = stdnse.get_script_args(SCRIPT_NAME .. ".interface") - or nmap.get_interface() + local interface_name = stdnse.get_script_args(SCRIPT_NAME .. ".interface") + or nmap.get_interface() - -- interfaces list (decide which interfaces to broadcast on) - local interfaces = {} - if interface_name then - -- single interface defined - local if_table = nmap.get_interface_info(interface_name) - if if_table and packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then - interfaces[#interfaces + 1] = if_table - else - stdnse.print_debug("Interface not supported or not properly configured.") - end - else - for _, if_table in ipairs(nmap.list_interfaces()) do - if packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then - table.insert(interfaces, if_table) - end - end - end + -- interfaces list (decide which interfaces to broadcast on) + local interfaces = {} + if interface_name then + -- single interface defined + local if_table = nmap.get_interface_info(interface_name) + if if_table and packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then + interfaces[#interfaces + 1] = if_table + else + stdnse.print_debug("Interface not supported or not properly configured.") + end + else + for _, if_table in ipairs(nmap.list_interfaces()) do + if packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then + table.insert(interfaces, if_table) + end + end + end - return interfaces + return interfaces end local function single_interface_broadcast(if_nfo, results) - stdnse.print_debug("Starting " .. SCRIPT_NAME .. " on " .. if_nfo.device) + stdnse.print_debug("Starting " .. SCRIPT_NAME .. " on " .. if_nfo.device) - local condvar = nmap.condvar(results) - local src_mac = if_nfo.mac - local src_ip6 = packet.ip6tobin(if_nfo.address) - local dst_mac = packet.mactobin("33:33:00:00:00:01") - local dst_ip6 = packet.ip6tobin("ff02::1") + local condvar = nmap.condvar(results) + local src_mac = if_nfo.mac + local src_ip6 = packet.ip6tobin(if_nfo.address) + local dst_mac = packet.mactobin("33:33:00:00:00:01") + local dst_ip6 = packet.ip6tobin("ff02::1") ----------------------------------------------------------------------------- ---Multicast invalid destination exheader probe + ---------------------------------------------------------------------------- + --Multicast invalid destination exheader probe - local dnet = nmap.new_dnet() - local pcap = nmap.new_socket() + local dnet = nmap.new_dnet() + local pcap = nmap.new_socket() - local function catch () - dnet:ethernet_close() - pcap:pcap_close() + local function catch () + dnet:ethernet_close() + pcap:pcap_close() + end + local try = nmap.new_try(catch) + + try(dnet:ethernet_open(if_nfo.device)) + pcap:pcap_open(if_nfo.device, 128, false, "icmp6 and ip6[6:1] = 58 and ip6[40:1] = 4") + + local probe = packet.Frame:new() + probe.mac_src = src_mac + probe.mac_dst = dst_mac + probe.ip_bin_src = src_ip6 + probe.ip_bin_dst = dst_ip6 + + -- In addition to setting an invalid option in + -- build_invalid_extension_header, we set an unknown ICMPv6 type of + -- 254. (See http://www.iana.org/assignments/icmpv6-parameters for + -- allocations.) Mac OS X 10.6 appears to send a Parameter Problem + -- response only if both of these conditions are met. In this we differ + -- from the alive6 tool, which sends a proper echo request. + probe.icmpv6_type = 254 + probe.icmpv6_code = 0 + -- Add a non-empty payload too. + probe.icmpv6_payload = string.char(0x00, 0x00, 0x00, 0x00) + probe:build_icmpv6_header() + + probe.exheader = build_invalid_extension_header(packet.IPPROTO_ICMPV6) + probe.ip6_nhdr = packet.IPPROTO_DSTOPTS + + probe:build_ipv6_packet() + probe:build_ether_frame() + + try(dnet:ethernet_send(probe.frame_buf)) + + pcap:set_timeout(1000) + local pcap_timeout_count = 0 + local nse_timeout = 5 + local start_time = nmap:clock() + local cur_time = nmap:clock() + + local addrs = {} + + repeat + local status, length, layer2, layer3 = pcap:pcap_receive() + cur_time = nmap:clock() + if not status then + pcap_timeout_count = pcap_timeout_count + 1 + else + local l2reply = packet.Frame:new(layer2) + if l2reply.mac_dst == src_mac then + local reply = packet.Packet:new(layer3) + local target_str = reply.ip_src + if not results[target_str] then + if target.ALLOW_NEW_TARGETS then + target.add(target_str) + end + results[#results + 1] = { address = target_str, mac = stdnse.format_mac(l2reply.mac_src), iface = if_nfo.device } + results[target_str] = true + end + end end - local try = nmap.new_try(catch) + until pcap_timeout_count >= 2 or cur_time - start_time >= nse_timeout - try(dnet:ethernet_open(if_nfo.device)) - pcap:pcap_open(if_nfo.device, 128, false, "icmp6 and ip6[6:1] = 58 and ip6[40:1] = 4") + dnet:ethernet_close() + pcap:pcap_close() - local probe = packet.Frame:new() - probe.mac_src = src_mac - probe.mac_dst = dst_mac - probe.ip_bin_src = src_ip6 - probe.ip_bin_dst = dst_ip6 - - -- In addition to setting an invalid option in - -- build_invalid_extension_header, we set an unknown ICMPv6 type of - -- 254. (See http://www.iana.org/assignments/icmpv6-parameters for - -- allocations.) Mac OS X 10.6 appears to send a Parameter Problem - -- response only if both of these conditions are met. In this we differ - -- from the alive6 tool, which sends a proper echo request. - probe.icmpv6_type = 254 - probe.icmpv6_code = 0 - -- Add a non-empty payload too. - probe.icmpv6_payload = string.char(0x00, 0x00, 0x00, 0x00) - probe:build_icmpv6_header() - - probe.exheader = build_invalid_extension_header(packet.IPPROTO_ICMPV6) - probe.ip6_nhdr = packet.IPPROTO_DSTOPTS - - probe:build_ipv6_packet() - probe:build_ether_frame() - - try(dnet:ethernet_send(probe.frame_buf)) - - pcap:set_timeout(1000) - local pcap_timeout_count = 0 - local nse_timeout = 5 - local start_time = nmap:clock() - local cur_time = nmap:clock() - - local addrs = {} - - repeat - local status, length, layer2, layer3 = pcap:pcap_receive() - cur_time = nmap:clock() - if not status then - pcap_timeout_count = pcap_timeout_count + 1 - else - local l2reply = packet.Frame:new(layer2) - if l2reply.mac_dst == src_mac then - local reply = packet.Packet:new(layer3) - local target_str = reply.ip_src - if not results[target_str] then - if target.ALLOW_NEW_TARGETS then - target.add(target_str) - end - results[#results + 1] = { address = target_str, mac = stdnse.format_mac(l2reply.mac_src), iface = if_nfo.device } - results[target_str] = true - end - end - end - until pcap_timeout_count >= 2 or cur_time - start_time >= nse_timeout - - dnet:ethernet_close() - pcap:pcap_close() - - condvar("signal") + condvar("signal") end local function format_output(results) - local output = tab.new() + local output = tab.new() - for _, record in ipairs(results) do - tab.addrow(output, "IP: " .. record.address, "MAC: " .. record.mac, "IFACE: " .. record.iface) - end - if #results > 0 then - output = { tab.dump(output) } - if not target.ALLOW_NEW_TARGETS then - output[#output + 1] = "Use --script-args=newtargets to add the results as targets" - end - return stdnse.format_output(true, output) - end + for _, record in ipairs(results) do + tab.addrow(output, "IP: " .. record.address, "MAC: " .. record.mac, "IFACE: " .. record.iface) + end + if #results > 0 then + output = { tab.dump(output) } + if not target.ALLOW_NEW_TARGETS then + output[#output + 1] = "Use --script-args=newtargets to add the results as targets" + end + return stdnse.format_output(true, output) + end end action = function() - local threads = {} - local results = {} - local condvar = nmap.condvar(results) + local threads = {} + local results = {} + local condvar = nmap.condvar(results) - for _, if_nfo in ipairs(get_interfaces()) do - -- create a thread for each interface - local co = stdnse.new_thread(single_interface_broadcast, if_nfo, results) - threads[co] = true - end + for _, if_nfo in ipairs(get_interfaces()) do + -- create a thread for each interface + local co = stdnse.new_thread(single_interface_broadcast, if_nfo, results) + threads[co] = true + end - repeat - for thread in pairs(threads) do - if coroutine.status(thread) == "dead" then threads[thread] = nil end - end - if ( next(threads) ) then - condvar "wait" - end - until next(threads) == nil + repeat + for thread in pairs(threads) do + if coroutine.status(thread) == "dead" then threads[thread] = nil end + end + if ( next(threads) ) then + condvar "wait" + end + until next(threads) == nil - return format_output(results) + return format_output(results) end diff --git a/scripts/targets-ipv6-multicast-slaac.nse b/scripts/targets-ipv6-multicast-slaac.nse index 21b8f97d9..65cc23b23 100644 --- a/scripts/targets-ipv6-multicast-slaac.nse +++ b/scripts/targets-ipv6-multicast-slaac.nse @@ -48,28 +48,28 @@ categories = {"discovery","broadcast"} prerule = function() - return nmap.is_privileged() + return nmap.is_privileged() end local function get_identifier(ip6_addr) - return string.sub(ip6_addr, 9, 16) + return string.sub(ip6_addr, 9, 16) end --- Get a Unique-local Address with random global ID. -- @param local_scope The scope of the address, local or reserved. -- @return A 16-byte string of IPv6 address, and the length of the prefix. local function get_radom_ula_prefix(local_scope) - local ula_prefix - math.randomseed(os.time()) - local global_id = string.char(math.random(256)-1,math.random(256)-1,math.random(256)-1,math.random(256)-1,math.random(256)-1) + local ula_prefix + math.randomseed(os.time()) + local global_id = string.char(math.random(256)-1,math.random(256)-1,math.random(256)-1,math.random(256)-1,math.random(256)-1) - if local_scope then - ula_prefix = packet.ip6tobin("fd00::") - else - ula_prefix = packet.ip6tobin("fc00::") - end - ula_prefix = string.sub(ula_prefix,1,1) .. global_id .. string.sub(ula_prefix,7,-1) - return ula_prefix,64 + if local_scope then + ula_prefix = packet.ip6tobin("fd00::") + else + ula_prefix = packet.ip6tobin("fc00::") + end + ula_prefix = string.sub(ula_prefix,1,1) .. global_id .. string.sub(ula_prefix,7,-1) + return ula_prefix,64 end --- Build an ICMPv6 payload of Router Advertisement. @@ -79,174 +79,174 @@ end -- @param valid_time integer that represents the valid time of the prefix. -- @param preferred_time integer that represents the preferred time of the prefix. local function build_router_advert(mac_src,prefix,prefix_len,valid_time,preferred_time) - local ra_msg = string.char(0x0, --cur hop limit - 0x08, --flags - 0x00,0x00, --router lifetime - 0x00,0x00,0x00,0x00, --reachable time - 0x00,0x00,0x00,0x00) --retrans timer - local prefix_option_msg = string.char(prefix_len, 0xc0) .. --flags: Onlink, Auto - packet.set_u32("....",0,valid_time) .. - packet.set_u32("....",0,preferred_time) .. - string.char(0,0,0,0) .. --unknown - prefix - local icmpv6_prefix_option = packet.Packet:set_icmpv6_option(packet.ND_OPT_PREFIX_INFORMATION,prefix_option_msg) - local icmpv6_src_link_option = packet.Packet:set_icmpv6_option(packet.ND_OPT_SOURCE_LINKADDR,mac_src) - local icmpv6_payload = ra_msg .. icmpv6_prefix_option .. icmpv6_src_link_option - return icmpv6_payload + local ra_msg = string.char(0x0, --cur hop limit + 0x08, --flags + 0x00,0x00, --router lifetime + 0x00,0x00,0x00,0x00, --reachable time + 0x00,0x00,0x00,0x00) --retrans timer + local prefix_option_msg = string.char(prefix_len, 0xc0) .. --flags: Onlink, Auto + packet.set_u32("....",0,valid_time) .. + packet.set_u32("....",0,preferred_time) .. + string.char(0,0,0,0) .. --unknown + prefix + local icmpv6_prefix_option = packet.Packet:set_icmpv6_option(packet.ND_OPT_PREFIX_INFORMATION,prefix_option_msg) + local icmpv6_src_link_option = packet.Packet:set_icmpv6_option(packet.ND_OPT_SOURCE_LINKADDR,mac_src) + local icmpv6_payload = ra_msg .. icmpv6_prefix_option .. icmpv6_src_link_option + return icmpv6_payload end local function get_interfaces() - local interface_name = stdnse.get_script_args(SCRIPT_NAME .. ".interface") - or nmap.get_interface() + local interface_name = stdnse.get_script_args(SCRIPT_NAME .. ".interface") + or nmap.get_interface() - -- interfaces list (decide which interfaces to broadcast on) - local interfaces = {} - if interface_name then - -- single interface defined - local if_table = nmap.get_interface_info(interface_name) - if if_table and packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then - interfaces[#interfaces + 1] = if_table - else - stdnse.print_debug("Interface not supported or not properly configured.") - end - else - for _, if_table in ipairs(nmap.list_interfaces()) do - if packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then - table.insert(interfaces, if_table) - end - end - end + -- interfaces list (decide which interfaces to broadcast on) + local interfaces = {} + if interface_name then + -- single interface defined + local if_table = nmap.get_interface_info(interface_name) + if if_table and packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then + interfaces[#interfaces + 1] = if_table + else + stdnse.print_debug("Interface not supported or not properly configured.") + end + else + for _, if_table in ipairs(nmap.list_interfaces()) do + if packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then + table.insert(interfaces, if_table) + end + end + end - return interfaces + return interfaces end local function single_interface_broadcast(if_nfo, results) - stdnse.print_debug("Starting " .. SCRIPT_NAME .. " on " .. if_nfo.device) + stdnse.print_debug("Starting " .. SCRIPT_NAME .. " on " .. if_nfo.device) - local condvar = nmap.condvar(results) - local src_mac = if_nfo.mac - local src_ip6 = packet.ip6tobin(if_nfo.address) - local dst_mac = packet.mactobin("33:33:00:00:00:01") - local dst_ip6 = packet.ip6tobin("ff02::1") + local condvar = nmap.condvar(results) + local src_mac = if_nfo.mac + local src_ip6 = packet.ip6tobin(if_nfo.address) + local dst_mac = packet.mactobin("33:33:00:00:00:01") + local dst_ip6 = packet.ip6tobin("ff02::1") ----------------------------------------------------------------------------- ---SLAAC-based host discovery probe + ---------------------------------------------------------------------------- + --SLAAC-based host discovery probe - local dnet = nmap.new_dnet() - local pcap = nmap.new_socket() + local dnet = nmap.new_dnet() + local pcap = nmap.new_socket() - local function catch () - dnet:ethernet_close() - pcap:pcap_close() + local function catch () + dnet:ethernet_close() + pcap:pcap_close() + end + local try = nmap.new_try(catch) + + try(dnet:ethernet_open(if_nfo.device)) + pcap:pcap_open(if_nfo.device, 128, true, "src ::0/128 and dst net ff02::1:0:0/96 and icmp6 and ip6[6:1] = 58 and ip6[40:1] = 135") + + local actual_prefix = string.sub(src_ip6,1,8) + local ula_prefix, prefix_len = get_radom_ula_prefix() + + -- preferred_lifetime <= valid_lifetime. + -- Nmap will get the whole IPv6 addresses of each host if the two parameters are both longer than 5 seconds. + -- Sometimes it makes sense to regard the several addresses of a host as different hosts, as the host's administrator may apply different firewall configurations on them. + local valid_lifetime = 6 + local preferred_lifetime = 6 + + local probe = packet.Frame:new() + + probe.ip_bin_src = packet.mac_to_lladdr(src_mac) + probe.ip_bin_dst = dst_ip6 + probe.mac_src = src_mac + probe.mac_dst = packet.mactobin("33:33:00:00:00:01") + + local icmpv6_payload = build_router_advert(src_mac,ula_prefix,prefix_len,valid_lifetime,preferred_lifetime) + probe:build_icmpv6_header(packet.ND_ROUTER_ADVERT, 0, icmpv6_payload) + probe:build_ipv6_packet() + probe:build_ether_frame() + + try(dnet:ethernet_send(probe.frame_buf)) + + local expected_mac_dst_prefix = packet.mactobin("33:33:ff:00:00:00") + local expected_ip6_src = packet.ip6tobin("::") + local expected_ip6_dst_prefix = packet.ip6tobin("ff02::1:0:0") + + pcap:set_timeout(1000) + local pcap_timeout_count = 0 + local nse_timeout = 5 + local start_time = nmap:clock() + local cur_time = nmap:clock() + + repeat + local status, length, layer2, layer3 = pcap:pcap_receive() + cur_time = nmap:clock() + if not status then + pcap_timeout_count = pcap_timeout_count + 1 + else + local l2reply = packet.Frame:new(layer2) + if string.sub(l2reply.mac_dst, 1, 3) == string.sub(expected_mac_dst_prefix, 1, 3) then + local reply = packet.Packet:new(layer3) + if reply.ip_bin_src == expected_ip6_src and + string.sub(expected_ip6_dst_prefix,1,12) == string.sub(reply.ip_bin_dst,1,12) then + local ula_target_addr_str = packet.toipv6(reply.ns_target) + local identifier = get_identifier(reply.ns_target) + --Filter out the reduplicative identifiers. + --A host will send several NS packets with the same interface identifier if it receives several RA packets with different prefix during the discovery phase. + local actual_addr_str = packet.toipv6(actual_prefix .. identifier) + if not results[actual_addr_str] then + if target.ALLOW_NEW_TARGETS then + target.add(actual_addr_str) + end + results[#results + 1] = { address = actual_addr_str, mac = stdnse.format_mac(l2reply.mac_src), iface = if_nfo.device } + results[actual_addr_str] = true + end + end + end end - local try = nmap.new_try(catch) + until pcap_timeout_count >= 2 or cur_time - start_time >= nse_timeout - try(dnet:ethernet_open(if_nfo.device)) - pcap:pcap_open(if_nfo.device, 128, true, "src ::0/128 and dst net ff02::1:0:0/96 and icmp6 and ip6[6:1] = 58 and ip6[40:1] = 135") + dnet:ethernet_close() + pcap:pcap_close() - local actual_prefix = string.sub(src_ip6,1,8) - local ula_prefix, prefix_len = get_radom_ula_prefix() - - -- preferred_lifetime <= valid_lifetime. - -- Nmap will get the whole IPv6 addresses of each host if the two parameters are both longer than 5 seconds. - -- Sometimes it makes sense to regard the several addresses of a host as different hosts, as the host's administrator may apply different firewall configurations on them. - local valid_lifetime = 6 - local preferred_lifetime = 6 - - local probe = packet.Frame:new() - - probe.ip_bin_src = packet.mac_to_lladdr(src_mac) - probe.ip_bin_dst = dst_ip6 - probe.mac_src = src_mac - probe.mac_dst = packet.mactobin("33:33:00:00:00:01") - - local icmpv6_payload = build_router_advert(src_mac,ula_prefix,prefix_len,valid_lifetime,preferred_lifetime) - probe:build_icmpv6_header(packet.ND_ROUTER_ADVERT, 0, icmpv6_payload) - probe:build_ipv6_packet() - probe:build_ether_frame() - - try(dnet:ethernet_send(probe.frame_buf)) - - local expected_mac_dst_prefix = packet.mactobin("33:33:ff:00:00:00") - local expected_ip6_src = packet.ip6tobin("::") - local expected_ip6_dst_prefix = packet.ip6tobin("ff02::1:0:0") - - pcap:set_timeout(1000) - local pcap_timeout_count = 0 - local nse_timeout = 5 - local start_time = nmap:clock() - local cur_time = nmap:clock() - - repeat - local status, length, layer2, layer3 = pcap:pcap_receive() - cur_time = nmap:clock() - if not status then - pcap_timeout_count = pcap_timeout_count + 1 - else - local l2reply = packet.Frame:new(layer2) - if string.sub(l2reply.mac_dst, 1, 3) == string.sub(expected_mac_dst_prefix, 1, 3) then - local reply = packet.Packet:new(layer3) - if reply.ip_bin_src == expected_ip6_src and - string.sub(expected_ip6_dst_prefix,1,12) == string.sub(reply.ip_bin_dst,1,12) then - local ula_target_addr_str = packet.toipv6(reply.ns_target) - local identifier = get_identifier(reply.ns_target) - --Filter out the reduplicative identifiers. - --A host will send several NS packets with the same interface identifier if it receives several RA packets with different prefix during the discovery phase. - local actual_addr_str = packet.toipv6(actual_prefix .. identifier) - if not results[actual_addr_str] then - if target.ALLOW_NEW_TARGETS then - target.add(actual_addr_str) - end - results[#results + 1] = { address = actual_addr_str, mac = stdnse.format_mac(l2reply.mac_src), iface = if_nfo.device } - results[actual_addr_str] = true - end - end - end - end - until pcap_timeout_count >= 2 or cur_time - start_time >= nse_timeout - - dnet:ethernet_close() - pcap:pcap_close() - - condvar("signal") + condvar("signal") end local function format_output(results) - local output = tab.new() + local output = tab.new() - for _, record in ipairs(results) do - tab.addrow(output, "IP: " .. record.address, "MAC: " .. record.mac, "IFACE: " .. record.iface) - end - if #results > 0 then - output = { tab.dump(output) } - if not target.ALLOW_NEW_TARGETS then - output[#output + 1] = "Use --script-args=newtargets to add the results as targets" - end - return stdnse.format_output(true, output) - end + for _, record in ipairs(results) do + tab.addrow(output, "IP: " .. record.address, "MAC: " .. record.mac, "IFACE: " .. record.iface) + end + if #results > 0 then + output = { tab.dump(output) } + if not target.ALLOW_NEW_TARGETS then + output[#output + 1] = "Use --script-args=newtargets to add the results as targets" + end + return stdnse.format_output(true, output) + end end action = function() - local threads = {} - local results = {} - local condvar = nmap.condvar(results) + local threads = {} + local results = {} + local condvar = nmap.condvar(results) - for _, if_nfo in ipairs(get_interfaces()) do - -- create a thread for each interface - if ipOps.ip_in_range(if_nfo.address, "fe80::/10") then - local co = stdnse.new_thread(single_interface_broadcast, if_nfo, results) - threads[co] = true - end - end + for _, if_nfo in ipairs(get_interfaces()) do + -- create a thread for each interface + if ipOps.ip_in_range(if_nfo.address, "fe80::/10") then + local co = stdnse.new_thread(single_interface_broadcast, if_nfo, results) + threads[co] = true + end + end - repeat - for thread in pairs(threads) do - if coroutine.status(thread) == "dead" then threads[thread] = nil end - end - if ( next(threads) ) then - condvar "wait" - end - until next(threads) == nil + repeat + for thread in pairs(threads) do + if coroutine.status(thread) == "dead" then threads[thread] = nil end + end + if ( next(threads) ) then + condvar "wait" + end + until next(threads) == nil - return format_output(results) + return format_output(results) end diff --git a/scripts/wdb-version.nse b/scripts/wdb-version.nse index e06b1eb2f..828a8b667 100644 --- a/scripts/wdb-version.nse +++ b/scripts/wdb-version.nse @@ -55,37 +55,37 @@ rpc.RPC_version["wdb"] = { min=1, max=1 } local WDB_Procedure = { ["WDB_TARGET_PING"] = 0, - ["WDB_TARGET_CONNECT"] = 1, + ["WDB_TARGET_CONNECT"] = 1, ["WDB_TARGET_DISCONNECT"] = 2, ["WDB_TARGET_MODE_SET"] = 3, ["WDB_TARGET_MODE_GET"] = 4, } local function checksum(data) - local sum = 0 - local p = 0 - local _ - p, _ = bin.unpack(">I", data) - while p < data:len() do - local c - p, c = bin.unpack(">S", data, p) - sum = sum + c - end - sum = bit.band(sum, 0xffff) + bit.rshift(sum, 16) - return bit.bnot( sum ) + local sum = 0 + local p = 0 + local _ + p, _ = bin.unpack(">I", data) + while p < data:len() do + local c + p, c = bin.unpack(">S", data, p) + sum = sum + c + end + sum = bit.band(sum, 0xffff) + bit.rshift(sum, 16) + return bit.bnot( sum ) end local seqnum = 0 local function seqno() - seqnum = seqnum + 1 - return seqnum + seqnum = seqnum + 1 + return seqnum end local function request(comm, procedure, data) - local packet = comm:EncodePacket( nil, procedure, {type = rpc.Portmap.AuthType.NULL}, nil ) - local wdbwrapper = bin.pack( ">I2", data:len() + packet:len() + 8, seqno() ) - local sum = checksum(packet..bin.pack(">I", 0x00000000)..wdbwrapper..data) - return packet .. bin.pack(">S2", 0xffff, sum) .. wdbwrapper .. data + local packet = comm:EncodePacket( nil, procedure, {type = rpc.Portmap.AuthType.NULL}, nil ) + local wdbwrapper = bin.pack( ">I2", data:len() + packet:len() + 8, seqno() ) + local sum = checksum(packet..bin.pack(">I", 0x00000000)..wdbwrapper..data) + return packet .. bin.pack(">S2", 0xffff, sum) .. wdbwrapper .. data end local function stripnull(str) @@ -97,139 +97,139 @@ local function stripnull(str) end local function decode_reply(data, pos) - local wdberr, len - local done = data:len() - local info = {} - local _ - pos, _ = rpc.Util.unmarshall_uint32(data, pos) - pos, _ = rpc.Util.unmarshall_uint32(data, pos) - pos, wdberr = rpc.Util.unmarshall_uint32(data, pos) - info["error"] = bit.band(wdberr, 0xc0000000) - if (info["error"] ~= 0x00000000 ) then - stdnse.print_debug(1,"Error from decode_reply: %x", info["error"]) - return nil, info - end - pos, len = rpc.Util.unmarshall_uint32(data, pos) - if (len ~= 0) then - pos, info["agent_ver"] = rpc.Util.unmarshall_vopaque(len, data, pos) - end - pos, info["agent_mtu"] = rpc.Util.unmarshall_uint32(data, pos) - pos, info["agent_mod"] = rpc.Util.unmarshall_uint32(data, pos) - pos, info["rt_type"] = rpc.Util.unmarshall_uint32(data, pos) - pos, len = rpc.Util.unmarshall_uint32(data, pos) - if (pos == done) then return pos, info end - if (len ~= 0) then - pos, info["rt_vers"] = rpc.Util.unmarshall_vopaque(len, data, pos) - end - pos, info["rt_cpu_type"] = rpc.Util.unmarshall_uint32(data, pos) - pos, len = rpc.Util.unmarshall_uint32(data, pos) - info["rt_has_fpp"] = ( len ~= 0 ) - pos, len = rpc.Util.unmarshall_uint32(data, pos) - info["rt_has_wp"] = ( len ~= 0 ) - pos, info["rt_page_size"] = rpc.Util.unmarshall_uint32(data, pos) - pos, info["rt_endian"] = rpc.Util.unmarshall_uint32(data, pos) - pos, len = rpc.Util.unmarshall_uint32(data, pos) - if (len ~= 0) then - pos, info["rt_bsp_name"] = rpc.Util.unmarshall_vopaque(len, data, pos) - end - pos, len = rpc.Util.unmarshall_uint32(data, pos) - if (len ~= 0) then - pos, info["rt_bootline"] = rpc.Util.unmarshall_vopaque(len, data, pos) - end - if (pos == done) then return pos, info end - pos, info["rt_membase"] = rpc.Util.unmarshall_uint32(data, pos) - if (pos == done) then return pos, info end - pos, info["rt_memsize"] = rpc.Util.unmarshall_uint32(data, pos) - if (pos == done) then return pos, info end - pos, info["rt_region_count"] = rpc.Util.unmarshall_uint32(data, pos) - if (pos == done) then return pos, info end - pos, len = rpc.Util.unmarshall_uint32(data, pos) - if (len ~= 0) then - info["rt_regions"] = {} - for i = 1, len do - pos, info["rt_regions"][i] = rpc.Util.unmarshall_uint32(data, pos) - end - end - if (pos == done) then return pos, info end - pos, len = rpc.Util.unmarshall_uint32(data, pos) - if (len == nil) then return pos, info end - if (len ~= 0) then - pos, info["rt_hostpool_base"] = rpc.Util.unmarshall_vopaque(len, data, pos) - end - if (pos == done) then return pos, info end - pos, len = rpc.Util.unmarshall_uint32(data, pos) - if (len ~= 0) then - pos, info["rt_hostpool_size"] = rpc.Util.unmarshall_vopaque(len, data, pos) - end - return pos, info + local wdberr, len + local done = data:len() + local info = {} + local _ + pos, _ = rpc.Util.unmarshall_uint32(data, pos) + pos, _ = rpc.Util.unmarshall_uint32(data, pos) + pos, wdberr = rpc.Util.unmarshall_uint32(data, pos) + info["error"] = bit.band(wdberr, 0xc0000000) + if (info["error"] ~= 0x00000000 ) then + stdnse.print_debug(1,"Error from decode_reply: %x", info["error"]) + return nil, info + end + pos, len = rpc.Util.unmarshall_uint32(data, pos) + if (len ~= 0) then + pos, info["agent_ver"] = rpc.Util.unmarshall_vopaque(len, data, pos) + end + pos, info["agent_mtu"] = rpc.Util.unmarshall_uint32(data, pos) + pos, info["agent_mod"] = rpc.Util.unmarshall_uint32(data, pos) + pos, info["rt_type"] = rpc.Util.unmarshall_uint32(data, pos) + pos, len = rpc.Util.unmarshall_uint32(data, pos) + if (pos == done) then return pos, info end + if (len ~= 0) then + pos, info["rt_vers"] = rpc.Util.unmarshall_vopaque(len, data, pos) + end + pos, info["rt_cpu_type"] = rpc.Util.unmarshall_uint32(data, pos) + pos, len = rpc.Util.unmarshall_uint32(data, pos) + info["rt_has_fpp"] = ( len ~= 0 ) + pos, len = rpc.Util.unmarshall_uint32(data, pos) + info["rt_has_wp"] = ( len ~= 0 ) + pos, info["rt_page_size"] = rpc.Util.unmarshall_uint32(data, pos) + pos, info["rt_endian"] = rpc.Util.unmarshall_uint32(data, pos) + pos, len = rpc.Util.unmarshall_uint32(data, pos) + if (len ~= 0) then + pos, info["rt_bsp_name"] = rpc.Util.unmarshall_vopaque(len, data, pos) + end + pos, len = rpc.Util.unmarshall_uint32(data, pos) + if (len ~= 0) then + pos, info["rt_bootline"] = rpc.Util.unmarshall_vopaque(len, data, pos) + end + if (pos == done) then return pos, info end + pos, info["rt_membase"] = rpc.Util.unmarshall_uint32(data, pos) + if (pos == done) then return pos, info end + pos, info["rt_memsize"] = rpc.Util.unmarshall_uint32(data, pos) + if (pos == done) then return pos, info end + pos, info["rt_region_count"] = rpc.Util.unmarshall_uint32(data, pos) + if (pos == done) then return pos, info end + pos, len = rpc.Util.unmarshall_uint32(data, pos) + if (len ~= 0) then + info["rt_regions"] = {} + for i = 1, len do + pos, info["rt_regions"][i] = rpc.Util.unmarshall_uint32(data, pos) + end + end + if (pos == done) then return pos, info end + pos, len = rpc.Util.unmarshall_uint32(data, pos) + if (len == nil) then return pos, info end + if (len ~= 0) then + pos, info["rt_hostpool_base"] = rpc.Util.unmarshall_vopaque(len, data, pos) + end + if (pos == done) then return pos, info end + pos, len = rpc.Util.unmarshall_uint32(data, pos) + if (len ~= 0) then + pos, info["rt_hostpool_size"] = rpc.Util.unmarshall_vopaque(len, data, pos) + end + return pos, info end action = function(host, port) - local comm = rpc.Comm:new("wdb", 1) - local status, err, data, pos, header - local info = {} - status, err = comm:Connect(host, port) - if (not(status)) then - return stdnse.format_output(false, err) - end - comm.socket:set_timeout(3000) - local packet = request(comm, WDB_Procedure["WDB_TARGET_CONNECT"], bin.pack(">I3", 0x00000002, 0x00000000, 0x00000000)) - if (not(comm:SendPacket(packet))) then - return stdnse.format_output(false, "Failed to send request") - end + local comm = rpc.Comm:new("wdb", 1) + local status, err, data, pos, header + local info = {} + status, err = comm:Connect(host, port) + if (not(status)) then + return stdnse.format_output(false, err) + end + comm.socket:set_timeout(3000) + local packet = request(comm, WDB_Procedure["WDB_TARGET_CONNECT"], bin.pack(">I3", 0x00000002, 0x00000000, 0x00000000)) + if (not(comm:SendPacket(packet))) then + return stdnse.format_output(false, "Failed to send request") + end - status, data = comm:ReceivePacket() - if (not(status)) then - --return stdnse.format_output(false, "Failed to read data") - return nil - end - nmap.set_port_state(host, port, "open") + status, data = comm:ReceivePacket() + if (not(status)) then + --return stdnse.format_output(false, "Failed to read data") + return nil + end + nmap.set_port_state(host, port, "open") - pos = 0 - pos, header = comm:DecodeHeader(data, pos) - if not header then - return stdnse.format_output(false, "Failed to decode header") - end + pos = 0 + pos, header = comm:DecodeHeader(data, pos) + if not header then + return stdnse.format_output(false, "Failed to decode header") + end - if ( pos == data:len() ) then - return stdnse.format_output(false, "No WDB data in reply") - end + if ( pos == data:len() ) then + return stdnse.format_output(false, "No WDB data in reply") + end - pos, info = decode_reply(data, pos) - if not pos then - return stdnse.format_output(false, "WDB error: "..info.error) - end - port.version.name = "wdb" - port.version.name_confidence = 10 - port.version.product = "Wind DeBug Agent" - port.version.version = stripnull(info["agent_ver"]) - if (port.version.ostype ~= nil) then - port.version.ostype = "VxWorks " .. stripnull(info["rt_vers"]) - end - nmap.set_port_version(host, port) + pos, info = decode_reply(data, pos) + if not pos then + return stdnse.format_output(false, "WDB error: "..info.error) + end + port.version.name = "wdb" + port.version.name_confidence = 10 + port.version.product = "Wind DeBug Agent" + port.version.version = stripnull(info["agent_ver"]) + if (port.version.ostype ~= nil) then + port.version.ostype = "VxWorks " .. stripnull(info["rt_vers"]) + end + nmap.set_port_version(host, port) -- Clean up (some agents will continue to send data until we disconnect) - packet = request(comm, WDB_Procedure["WDB_TARGET_DISCONNECT"], bin.pack(">I3", 0x00000002, 0x00000000, 0x00000000)) - if (not(comm:SendPacket(packet))) then - return stdnse.format_output(false, "Failed to send request") - end + packet = request(comm, WDB_Procedure["WDB_TARGET_DISCONNECT"], bin.pack(">I3", 0x00000002, 0x00000000, 0x00000000)) + if (not(comm:SendPacket(packet))) then + return stdnse.format_output(false, "Failed to send request") + end - local o = stdnse.output_table() - table.insert(o, "VULNERABLE: Wind River Systems VxWorks debug service enabled. See http://www.kb.cert.org/vuls/id/362332") - if (info.agent_ver) then - o["Agent version"] = stripnull(info.agent_ver) - end - --table.insert(o, "Agent MTU: " .. info.agent_mtu) - if (info.rt_vers) then - o["VxWorks version"] = stripnull(info.rt_vers) - end - -- rt_cpu_type is an enum type, but I don't have access to - -- cputypes.h, where it is defined - --table.insert(o, "CPU Type: " .. info.rt_cpu_type) - if (info.rt_bsp_name) then - o["Board Support Package"] = stripnull(info.rt_bsp_name) - end - if (info.rt_bootline) then - o["Boot line"] = stripnull(info.rt_bootline) - end - return o + local o = stdnse.output_table() + table.insert(o, "VULNERABLE: Wind River Systems VxWorks debug service enabled. See http://www.kb.cert.org/vuls/id/362332") + if (info.agent_ver) then + o["Agent version"] = stripnull(info.agent_ver) + end + --table.insert(o, "Agent MTU: " .. info.agent_mtu) + if (info.rt_vers) then + o["VxWorks version"] = stripnull(info.rt_vers) + end + -- rt_cpu_type is an enum type, but I don't have access to + -- cputypes.h, where it is defined + --table.insert(o, "CPU Type: " .. info.rt_cpu_type) + if (info.rt_bsp_name) then + o["Board Support Package"] = stripnull(info.rt_bsp_name) + end + if (info.rt_bootline) then + o["Boot line"] = stripnull(info.rt_bootline) + end + return o end