mirror of
https://github.com/nmap/nmap.git
synced 2026-10-22 11:51:52 +00:00
Reindent the last of the NSE libraries.
https://secwiki.org/w/Nmap/Code_Standards
This commit is contained in:
parent
d5746993e2
commit
69e343f0aa
34 changed files with 26811 additions and 26811 deletions
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
1290
nselib/brute.lua
1290
nselib/brute.lua
File diff suppressed because it is too large
Load diff
|
|
@ -517,7 +517,7 @@ function request_reconnect_session_data(host, port, params)
|
|||
end
|
||||
|
||||
if params.DeviceId then
|
||||
xmldata = xmldata .. "<DeviceId>" .. params.DeviceId .. "</DeviceId>"
|
||||
xmldata = xmldata .. "<DeviceId>" .. params.DeviceId .. "</DeviceId>"
|
||||
end
|
||||
|
||||
for _, srvtype in pairs(params.ServerType) do
|
||||
|
|
|
|||
578
nselib/dhcp.lua
578
nselib/dhcp.lua
|
|
@ -26,14 +26,14 @@ _ENV = stdnse.module("dhcp", stdnse.seeall)
|
|||
|
||||
request_types =
|
||||
{
|
||||
DHCPDISCOVER = 1,
|
||||
DHCPOFFER = 2,
|
||||
DHCPREQUEST = 3,
|
||||
DHCPDECLINE = 4,
|
||||
DHCPACK = 5,
|
||||
DHCPNAK = 6,
|
||||
DHCPRELEASE = 7,
|
||||
DHCPINFORM = 8
|
||||
DHCPDISCOVER = 1,
|
||||
DHCPOFFER = 2,
|
||||
DHCPREQUEST = 3,
|
||||
DHCPDECLINE = 4,
|
||||
DHCPACK = 5,
|
||||
DHCPNAK = 6,
|
||||
DHCPRELEASE = 7,
|
||||
DHCPINFORM = 8
|
||||
}
|
||||
|
||||
request_types_str = {}
|
||||
|
|
@ -54,28 +54,28 @@ request_types_str[8] = "DHCPINFORM"
|
|||
--@return The new position (will always be pos + length, no matter what we think it should be)
|
||||
--@return The value of the field, or nil if the field length was wrong.
|
||||
local function read_ip(data, pos, length)
|
||||
if(length ~= 4) then
|
||||
if((length % 4) ~= 0) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Invalid length for an ip address (%d)", length)
|
||||
pos = pos + length
|
||||
if(length ~= 4) then
|
||||
if((length % 4) ~= 0) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Invalid length for an ip address (%d)", length)
|
||||
pos = pos + length
|
||||
|
||||
return pos, nil
|
||||
else
|
||||
local results = {}
|
||||
for i=1, length, 4 do
|
||||
local value
|
||||
pos, value = bin.unpack("<I", data, pos)
|
||||
table.insert(results, ipOps.fromdword(value))
|
||||
end
|
||||
return pos, nil
|
||||
else
|
||||
local results = {}
|
||||
for i=1, length, 4 do
|
||||
local value
|
||||
pos, value = bin.unpack("<I", data, pos)
|
||||
table.insert(results, ipOps.fromdword(value))
|
||||
end
|
||||
|
||||
return pos, results
|
||||
end
|
||||
else
|
||||
local value
|
||||
pos, value = bin.unpack("<I", data, pos)
|
||||
return pos, results
|
||||
end
|
||||
else
|
||||
local value
|
||||
pos, value = bin.unpack("<I", data, pos)
|
||||
|
||||
return pos, ipOps.fromdword(value)
|
||||
end
|
||||
return pos, ipOps.fromdword(value)
|
||||
end
|
||||
end
|
||||
|
||||
---Read a string. The length of the string is given by the length field.
|
||||
|
|
@ -86,7 +86,7 @@ end
|
|||
--@return The new position (will always be pos + length, no matter what we think it should be)
|
||||
--@return The value of the field, or nil if the field length was wrong.
|
||||
local function read_string(data, pos, length)
|
||||
return bin.unpack(string.format("A%d", length), data, pos)
|
||||
return bin.unpack(string.format("A%d", length), data, pos)
|
||||
end
|
||||
|
||||
---Read a single byte. Print an error if the length isn't 1.
|
||||
|
|
@ -97,12 +97,12 @@ end
|
|||
--@return The new position (will always be pos + length, no matter what we think it should be)
|
||||
--@return The value of the field, or nil if the field length was wrong.
|
||||
local function read_1_byte(data, pos, length)
|
||||
if(length ~= 1) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be %d)", length, 1)
|
||||
pos = pos + length
|
||||
return pos, nil
|
||||
end
|
||||
return bin.unpack("C", data, pos)
|
||||
if(length ~= 1) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be %d)", length, 1)
|
||||
pos = pos + length
|
||||
return pos, nil
|
||||
end
|
||||
return bin.unpack("C", data, pos)
|
||||
end
|
||||
|
||||
---Read a message type. This is a single-byte value that's looked up in the <code>request_types_str</code>
|
||||
|
|
@ -114,15 +114,15 @@ end
|
|||
--@return The new position (will always be pos + length, no matter what we think it should be)
|
||||
--@return The value of the field, or nil if the field length was wrong.
|
||||
local function read_message_type(data, pos, length)
|
||||
local value
|
||||
local value
|
||||
|
||||
pos, value = read_1_byte(data, pos, length)
|
||||
if(value == nil) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Couldn't read the 1-byte message type")
|
||||
return pos, nil
|
||||
end
|
||||
pos, value = read_1_byte(data, pos, length)
|
||||
if(value == nil) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Couldn't read the 1-byte message type")
|
||||
return pos, nil
|
||||
end
|
||||
|
||||
return pos, request_types_str[value]
|
||||
return pos, request_types_str[value]
|
||||
end
|
||||
|
||||
---Read a single byte, and return 'false' if it's 0, or 'true' if it's non-zero. Print an error if the
|
||||
|
|
@ -134,17 +134,17 @@ end
|
|||
--@return The new position (will always be pos + length, no matter what we think it should be)
|
||||
--@return The value of the field, or nil if the field length was wrong.
|
||||
local function read_boolean(data, pos, length)
|
||||
local result
|
||||
pos, result = read_1_byte(data, pos, length)
|
||||
local result
|
||||
pos, result = read_1_byte(data, pos, length)
|
||||
|
||||
if(result == nil) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Couldn't read the 1-byte boolean")
|
||||
return pos, nil
|
||||
elseif(result == 0) then
|
||||
return pos, "false"
|
||||
else
|
||||
return pos, "true"
|
||||
end
|
||||
if(result == nil) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Couldn't read the 1-byte boolean")
|
||||
return pos, nil
|
||||
elseif(result == 0) then
|
||||
return pos, "false"
|
||||
else
|
||||
return pos, "true"
|
||||
end
|
||||
end
|
||||
|
||||
---Read a 2-byte unsigned little endian value. Print an error if the length isn't 2.
|
||||
|
|
@ -155,12 +155,12 @@ end
|
|||
--@return The new position (will always be pos + length, no matter what we think it should be)
|
||||
--@return The value of the field, or nil if the field length was wrong.
|
||||
local function read_2_bytes(data, pos, length)
|
||||
if(length ~= 2) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be %d)", length, 2)
|
||||
pos = pos + length
|
||||
return pos, nil
|
||||
end
|
||||
return bin.unpack(">S", data, pos)
|
||||
if(length ~= 2) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be %d)", length, 2)
|
||||
pos = pos + length
|
||||
return pos, nil
|
||||
end
|
||||
return bin.unpack(">S", data, pos)
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -173,21 +173,21 @@ end
|
|||
--@return The new position (will always be pos + length, no matter what we think it should be)
|
||||
--@return The value of the field, or nil if the field length was wrong.
|
||||
local function read_2_bytes_list(data, pos, length)
|
||||
if((length % 2) ~= 0) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be multiple of %d)", length, 2)
|
||||
pos = pos + length
|
||||
if((length % 2) ~= 0) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be multiple of %d)", length, 2)
|
||||
pos = pos + length
|
||||
|
||||
return pos, nil
|
||||
else
|
||||
local results = {}
|
||||
for i=1, length, 2 do
|
||||
local value
|
||||
pos, value = bin.unpack(">S", data, pos)
|
||||
table.insert(results, value)
|
||||
end
|
||||
return pos, nil
|
||||
else
|
||||
local results = {}
|
||||
for i=1, length, 2 do
|
||||
local value
|
||||
pos, value = bin.unpack(">S", data, pos)
|
||||
table.insert(results, value)
|
||||
end
|
||||
|
||||
return pos, results
|
||||
end
|
||||
return pos, results
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -199,12 +199,12 @@ end
|
|||
--@return The new position (will always be pos + length, no matter what we think it should be)
|
||||
--@return The value of the field, or nil if the field length was wrong.
|
||||
local function read_4_bytes(data, pos, length)
|
||||
if(length ~= 4) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be %d)", length, 4)
|
||||
pos = pos + length
|
||||
return pos, nil
|
||||
end
|
||||
return bin.unpack(">I", data, pos)
|
||||
if(length ~= 4) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be %d)", length, 4)
|
||||
pos = pos + length
|
||||
return pos, nil
|
||||
end
|
||||
return bin.unpack(">I", data, pos)
|
||||
end
|
||||
|
||||
---Read a 4-byte unsigned little endian value, and interpret it as a time offset value. Print an
|
||||
|
|
@ -216,32 +216,32 @@ end
|
|||
--@return The new position (will always be pos + length, no matter what we think it should be)
|
||||
--@return The value of the field, or nil if the field length was wrong.
|
||||
local function read_time(data, pos, length)
|
||||
local result
|
||||
if(length ~= 4) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be %d)", length, 4)
|
||||
pos = pos + length
|
||||
return pos, nil
|
||||
end
|
||||
pos, result = bin.unpack(">I", data, pos)
|
||||
local result
|
||||
if(length ~= 4) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be %d)", length, 4)
|
||||
pos = pos + length
|
||||
return pos, nil
|
||||
end
|
||||
pos, result = bin.unpack(">I", data, pos)
|
||||
|
||||
-- This code was mostly taken from snmp-sysdescr.nse. It should probably be abstracted into stdnse.lua [TODO]
|
||||
local days, hours, minutes, seconds, htime, mtime, stime
|
||||
days = math.floor(result / 86400)
|
||||
htime = math.fmod(result, 86400)
|
||||
hours = math.floor(htime / 3600)
|
||||
mtime = math.fmod(htime, 3600)
|
||||
minutes = math.floor(mtime / 60)
|
||||
seconds = math.fmod(mtime, 60)
|
||||
-- This code was mostly taken from snmp-sysdescr.nse. It should probably be abstracted into stdnse.lua [TODO]
|
||||
local days, hours, minutes, seconds, htime, mtime, stime
|
||||
days = math.floor(result / 86400)
|
||||
htime = math.fmod(result, 86400)
|
||||
hours = math.floor(htime / 3600)
|
||||
mtime = math.fmod(htime, 3600)
|
||||
minutes = math.floor(mtime / 60)
|
||||
seconds = math.fmod(mtime, 60)
|
||||
|
||||
local dayLabel
|
||||
local dayLabel
|
||||
|
||||
if days == 1 then
|
||||
dayLabel = "day"
|
||||
else
|
||||
dayLabel = "days"
|
||||
end
|
||||
if days == 1 then
|
||||
dayLabel = "day"
|
||||
else
|
||||
dayLabel = "days"
|
||||
end
|
||||
|
||||
return pos, string.format("%d %s, %d:%02d:%02d", days, dayLabel, hours, minutes, seconds)
|
||||
return pos, string.format("%d %s, %d:%02d:%02d", days, dayLabel, hours, minutes, seconds)
|
||||
end
|
||||
|
||||
---Read a list of static routes. Each of them are a pair of IP addresses, a destination and a
|
||||
|
|
@ -253,22 +253,22 @@ end
|
|||
--@return The new position (will always be pos + length, no matter what we think it should be)
|
||||
--@return The value of the field, or nil if the field length was wrong.
|
||||
local function read_static_route(data, pos, length)
|
||||
if((length % 8) ~= 0) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be multiple of %d)", length, 8)
|
||||
pos = pos + length
|
||||
if((length % 8) ~= 0) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be multiple of %d)", length, 8)
|
||||
pos = pos + length
|
||||
|
||||
return pos, nil
|
||||
else
|
||||
local results = {}
|
||||
for i=1, length, 8 do
|
||||
local destination, router
|
||||
pos, destination = read_ip(data, pos, 4)
|
||||
pos, router = read_ip(data, pos, 4)
|
||||
table.insert(results, {destination=destination, router=router})
|
||||
end
|
||||
return pos, nil
|
||||
else
|
||||
local results = {}
|
||||
for i=1, length, 8 do
|
||||
local destination, router
|
||||
pos, destination = read_ip(data, pos, 4)
|
||||
pos, router = read_ip(data, pos, 4)
|
||||
table.insert(results, {destination=destination, router=router})
|
||||
end
|
||||
|
||||
return pos, results
|
||||
end
|
||||
return pos, results
|
||||
end
|
||||
end
|
||||
|
||||
---Read a list of policy filters. Each of them are a pair of IP addresses, an address and a
|
||||
|
|
@ -280,22 +280,22 @@ end
|
|||
--@return The new position (will always be pos + length, no matter what we think it should be)
|
||||
--@return The value of the field, or nil if the field length was wrong.
|
||||
local function read_policy_filter(data, pos, length)
|
||||
if((length % 8) ~= 0) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be multiple of %d)", length, 8)
|
||||
pos = pos + length
|
||||
if((length % 8) ~= 0) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be multiple of %d)", length, 8)
|
||||
pos = pos + length
|
||||
|
||||
return pos, nil
|
||||
else
|
||||
local results = {}
|
||||
for i=1, length, 8 do
|
||||
local address, router, mask
|
||||
pos, address = read_ip(data, pos, 4)
|
||||
pos, mask = read_ip(data, pos, 4)
|
||||
table.insert(results, {address=address, mask=mask})
|
||||
end
|
||||
return pos, nil
|
||||
else
|
||||
local results = {}
|
||||
for i=1, length, 8 do
|
||||
local address, router, mask
|
||||
pos, address = read_ip(data, pos, 4)
|
||||
pos, mask = read_ip(data, pos, 4)
|
||||
table.insert(results, {address=address, mask=mask})
|
||||
end
|
||||
|
||||
return pos, results
|
||||
end
|
||||
return pos, results
|
||||
end
|
||||
end
|
||||
|
||||
---These are the different fields for DHCP. These have to come after the read_* function
|
||||
|
|
@ -366,25 +366,25 @@ actions[252]= {name="WPAD", func=read_string,
|
|||
|
||||
--- Does the send/receive, doesn't build/parse anything.
|
||||
local function dhcp_send(socket, host, packet)
|
||||
-- Send out the packet
|
||||
return socket:sendto(host, { number=67, protocol="udp" }, packet)
|
||||
-- Send out the packet
|
||||
return socket:sendto(host, { number=67, protocol="udp" }, packet)
|
||||
end
|
||||
|
||||
local function dhcp_receive(socket, transaction_id)
|
||||
|
||||
local status, data = socket:receive()
|
||||
if ( not(status) ) then
|
||||
socket:close()
|
||||
return false, data
|
||||
end
|
||||
local status, data = socket:receive()
|
||||
if ( not(status) ) then
|
||||
socket:close()
|
||||
return false, data
|
||||
end
|
||||
|
||||
-- This pulls back 4 bytes in the packet that correspond to the transaction id. This should be randomly
|
||||
-- generated and different for every instance of a script (to prevent collisions)
|
||||
while status and data:sub(5, 8) ~= transaction_id do
|
||||
status, data = socket:receive()
|
||||
end
|
||||
-- This pulls back 4 bytes in the packet that correspond to the transaction id. This should be randomly
|
||||
-- generated and different for every instance of a script (to prevent collisions)
|
||||
while status and data:sub(5, 8) ~= transaction_id do
|
||||
status, data = socket:receive()
|
||||
end
|
||||
|
||||
return status, data
|
||||
return status, data
|
||||
end
|
||||
|
||||
--- Builds a DHCP packet
|
||||
|
|
@ -417,58 +417,58 @@ end
|
|||
--@return status (true or false)
|
||||
--@return The parsed response, as a table.
|
||||
function dhcp_build(request_type, ip_address, mac_address, options, request_options, overrides, lease_time, transaction_id)
|
||||
local packet = ''
|
||||
local packet = ''
|
||||
|
||||
-- Set up the default overrides
|
||||
if(overrides == nil) then
|
||||
overrides = {}
|
||||
end
|
||||
-- Set up the default overrides
|
||||
if(overrides == nil) then
|
||||
overrides = {}
|
||||
end
|
||||
|
||||
if(request_options == nil) then
|
||||
-- Request the defaults, or there's no verbosity; otherwise, request everything!
|
||||
request_options = ''
|
||||
for i = 1, 61, 1 do
|
||||
if(nmap.verbosity() > 0) then
|
||||
request_options = request_options .. string.char(i)
|
||||
else
|
||||
if(actions[i] and actions[i].default) then
|
||||
request_options = request_options .. string.char(i)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if(request_options == nil) then
|
||||
-- Request the defaults, or there's no verbosity; otherwise, request everything!
|
||||
request_options = ''
|
||||
for i = 1, 61, 1 do
|
||||
if(nmap.verbosity() > 0) then
|
||||
request_options = request_options .. string.char(i)
|
||||
else
|
||||
if(actions[i] and actions[i].default) then
|
||||
request_options = request_options .. string.char(i)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Header
|
||||
packet = packet .. bin.pack(">CCCC", overrides['op'] or 1, overrides['htype'] or 1, overrides['hlen'] or 6, overrides['hops'] or 0) -- BOOTREQUEST, 10mb ethernet, 6 bytes long, 0 hops
|
||||
packet = packet .. ( overrides['xid'] or transaction_id ) -- Transaction ID =
|
||||
packet = packet .. bin.pack(">SS", overrides['secs'] or 0, overrides['flags'] or 0x0000) -- Secs, flags
|
||||
packet = packet .. bin.pack("A", ip_address) -- Client address
|
||||
packet = packet .. bin.pack("<I", overrides['yiaddr'] or 0) -- yiaddr
|
||||
packet = packet .. bin.pack("<I", overrides['siaddr'] or 0) -- siaddr
|
||||
packet = packet .. bin.pack("<I", overrides['giaddr'] or 0) -- giaddr
|
||||
packet = packet .. mac_address .. string.rep(string.char(0), 16 - #mac_address) -- chaddr (MAC address)
|
||||
packet = packet .. (overrides['sname'] or string.rep(string.char(0), 64)) -- sname
|
||||
packet = packet .. (overrides['file'] or string.rep(string.char(0), 128)) -- file
|
||||
packet = packet .. bin.pack(">I", overrides['cookie'] or 0x63825363) -- Magic cookie
|
||||
-- Header
|
||||
packet = packet .. bin.pack(">CCCC", overrides['op'] or 1, overrides['htype'] or 1, overrides['hlen'] or 6, overrides['hops'] or 0) -- BOOTREQUEST, 10mb ethernet, 6 bytes long, 0 hops
|
||||
packet = packet .. ( overrides['xid'] or transaction_id ) -- Transaction ID =
|
||||
packet = packet .. bin.pack(">SS", overrides['secs'] or 0, overrides['flags'] or 0x0000) -- Secs, flags
|
||||
packet = packet .. bin.pack("A", ip_address) -- Client address
|
||||
packet = packet .. bin.pack("<I", overrides['yiaddr'] or 0) -- yiaddr
|
||||
packet = packet .. bin.pack("<I", overrides['siaddr'] or 0) -- siaddr
|
||||
packet = packet .. bin.pack("<I", overrides['giaddr'] or 0) -- giaddr
|
||||
packet = packet .. mac_address .. string.rep(string.char(0), 16 - #mac_address) -- chaddr (MAC address)
|
||||
packet = packet .. (overrides['sname'] or string.rep(string.char(0), 64)) -- sname
|
||||
packet = packet .. (overrides['file'] or string.rep(string.char(0), 128)) -- file
|
||||
packet = packet .. bin.pack(">I", overrides['cookie'] or 0x63825363) -- Magic cookie
|
||||
|
||||
-- Options
|
||||
packet = packet .. bin.pack(">CCC", 0x35, 1, request_type) -- Request type
|
||||
-- Options
|
||||
packet = packet .. bin.pack(">CCC", 0x35, 1, request_type) -- Request type
|
||||
|
||||
for _, option in ipairs(options or {}) do
|
||||
packet = packet .. bin.pack(">C", option.number)
|
||||
if ( "string" == option.type ) then
|
||||
packet = packet .. bin.pack("p", option.value)
|
||||
elseif( "ip" == option.type ) then
|
||||
packet = packet .. bin.pack(">CI", 4, option.value)
|
||||
end
|
||||
end
|
||||
for _, option in ipairs(options or {}) do
|
||||
packet = packet .. bin.pack(">C", option.number)
|
||||
if ( "string" == option.type ) then
|
||||
packet = packet .. bin.pack("p", option.value)
|
||||
elseif( "ip" == option.type ) then
|
||||
packet = packet .. bin.pack(">CI", 4, option.value)
|
||||
end
|
||||
end
|
||||
|
||||
packet = packet .. bin.pack(">CCA", 0x37, #request_options, request_options) -- Request options
|
||||
packet = packet .. bin.pack(">CCI", 0x33, 4, lease_time or 1) -- Lease time
|
||||
packet = packet .. bin.pack(">CCA", 0x37, #request_options, request_options) -- Request options
|
||||
packet = packet .. bin.pack(">CCI", 0x33, 4, lease_time or 1) -- Lease time
|
||||
|
||||
packet = packet .. bin.pack(">C", 0xFF) -- Termination
|
||||
packet = packet .. bin.pack(">C", 0xFF) -- Termination
|
||||
|
||||
return true, packet
|
||||
return true, packet
|
||||
end
|
||||
|
||||
---Parse a DHCP packet (either a request or a response) and return the results as a table. The
|
||||
|
|
@ -480,96 +480,96 @@ end
|
|||
--@param data The DHCP packet data. Any padding at the end of the packet will be ignored (by default,
|
||||
-- DHCP packets are padded with \x00 bytes).
|
||||
function dhcp_parse(data, transaction_id)
|
||||
local pos = 1
|
||||
local result = {}
|
||||
local pos = 1
|
||||
local result = {}
|
||||
|
||||
-- Receive the first bit and make sure we got the correct operation back
|
||||
pos, result['op'], result['htype'], result['hlen'], result['hops'] = bin.unpack(">CCCC", data, pos)
|
||||
if(result['op'] ~= 2) then
|
||||
return false, string.format("DHCP server returned invalid reply ('op' wasn't BOOTREPLY (it was 0x%02x))", result['op'])
|
||||
end
|
||||
-- Receive the first bit and make sure we got the correct operation back
|
||||
pos, result['op'], result['htype'], result['hlen'], result['hops'] = bin.unpack(">CCCC", data, pos)
|
||||
if(result['op'] ~= 2) then
|
||||
return false, string.format("DHCP server returned invalid reply ('op' wasn't BOOTREPLY (it was 0x%02x))", result['op'])
|
||||
end
|
||||
|
||||
-- Confirm the transaction id
|
||||
pos, result['xid'] = bin.unpack("A4", data, pos)
|
||||
if(result['xid'] ~= transaction_id) then
|
||||
return false, string.format("DHCP server returned invalid reply (transaction id didn't match (%s != %s))", result['xid'], transaction_id)
|
||||
end
|
||||
-- Confirm the transaction id
|
||||
pos, result['xid'] = bin.unpack("A4", data, pos)
|
||||
if(result['xid'] ~= transaction_id) then
|
||||
return false, string.format("DHCP server returned invalid reply (transaction id didn't match (%s != %s))", result['xid'], transaction_id)
|
||||
end
|
||||
|
||||
-- Unpack the secs, flags, addresses, sname, and file
|
||||
pos, result['secs'], result['flags'] = bin.unpack(">SS", data, pos)
|
||||
pos, result['ciaddr'] = bin.unpack("<I", data, pos)
|
||||
pos, result['yiaddr'] = bin.unpack("<I", data, pos)
|
||||
pos, result['siaddr'] = bin.unpack("<I", data, pos)
|
||||
pos, result['giaddr'] = bin.unpack("<I", data, pos)
|
||||
pos, result['chaddr'] = bin.unpack("A16", data, pos)
|
||||
pos, result['sname'] = bin.unpack("A64", data, pos)
|
||||
pos, result['file'] = bin.unpack("A128", data, pos)
|
||||
-- Unpack the secs, flags, addresses, sname, and file
|
||||
pos, result['secs'], result['flags'] = bin.unpack(">SS", data, pos)
|
||||
pos, result['ciaddr'] = bin.unpack("<I", data, pos)
|
||||
pos, result['yiaddr'] = bin.unpack("<I", data, pos)
|
||||
pos, result['siaddr'] = bin.unpack("<I", data, pos)
|
||||
pos, result['giaddr'] = bin.unpack("<I", data, pos)
|
||||
pos, result['chaddr'] = bin.unpack("A16", data, pos)
|
||||
pos, result['sname'] = bin.unpack("A64", data, pos)
|
||||
pos, result['file'] = bin.unpack("A128", data, pos)
|
||||
|
||||
-- Convert the addresses to strings
|
||||
result['ciaddr_str'] = ipOps.fromdword(result['ciaddr'])
|
||||
result['yiaddr_str'] = ipOps.fromdword(result['yiaddr'])
|
||||
result['siaddr_str'] = ipOps.fromdword(result['siaddr'])
|
||||
result['giaddr_str'] = ipOps.fromdword(result['giaddr'])
|
||||
-- Convert the addresses to strings
|
||||
result['ciaddr_str'] = ipOps.fromdword(result['ciaddr'])
|
||||
result['yiaddr_str'] = ipOps.fromdword(result['yiaddr'])
|
||||
result['siaddr_str'] = ipOps.fromdword(result['siaddr'])
|
||||
result['giaddr_str'] = ipOps.fromdword(result['giaddr'])
|
||||
|
||||
-- Confirm the cookie
|
||||
pos, result['cookie'] = bin.unpack(">I", data, pos)
|
||||
if(result['cookie'] ~= 0x63825363) then
|
||||
return false, "DHCP server returned invalid reply (the magic cookie was invalid)"
|
||||
end
|
||||
-- Confirm the cookie
|
||||
pos, result['cookie'] = bin.unpack(">I", data, pos)
|
||||
if(result['cookie'] ~= 0x63825363) then
|
||||
return false, "DHCP server returned invalid reply (the magic cookie was invalid)"
|
||||
end
|
||||
|
||||
-- Parse the options
|
||||
result['options'] = {}
|
||||
while true do
|
||||
local option, length
|
||||
pos, option, length = bin.unpack(">CC", data, pos)
|
||||
-- Parse the options
|
||||
result['options'] = {}
|
||||
while true do
|
||||
local option, length
|
||||
pos, option, length = bin.unpack(">CC", data, pos)
|
||||
|
||||
-- Check for termination condition
|
||||
if(option == 0xFF) then
|
||||
break;
|
||||
end
|
||||
-- Check for termination condition
|
||||
if(option == 0xFF) then
|
||||
break;
|
||||
end
|
||||
|
||||
-- Get the action from the array, based on the code
|
||||
local action = actions[option]
|
||||
-- Get the action from the array, based on the code
|
||||
local action = actions[option]
|
||||
|
||||
-- Verify we got a valid code (if we didn't, we're probably in big trouble)
|
||||
local value
|
||||
if(action == nil) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Unknown option: %d", option)
|
||||
pos = pos + length
|
||||
else
|
||||
-- Call the function to parse the option, and insert the result into our results table
|
||||
-- Verify we got a valid code (if we didn't, we're probably in big trouble)
|
||||
local value
|
||||
if(action == nil) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Unknown option: %d", option)
|
||||
pos = pos + length
|
||||
else
|
||||
-- Call the function to parse the option, and insert the result into our results table
|
||||
|
||||
stdnse.print_debug(2, "dhcp-discover: Attempting to parse %s", action['name'])
|
||||
pos, value = action['func'](data, pos, length)
|
||||
stdnse.print_debug(2, "dhcp-discover: Attempting to parse %s", action['name'])
|
||||
pos, value = action['func'](data, pos, length)
|
||||
|
||||
if(nmap.verbosity() == 0 and action.default == false) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Server returned unrequested option (%s => %s)", action['name'], value)
|
||||
if(nmap.verbosity() == 0 and action.default == false) then
|
||||
stdnse.print_debug(1, "dhcp-discover: Server returned unrequested option (%s => %s)", action['name'], value)
|
||||
|
||||
else
|
||||
if(value) then
|
||||
table.insert(result['options'], {name=action['name'], value=value})
|
||||
else
|
||||
stdnse.print_debug(1, "dhcp-discover: Couldn't determine value for %s", action['name']);
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if(value) then
|
||||
table.insert(result['options'], {name=action['name'], value=value})
|
||||
else
|
||||
stdnse.print_debug(1, "dhcp-discover: Couldn't determine value for %s", action['name']);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Handle the 'Option Overload' option specially -- if it's set, it tells us to use the file and/or sname values after we
|
||||
-- run out of data.
|
||||
if(option == 52) then
|
||||
if(value == 1) then
|
||||
data = data .. result['file']
|
||||
elseif(value == 2) then
|
||||
data = data .. result['sname']
|
||||
elseif(value == 3) then
|
||||
data = data .. result['file'] .. result['sname']
|
||||
else
|
||||
stdnse.print_debug(1, "dhcp-discover: Warning: 'Option Overload' gave an unsupported value: %d", value)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Handle the 'Option Overload' option specially -- if it's set, it tells us to use the file and/or sname values after we
|
||||
-- run out of data.
|
||||
if(option == 52) then
|
||||
if(value == 1) then
|
||||
data = data .. result['file']
|
||||
elseif(value == 2) then
|
||||
data = data .. result['sname']
|
||||
elseif(value == 3) then
|
||||
data = data .. result['file'] .. result['sname']
|
||||
else
|
||||
stdnse.print_debug(1, "dhcp-discover: Warning: 'Option Overload' gave an unsupported value: %d", value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true, result
|
||||
return true, result
|
||||
end
|
||||
|
||||
---Build and send any kind of DHCP packet, and parse the response. This is the only interface
|
||||
|
|
@ -616,43 +616,43 @@ end
|
|||
--@return status (true or false)
|
||||
--@return The parsed response, as a table.
|
||||
function make_request(target, request_type, ip_address, mac_address, options, request_options, overrides, lease_time)
|
||||
-- A unique id that identifies this particular session (and lets us filter out what we don't want to see)
|
||||
local transaction_id = overrides and overrides['xid'] or bin.pack("<I", math.random(0, 0x7FFFFFFF))
|
||||
-- A unique id that identifies this particular session (and lets us filter out what we don't want to see)
|
||||
local transaction_id = overrides and overrides['xid'] or bin.pack("<I", math.random(0, 0x7FFFFFFF))
|
||||
|
||||
-- Generate the packet
|
||||
local status, packet = dhcp_build(request_type, bin.pack(">I", ipOps.todword(ip_address)), mac_address, options, request_options, overrides, lease_time, transaction_id)
|
||||
if(not(status)) then
|
||||
stdnse.print_debug(1, "dhcp: Couldn't build packet: " .. packet)
|
||||
return false, "Couldn't build packet: " .. packet
|
||||
end
|
||||
-- Generate the packet
|
||||
local status, packet = dhcp_build(request_type, bin.pack(">I", ipOps.todword(ip_address)), mac_address, options, request_options, overrides, lease_time, transaction_id)
|
||||
if(not(status)) then
|
||||
stdnse.print_debug(1, "dhcp: Couldn't build packet: " .. packet)
|
||||
return false, "Couldn't build packet: " .. packet
|
||||
end
|
||||
|
||||
local socket = nmap.new_socket("udp")
|
||||
socket:bind(nil, 68)
|
||||
socket:set_timeout(5000)
|
||||
local socket = nmap.new_socket("udp")
|
||||
socket:bind(nil, 68)
|
||||
socket:set_timeout(5000)
|
||||
|
||||
-- Send the packet and get the response
|
||||
local status, response = dhcp_send(socket, target, packet)
|
||||
if(not(status)) then
|
||||
stdnse.print_debug(1, "dhcp: Couldn't send packet: " .. response)
|
||||
return false, "Couldn't send packet: " .. response
|
||||
end
|
||||
-- Send the packet and get the response
|
||||
local status, response = dhcp_send(socket, target, packet)
|
||||
if(not(status)) then
|
||||
stdnse.print_debug(1, "dhcp: Couldn't send packet: " .. response)
|
||||
return false, "Couldn't send packet: " .. response
|
||||
end
|
||||
|
||||
status, response = dhcp_receive(socket, transaction_id)
|
||||
socket:close()
|
||||
status, response = dhcp_receive(socket, transaction_id)
|
||||
socket:close()
|
||||
|
||||
if ( not(status) ) then
|
||||
stdnse.print_debug(1, "dhcp: Couldn't receive packet: " .. response)
|
||||
return false, "Couldn't receive packet: " .. response
|
||||
end
|
||||
if ( not(status) ) then
|
||||
stdnse.print_debug(1, "dhcp: Couldn't receive packet: " .. response)
|
||||
return false, "Couldn't receive packet: " .. response
|
||||
end
|
||||
|
||||
-- Parse the response
|
||||
local status, parsed = dhcp_parse(response, transaction_id)
|
||||
if(not(status)) then
|
||||
stdnse.print_debug(1, "dhcp: Couldn't parse response: " .. parsed)
|
||||
return false, "Couldn't parse response: " .. parsed
|
||||
end
|
||||
-- Parse the response
|
||||
local status, parsed = dhcp_parse(response, transaction_id)
|
||||
if(not(status)) then
|
||||
stdnse.print_debug(1, "dhcp: Couldn't parse response: " .. parsed)
|
||||
return false, "Couldn't parse response: " .. parsed
|
||||
end
|
||||
|
||||
return true, parsed
|
||||
return true, parsed
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
1028
nselib/dhcp6.lua
1028
nselib/dhcp6.lua
File diff suppressed because it is too large
Load diff
1676
nselib/dns.lua
1676
nselib/dns.lua
File diff suppressed because it is too large
Load diff
1164
nselib/dnsbl.lua
1164
nselib/dnsbl.lua
File diff suppressed because it is too large
Load diff
1178
nselib/drda.lua
1178
nselib/drda.lua
File diff suppressed because it is too large
Load diff
992
nselib/giop.lua
992
nselib/giop.lua
File diff suppressed because it is too large
Load diff
728
nselib/ike.lua
728
nselib/ike.lua
|
|
@ -12,19 +12,19 @@ description = [[
|
|||
A very basic IKE library.
|
||||
|
||||
The current funcionality includes:
|
||||
1. Generating a Main or Aggressive Mode IKE request packet with a variable amount of transforms and a vpn group.
|
||||
2. Sending a packet
|
||||
3. Receiving the response
|
||||
4. Parsing the response for VIDs
|
||||
5. Searching for the VIDs in 'ike-fingerprints.lua'
|
||||
6. returning a parsed info table
|
||||
1. Generating a Main or Aggressive Mode IKE request packet with a variable amount of transforms and a vpn group.
|
||||
2. Sending a packet
|
||||
3. Receiving the response
|
||||
4. Parsing the response for VIDs
|
||||
5. Searching for the VIDs in 'ike-fingerprints.lua'
|
||||
6. returning a parsed info table
|
||||
|
||||
This library is meant for extension, which could include:
|
||||
1. complete parsing of the response packet (might allow for better fingerprinting)
|
||||
2. adding more options to the request packet
|
||||
vendor field (might give better fingerprinting of services, e.g. Checkpoint)
|
||||
3. backoff pattern analyses
|
||||
...
|
||||
1. complete parsing of the response packet (might allow for better fingerprinting)
|
||||
2. adding more options to the request packet
|
||||
vendor field (might give better fingerprinting of services, e.g. Checkpoint)
|
||||
3. backoff pattern analyses
|
||||
...
|
||||
|
||||
An a implementation resembling 'ike-scan' could be built.
|
||||
]]
|
||||
|
|
@ -37,64 +37,64 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
|||
categories = {"discovery", "safe"}
|
||||
|
||||
local ENC_METHODS = {
|
||||
["des"] = 0x80010001,
|
||||
["3des"] = 0x80010005,
|
||||
["cast"] = 0x80010006,
|
||||
["aes/128"] = { 0x80010007, 0x800E0080 },
|
||||
["aes/192"] = { 0x80010007, 0x800E00C0 },
|
||||
["aes/256"] = { 0x80010007, 0x800E0100 },
|
||||
["des"] = 0x80010001,
|
||||
["3des"] = 0x80010005,
|
||||
["cast"] = 0x80010006,
|
||||
["aes/128"] = { 0x80010007, 0x800E0080 },
|
||||
["aes/192"] = { 0x80010007, 0x800E00C0 },
|
||||
["aes/256"] = { 0x80010007, 0x800E0100 },
|
||||
}
|
||||
|
||||
local AUTH_TYPES = {
|
||||
["psk"] = 0x80030001,
|
||||
["rsa"] = 0x80030003,
|
||||
["ECDSA"] = 0x80030008,
|
||||
["Hybrid"] = 0x8003FADD,
|
||||
["XAUTH"] = 0x8003FDE9,
|
||||
["psk"] = 0x80030001,
|
||||
["rsa"] = 0x80030003,
|
||||
["ECDSA"] = 0x80030008,
|
||||
["Hybrid"] = 0x8003FADD,
|
||||
["XAUTH"] = 0x8003FDE9,
|
||||
}
|
||||
|
||||
local HASH_ALGORITHM = {
|
||||
["md5"] = 0x80020001,
|
||||
["sha1"] = 0x80020002,
|
||||
["sha2-256"] = 0x80020004,
|
||||
["sha2-384"] = 0x80020005,
|
||||
["sha2-512"] = 0x80020006,
|
||||
["md5"] = 0x80020001,
|
||||
["sha1"] = 0x80020002,
|
||||
["sha2-256"] = 0x80020004,
|
||||
["sha2-384"] = 0x80020005,
|
||||
["sha2-512"] = 0x80020006,
|
||||
}
|
||||
|
||||
local GROUP_DESCRIPTION = {
|
||||
["768"] = 0x80040001,
|
||||
["1024"] = 0x80040002,
|
||||
["1536"] = 0x80040005,
|
||||
["2048"] = 0x0004000E,
|
||||
["768"] = 0x80040001,
|
||||
["1024"] = 0x80040002,
|
||||
["1536"] = 0x80040005,
|
||||
["2048"] = 0x0004000E,
|
||||
}
|
||||
|
||||
local EXCHANGE_MODE = {
|
||||
["Main"] = 0x02,
|
||||
["Aggressive"] = 0x04,
|
||||
["Main"] = 0x02,
|
||||
["Aggressive"] = 0x04,
|
||||
}
|
||||
|
||||
local PROTOCOL_IDS = {
|
||||
["tcp"] = "06",
|
||||
["udp"] = "11",
|
||||
["tcp"] = "06",
|
||||
["udp"] = "11",
|
||||
}
|
||||
|
||||
-- Response packet types
|
||||
local EXCHANGE_TYPE = {
|
||||
["02"] = "Main",
|
||||
["04"] = "Aggressive",
|
||||
["05"] = "Informational",
|
||||
["02"] = "Main",
|
||||
["04"] = "Aggressive",
|
||||
["05"] = "Informational",
|
||||
}
|
||||
|
||||
-- Payload names
|
||||
local PAYLOADS = {
|
||||
["00"] = "None",
|
||||
["01"] = "SA",
|
||||
["03"] = "Transform",
|
||||
["04"] = "Key Exchange",
|
||||
["05"] = "ID",
|
||||
["08"] = "Hash",
|
||||
["0A"] = "Nonce",
|
||||
["0D"] = "VID",
|
||||
["00"] = "None",
|
||||
["01"] = "SA",
|
||||
["03"] = "Transform",
|
||||
["04"] = "Key Exchange",
|
||||
["05"] = "ID",
|
||||
["08"] = "Hash",
|
||||
["0A"] = "Nonce",
|
||||
["0D"] = "VID",
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -102,98 +102,98 @@ local PAYLOADS = {
|
|||
-- (located in: nselib/data/ike-fingerprints.lua)
|
||||
--
|
||||
local function load_fingerprints()
|
||||
local file, filename_full, fingerprints
|
||||
local file, filename_full, fingerprints
|
||||
|
||||
-- Check if fingerprints are cached
|
||||
if(nmap.registry.ike_fingerprints ~= nil) then
|
||||
stdnse.print_debug(1, "ike: Loading cached fingerprints")
|
||||
return nmap.registry.ike_fingerprints
|
||||
end
|
||||
-- Check if fingerprints are cached
|
||||
if(nmap.registry.ike_fingerprints ~= nil) then
|
||||
stdnse.print_debug(1, "ike: Loading cached fingerprints")
|
||||
return nmap.registry.ike_fingerprints
|
||||
end
|
||||
|
||||
-- Try and find the file
|
||||
-- If it isn't in Nmap's directories, take it as a direct path
|
||||
filename_full = nmap.fetchfile('nselib/data/ike-fingerprints.lua')
|
||||
-- Try and find the file
|
||||
-- If it isn't in Nmap's directories, take it as a direct path
|
||||
filename_full = nmap.fetchfile('nselib/data/ike-fingerprints.lua')
|
||||
|
||||
-- Load the file
|
||||
stdnse.print_debug(1, "ike: Loading fingerprints: %s", filename_full)
|
||||
local env = setmetatable({fingerprints = {}}, {__index = _G});
|
||||
file = loadfile(filename_full, "t", env)
|
||||
if( not(file) ) then
|
||||
stdnse.print_debug(1, "ike: Couldn't load the file: %s", filename_full)
|
||||
return false, "Couldn't load fingerprint file: " .. filename_full
|
||||
end
|
||||
file()
|
||||
fingerprints = env.fingerprints
|
||||
-- Load the file
|
||||
stdnse.print_debug(1, "ike: Loading fingerprints: %s", filename_full)
|
||||
local env = setmetatable({fingerprints = {}}, {__index = _G});
|
||||
file = loadfile(filename_full, "t", env)
|
||||
if( not(file) ) then
|
||||
stdnse.print_debug(1, "ike: Couldn't load the file: %s", filename_full)
|
||||
return false, "Couldn't load fingerprint file: " .. filename_full
|
||||
end
|
||||
file()
|
||||
fingerprints = env.fingerprints
|
||||
|
||||
-- Check there are fingerprints to use
|
||||
if(#fingerprints == 0 ) then
|
||||
return false, "No fingerprints were loaded after processing ".. filename_full
|
||||
end
|
||||
-- Check there are fingerprints to use
|
||||
if(#fingerprints == 0 ) then
|
||||
return false, "No fingerprints were loaded after processing ".. filename_full
|
||||
end
|
||||
|
||||
return true, fingerprints
|
||||
return true, fingerprints
|
||||
end
|
||||
|
||||
|
||||
-- generate a random hex-string of length 'length'
|
||||
--
|
||||
local function generate_random(length)
|
||||
local rnd = ""
|
||||
local rnd = ""
|
||||
|
||||
for i=1, length do
|
||||
rnd = rnd .. string.format("%.2X", math.random(255))
|
||||
end
|
||||
return rnd
|
||||
for i=1, length do
|
||||
rnd = rnd .. string.format("%.2X", math.random(255))
|
||||
end
|
||||
return rnd
|
||||
end
|
||||
|
||||
|
||||
-- convert a string to a hex-string (of the ASCII representation)
|
||||
--
|
||||
local function convert_to_hex(id)
|
||||
local hex_str = ""
|
||||
for c in string.gmatch(id, ".") do
|
||||
hex_str = hex_str .. string.format("%X", c:byte())
|
||||
end
|
||||
return hex_str
|
||||
local hex_str = ""
|
||||
for c in string.gmatch(id, ".") do
|
||||
hex_str = hex_str .. string.format("%X", c:byte())
|
||||
end
|
||||
return hex_str
|
||||
end
|
||||
|
||||
|
||||
-- Extract Payloads
|
||||
local function extract_payloads(packet)
|
||||
|
||||
-- packet only contains HDR
|
||||
if packet:len() < 61 then return {} end
|
||||
-- packet only contains HDR
|
||||
if packet:len() < 61 then return {} end
|
||||
|
||||
local np = packet:sub(33,34) -- next payload
|
||||
local index = 61 -- starting point for search
|
||||
local ike_headers = {} -- ike headers
|
||||
local payload = ''
|
||||
local np = packet:sub(33,34) -- next payload
|
||||
local index = 61 -- starting point for search
|
||||
local ike_headers = {} -- ike headers
|
||||
local payload = ''
|
||||
|
||||
-- loop over packet
|
||||
while PAYLOADS[np] ~= "None" and index <= packet:len() do
|
||||
local payload_length = tonumber("0x"..packet:sub(index, index+3)) * 2
|
||||
payload = string.lower(packet:sub(index+4, index+payload_length-5))
|
||||
-- loop over packet
|
||||
while PAYLOADS[np] ~= "None" and index <= packet:len() do
|
||||
local payload_length = tonumber("0x"..packet:sub(index, index+3)) * 2
|
||||
payload = string.lower(packet:sub(index+4, index+payload_length-5))
|
||||
|
||||
-- debug
|
||||
if PAYLOADS[np] == 'VID' then
|
||||
stdnse.print_debug(2, 'IKE: Found IKE Header: %s: %s - %s', np, PAYLOADS[np], payload)
|
||||
else
|
||||
stdnse.print_debug(2, 'IKE: Found IKE Header: %s: %s', np, PAYLOADS[np])
|
||||
end
|
||||
-- debug
|
||||
if PAYLOADS[np] == 'VID' then
|
||||
stdnse.print_debug(2, 'IKE: Found IKE Header: %s: %s - %s', np, PAYLOADS[np], payload)
|
||||
else
|
||||
stdnse.print_debug(2, 'IKE: Found IKE Header: %s: %s', np, PAYLOADS[np])
|
||||
end
|
||||
|
||||
-- Store payload
|
||||
if ike_headers[PAYLOADS[np]] == nil then
|
||||
ike_headers[PAYLOADS[np]] = {payload}
|
||||
else
|
||||
table.insert(ike_headers[PAYLOADS[np]], payload)
|
||||
end
|
||||
-- Store payload
|
||||
if ike_headers[PAYLOADS[np]] == nil then
|
||||
ike_headers[PAYLOADS[np]] = {payload}
|
||||
else
|
||||
table.insert(ike_headers[PAYLOADS[np]], payload)
|
||||
end
|
||||
|
||||
-- find the next payload type
|
||||
np = packet:sub(index-4, index-3)
|
||||
-- find the next payload type
|
||||
np = packet:sub(index-4, index-3)
|
||||
|
||||
-- jump to the next payload
|
||||
index = index + payload_length
|
||||
end
|
||||
return ike_headers
|
||||
-- jump to the next payload
|
||||
index = index + payload_length
|
||||
end
|
||||
return ike_headers
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -201,152 +201,152 @@ end
|
|||
|
||||
|
||||
-- Search the fingerprint database for matches
|
||||
-- This is a (currently) divided into two parts
|
||||
-- 1) version detection based on single fingerprints
|
||||
-- 2) version detection based on the order of all vendor ids
|
||||
-- This is a (currently) divided into two parts
|
||||
-- 1) version detection based on single fingerprints
|
||||
-- 2) version detection based on the order of all vendor ids
|
||||
--
|
||||
-- NOTE: the second step currently only has support for CISCO devices
|
||||
-- NOTE: the second step currently only has support for CISCO devices
|
||||
--
|
||||
-- Input is a table of collected vendor-ids, output is a table
|
||||
-- with fields:
|
||||
-- vendor, version, name, attributes (table), guess (table), os
|
||||
-- vendor, version, name, attributes (table), guess (table), os
|
||||
local function lookup(vendor_ids)
|
||||
if vendor_ids == {} or vendor_ids == nil then return {} end
|
||||
if vendor_ids == {} or vendor_ids == nil then return {} end
|
||||
|
||||
-- concat all vids to one string
|
||||
local all_vids = ''
|
||||
for _,vid in pairs(vendor_ids) do all_vids = all_vids .. vid end
|
||||
-- concat all vids to one string
|
||||
local all_vids = ''
|
||||
for _,vid in pairs(vendor_ids) do all_vids = all_vids .. vid end
|
||||
|
||||
-- the results
|
||||
local info = {
|
||||
vendor = nil,
|
||||
attribs = {},
|
||||
}
|
||||
-- the results
|
||||
local info = {
|
||||
vendor = nil,
|
||||
attribs = {},
|
||||
}
|
||||
|
||||
local status, fingerprints
|
||||
status, fingerprints = load_fingerprints()
|
||||
local status, fingerprints
|
||||
status, fingerprints = load_fingerprints()
|
||||
|
||||
if status then
|
||||
if status then
|
||||
|
||||
-- loop over the vendor_ids returned in ike request
|
||||
for _,vendor_id in pairs(vendor_ids) do
|
||||
-- loop over the vendor_ids returned in ike request
|
||||
for _,vendor_id in pairs(vendor_ids) do
|
||||
|
||||
-- loop over the fingerprints found in database
|
||||
for _,row in pairs(fingerprints) do
|
||||
-- loop over the fingerprints found in database
|
||||
for _,row in pairs(fingerprints) do
|
||||
|
||||
if vendor_id:find(row.fingerprint) then
|
||||
if vendor_id:find(row.fingerprint) then
|
||||
|
||||
-- if a match is found, check if it's a version detection or attribute
|
||||
if row.category == 'vendor' then
|
||||
local debug_string = ''
|
||||
if row.vendor ~= nil then debug_string = debug_string .. row.vendor .. ' ' end
|
||||
if row.version ~= nil then debug_string = debug_string .. row.version end
|
||||
stdnse.print_debug(2, "IKE: Fingerprint: %s matches %s", vendor_id, debug_string)
|
||||
-- if a match is found, check if it's a version detection or attribute
|
||||
if row.category == 'vendor' then
|
||||
local debug_string = ''
|
||||
if row.vendor ~= nil then debug_string = debug_string .. row.vendor .. ' ' end
|
||||
if row.version ~= nil then debug_string = debug_string .. row.version end
|
||||
stdnse.print_debug(2, "IKE: Fingerprint: %s matches %s", vendor_id, debug_string)
|
||||
|
||||
-- Only store the first match
|
||||
if info.vendor == nil then
|
||||
-- the fingerprint contains information about the VID
|
||||
info.vendor = row
|
||||
end
|
||||
-- Only store the first match
|
||||
if info.vendor == nil then
|
||||
-- the fingerprint contains information about the VID
|
||||
info.vendor = row
|
||||
end
|
||||
|
||||
elseif row.category == 'attribute' then
|
||||
info.attribs[ #info.attribs + 1] = row
|
||||
stdnse.print_debug(2, "IKE: Attribute: %s matches %s", vendor_id, row.text)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif row.category == 'attribute' then
|
||||
info.attribs[ #info.attribs + 1] = row
|
||||
stdnse.print_debug(2, "IKE: Attribute: %s matches %s", vendor_id, row.text)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---------------------------------------------------
|
||||
-- Search for the order of the vids
|
||||
-- Uses category 'vid_ordering'
|
||||
---
|
||||
---------------------------------------------------
|
||||
-- Search for the order of the vids
|
||||
-- Uses category 'vid_ordering'
|
||||
---
|
||||
|
||||
-- search in the 'vid_ordering' category
|
||||
local debug_string = ''
|
||||
for _,row in pairs(fingerprints) do
|
||||
-- search in the 'vid_ordering' category
|
||||
local debug_string = ''
|
||||
for _,row in pairs(fingerprints) do
|
||||
|
||||
if row.category == 'vid_ordering' and all_vids:find(row.fingerprint) then
|
||||
if row.category == 'vid_ordering' and all_vids:find(row.fingerprint) then
|
||||
|
||||
-- Use ordering information if there where no vendor matches from prevoius step
|
||||
if info.vendor == nil then
|
||||
info.vendor = row
|
||||
-- Use ordering information if there where no vendor matches from prevoius step
|
||||
if info.vendor == nil then
|
||||
info.vendor = row
|
||||
|
||||
-- Debugging info
|
||||
debug_string = ''
|
||||
if info.vendor.vendor ~= nil then debug_string = debug_string .. info.vendor.vendor .. ' ' end
|
||||
if info.vendor.version ~= nil then debug_string = debug_string .. info.vendor.version .. ' ' end
|
||||
if info.vendor.ostype ~= nil then debug_string = debug_string .. info.vendor.ostype end
|
||||
stdnse.print_debug(2, 'IKE: No vendor match, but ordering match found: %s', debug_string)
|
||||
-- Debugging info
|
||||
debug_string = ''
|
||||
if info.vendor.vendor ~= nil then debug_string = debug_string .. info.vendor.vendor .. ' ' end
|
||||
if info.vendor.version ~= nil then debug_string = debug_string .. info.vendor.version .. ' ' end
|
||||
if info.vendor.ostype ~= nil then debug_string = debug_string .. info.vendor.ostype end
|
||||
stdnse.print_debug(2, 'IKE: No vendor match, but ordering match found: %s', debug_string)
|
||||
|
||||
return info
|
||||
return info
|
||||
|
||||
-- Update OS based on ordering
|
||||
elseif info.vendor.vendor == row.vendor then
|
||||
info.vendor.ostype = row.ostype
|
||||
-- Update OS based on ordering
|
||||
elseif info.vendor.vendor == row.vendor then
|
||||
info.vendor.ostype = row.ostype
|
||||
|
||||
-- Debugging info
|
||||
debug_string = ''
|
||||
if info.vendor.vendor ~= nil then debug_string = debug_string .. info.vendor.vendor .. ' to ' end
|
||||
if row.ostype ~= nil then debug_string = debug_string .. row.ostype end
|
||||
stdnse.print_debug(2, 'IKE: Vendor and ordering match. OS updated: %s', debug_string)
|
||||
-- Debugging info
|
||||
debug_string = ''
|
||||
if info.vendor.vendor ~= nil then debug_string = debug_string .. info.vendor.vendor .. ' to ' end
|
||||
if row.ostype ~= nil then debug_string = debug_string .. row.ostype end
|
||||
stdnse.print_debug(2, 'IKE: Vendor and ordering match. OS updated: %s', debug_string)
|
||||
|
||||
return info
|
||||
return info
|
||||
|
||||
-- Only print debugging information if conflicting information is detected
|
||||
else
|
||||
-- Debugging info
|
||||
debug_string = ''
|
||||
if info.vendor.vendor ~= nil then debug_string = debug_string .. info.vendor.vendor .. ' vs ' end
|
||||
if row.vendor ~= nil then debug_string = debug_string .. row.vendor end
|
||||
stdnse.print_debug(2, 'IKE: Found an ordering match, but vendors do not match. %s', debug_string)
|
||||
-- Only print debugging information if conflicting information is detected
|
||||
else
|
||||
-- Debugging info
|
||||
debug_string = ''
|
||||
if info.vendor.vendor ~= nil then debug_string = debug_string .. info.vendor.vendor .. ' vs ' end
|
||||
if row.vendor ~= nil then debug_string = debug_string .. row.vendor end
|
||||
stdnse.print_debug(2, 'IKE: Found an ordering match, but vendors do not match. %s', debug_string)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return info
|
||||
return info
|
||||
end
|
||||
|
||||
|
||||
-- Handle a response packet
|
||||
-- A very limited response parser
|
||||
-- Currently only the VIDs are extracted
|
||||
-- This could be made more advanced to
|
||||
-- allow for fingerprinting via the order
|
||||
-- of the returned headers
|
||||
-- A very limited response parser
|
||||
-- Currently only the VIDs are extracted
|
||||
-- This could be made more advanced to
|
||||
-- allow for fingerprinting via the order
|
||||
-- of the returned headers
|
||||
---
|
||||
function response(packet)
|
||||
local resp = { ["mode"] = "", ["info"] = nil, ['vids']={}, ['success'] = false }
|
||||
local resp = { ["mode"] = "", ["info"] = nil, ['vids']={}, ['success'] = false }
|
||||
|
||||
if packet:len() > 38 then
|
||||
if packet:len() > 38 then
|
||||
|
||||
-- extract the return type
|
||||
local resp_type = EXCHANGE_TYPE[packet:sub(37,38)]
|
||||
local ike_headers = {}
|
||||
-- extract the return type
|
||||
local resp_type = EXCHANGE_TYPE[packet:sub(37,38)]
|
||||
local ike_headers = {}
|
||||
|
||||
-- simple check that the type is something other than 'Informational'
|
||||
-- as this type does not include VIDs
|
||||
if resp_type ~= "Informational" then
|
||||
resp["mode"] = resp_type
|
||||
-- simple check that the type is something other than 'Informational'
|
||||
-- as this type does not include VIDs
|
||||
if resp_type ~= "Informational" then
|
||||
resp["mode"] = resp_type
|
||||
|
||||
ike_headers = extract_payloads(packet)
|
||||
ike_headers = extract_payloads(packet)
|
||||
|
||||
-- Extract the VIDs
|
||||
resp['vids'] = ike_headers['VID']
|
||||
-- Extract the VIDs
|
||||
resp['vids'] = ike_headers['VID']
|
||||
|
||||
-- search for fingerprints
|
||||
resp["info"] = lookup(resp['vids'])
|
||||
-- search for fingerprints
|
||||
resp["info"] = lookup(resp['vids'])
|
||||
|
||||
-- indicate that a packet 'useful' packet was returned
|
||||
resp['success'] = true
|
||||
end
|
||||
end
|
||||
-- indicate that a packet 'useful' packet was returned
|
||||
resp['success'] = true
|
||||
end
|
||||
end
|
||||
|
||||
return resp
|
||||
return resp
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -356,212 +356,212 @@ end
|
|||
--
|
||||
function send_request( host, port, packet )
|
||||
|
||||
local socket = nmap.new_socket()
|
||||
local s_status, r_status, data, i, hexstring, _
|
||||
local socket = nmap.new_socket()
|
||||
local s_status, r_status, data, i, hexstring, _
|
||||
|
||||
-- lock resource (port 500/udp)
|
||||
local mutex = nmap.mutex("ike_port_500");
|
||||
mutex "lock";
|
||||
-- lock resource (port 500/udp)
|
||||
local mutex = nmap.mutex("ike_port_500");
|
||||
mutex "lock";
|
||||
|
||||
-- send the request packet
|
||||
socket:set_timeout(1000)
|
||||
socket:bind(nil, port.number)
|
||||
socket:connect(host, port, "udp")
|
||||
s_status,_ = socket:send(packet)
|
||||
-- send the request packet
|
||||
socket:set_timeout(1000)
|
||||
socket:bind(nil, port.number)
|
||||
socket:connect(host, port, "udp")
|
||||
s_status,_ = socket:send(packet)
|
||||
|
||||
-- receive answer
|
||||
if s_status then
|
||||
r_status, data = socket:receive_lines(1)
|
||||
-- receive answer
|
||||
if s_status then
|
||||
r_status, data = socket:receive_lines(1)
|
||||
|
||||
if r_status then
|
||||
i, hexstring = bin.unpack("H" .. data:len(), data)
|
||||
socket:close()
|
||||
if r_status then
|
||||
i, hexstring = bin.unpack("H" .. data:len(), data)
|
||||
socket:close()
|
||||
|
||||
-- release mutex
|
||||
mutex "done";
|
||||
return response(hexstring)
|
||||
else
|
||||
socket:close()
|
||||
end
|
||||
else
|
||||
socket:close()
|
||||
end
|
||||
-- release mutex
|
||||
mutex "done";
|
||||
return response(hexstring)
|
||||
else
|
||||
socket:close()
|
||||
end
|
||||
else
|
||||
socket:close()
|
||||
end
|
||||
|
||||
-- release mutex
|
||||
mutex "done";
|
||||
-- release mutex
|
||||
mutex "done";
|
||||
|
||||
return {}
|
||||
return {}
|
||||
end
|
||||
|
||||
-- Create the aggressive part of a packet
|
||||
-- Aggressive mode includes the user-id, so the
|
||||
-- length of this has to be taken into account
|
||||
-- Aggressive mode includes the user-id, so the
|
||||
-- length of this has to be taken into account
|
||||
--
|
||||
local function generate_aggressive(port, protocol, id, diffie)
|
||||
local hex_port = string.format("%.4X", port)
|
||||
local hex_prot = PROTOCOL_IDS[protocol]
|
||||
local id_len = string.format("%.4X", 8 + id:len())
|
||||
local hex_port = string.format("%.4X", port)
|
||||
local hex_prot = PROTOCOL_IDS[protocol]
|
||||
local id_len = string.format("%.4X", 8 + id:len())
|
||||
|
||||
-- get length of key data based on diffie
|
||||
local key_length
|
||||
if diffie == 1 then
|
||||
key_length = 96
|
||||
elseif diffie == 2 then
|
||||
key_length = 128
|
||||
elseif diffie == 5 then
|
||||
key_length = 192
|
||||
end
|
||||
-- get length of key data based on diffie
|
||||
local key_length
|
||||
if diffie == 1 then
|
||||
key_length = 96
|
||||
elseif diffie == 2 then
|
||||
key_length = 128
|
||||
elseif diffie == 5 then
|
||||
key_length = 192
|
||||
end
|
||||
|
||||
return bin.pack(">SHHSSHSHCHHH",
|
||||
-- Key Exchange
|
||||
0x0a00 , -- Next payload (Nonce)
|
||||
string.format("%04X", key_length+4) , -- Length (132-bit)
|
||||
generate_random(key_length) , -- Random key data
|
||||
return bin.pack(">SHHSSHSHCHHH",
|
||||
-- Key Exchange
|
||||
0x0a00, -- Next payload (Nonce)
|
||||
string.format("%04X", key_length+4), -- Length (132-bit)
|
||||
generate_random(key_length), -- Random key data
|
||||
|
||||
-- Nonce
|
||||
0x0500 , -- Next payload (Identification)
|
||||
0x0018 , -- Length (24)
|
||||
generate_random(20) , -- Nonce data
|
||||
-- Nonce
|
||||
0x0500, -- Next payload (Identification)
|
||||
0x0018, -- Length (24)
|
||||
generate_random(20), -- Nonce data
|
||||
|
||||
-- Identification
|
||||
0x0000 , -- Next Payload (None)
|
||||
id_len , -- Payload length (id + 8)
|
||||
0x03 , -- ID Type (USER_FQDN)
|
||||
hex_prot , -- Protocol ID (UDP)
|
||||
hex_port , -- Port (500)
|
||||
convert_to_hex(id) -- Id Data (as hex)
|
||||
)
|
||||
-- Identification
|
||||
0x0000, -- Next Payload (None)
|
||||
id_len, -- Payload length (id + 8)
|
||||
0x03, -- ID Type (USER_FQDN)
|
||||
hex_prot, -- Protocol ID (UDP)
|
||||
hex_port, -- Port (500)
|
||||
convert_to_hex(id) -- Id Data (as hex)
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
-- Create the transform
|
||||
-- AES encryption needs an extra value to define the key length
|
||||
-- Currently only DES, 3DES and AES encryption is supported
|
||||
-- AES encryption needs an extra value to define the key length
|
||||
-- Currently only DES, 3DES and AES encryption is supported
|
||||
--
|
||||
local function generate_transform(auth, encryption, hash, group, number, total)
|
||||
local key_length, trans_length, aes_enc, sep, enc
|
||||
local next_payload, payload_number
|
||||
local key_length, trans_length, aes_enc, sep, enc
|
||||
local next_payload, payload_number
|
||||
|
||||
-- handle special case of aes
|
||||
if encryption:sub(1,3) == "aes" then
|
||||
trans_length = 0x0028
|
||||
enc = ENC_METHODS[encryption][1]
|
||||
key_length = ENC_METHODS[encryption][2]
|
||||
else
|
||||
trans_length = 0x0024
|
||||
enc = ENC_METHODS[encryption]
|
||||
key_length = nil
|
||||
end
|
||||
-- handle special case of aes
|
||||
if encryption:sub(1,3) == "aes" then
|
||||
trans_length = 0x0028
|
||||
enc = ENC_METHODS[encryption][1]
|
||||
key_length = ENC_METHODS[encryption][2]
|
||||
else
|
||||
trans_length = 0x0024
|
||||
enc = ENC_METHODS[encryption]
|
||||
key_length = nil
|
||||
end
|
||||
|
||||
-- check if there are more transforms
|
||||
if number == total then
|
||||
next_payload = 0x0000 -- none
|
||||
else
|
||||
next_payload = 0x0300 -- transform
|
||||
end
|
||||
-- check if there are more transforms
|
||||
if number == total then
|
||||
next_payload = 0x0000 -- none
|
||||
else
|
||||
next_payload = 0x0300 -- transform
|
||||
end
|
||||
|
||||
-- set the payload number
|
||||
payload_number = string.format("%.2X", number)
|
||||
-- set the payload number
|
||||
payload_number = string.format("%.2X", number)
|
||||
|
||||
local trans = bin.pack(">SSHCSIIII",
|
||||
next_payload , -- Next payload
|
||||
trans_length , -- Transform length
|
||||
payload_number , -- Transform number
|
||||
0x01 , -- Transform ID (IKE)
|
||||
0x0000 , -- spacers ?
|
||||
enc , -- Encryption algorithm
|
||||
HASH_ALGORITHM[hash] , -- Hash algorithm
|
||||
AUTH_TYPES[auth] , -- Authentication method
|
||||
GROUP_DESCRIPTION[group] -- Group Description
|
||||
)
|
||||
local trans = bin.pack(">SSHCSIIII",
|
||||
next_payload, -- Next payload
|
||||
trans_length, -- Transform length
|
||||
payload_number, -- Transform number
|
||||
0x01, -- Transform ID (IKE)
|
||||
0x0000, -- spacers ?
|
||||
enc, -- Encryption algorithm
|
||||
HASH_ALGORITHM[hash], -- Hash algorithm
|
||||
AUTH_TYPES[auth], -- Authentication method
|
||||
GROUP_DESCRIPTION[group] -- Group Description
|
||||
)
|
||||
|
||||
if key_length ~= nil then
|
||||
trans = trans .. bin.pack(">I", key_length) -- only set for aes
|
||||
end
|
||||
if key_length ~= nil then
|
||||
trans = trans .. bin.pack(">I", key_length) -- only set for aes
|
||||
end
|
||||
|
||||
trans = trans .. bin.pack(">IL",
|
||||
0x800b0001 , -- Life type (seconds)
|
||||
0x000c000400007080 -- Life duration (28800)
|
||||
)
|
||||
trans = trans .. bin.pack(">IL",
|
||||
0x800b0001, -- Life type (seconds)
|
||||
0x000c000400007080 -- Life duration (28800)
|
||||
)
|
||||
|
||||
return trans
|
||||
return trans
|
||||
end
|
||||
|
||||
|
||||
-- Generate multiple transforms
|
||||
-- Input nust be a table of complete transforms
|
||||
-- Input nust be a table of complete transforms
|
||||
--
|
||||
local function generate_transforms(transform_table)
|
||||
local transforms = ''
|
||||
local transforms = ''
|
||||
|
||||
for i,t in pairs(transform_table) do
|
||||
transforms = transforms .. generate_transform(t.auth, t.encryption, t.hash, t.group, i, #transform_table)
|
||||
end
|
||||
for i,t in pairs(transform_table) do
|
||||
transforms = transforms .. generate_transform(t.auth, t.encryption, t.hash, t.group, i, #transform_table)
|
||||
end
|
||||
|
||||
return transforms
|
||||
return transforms
|
||||
end
|
||||
|
||||
|
||||
-- Create a request packet
|
||||
-- Support for multiple transforms, which minimizes the
|
||||
-- the amount of traffic/packets needed to be sendt
|
||||
-- Support for multiple transforms, which minimizes the
|
||||
-- the amount of traffic/packets needed to be sendt
|
||||
--
|
||||
function request(port, proto, mode, transforms, diffie, id)
|
||||
local payload_after_sa, str_aggressive, l, l_sa, l_pro
|
||||
local number_transforms, transform_string
|
||||
local payload_after_sa, str_aggressive, l, l_sa, l_pro
|
||||
local number_transforms, transform_string
|
||||
|
||||
transform_string = generate_transforms(transforms)
|
||||
number_transforms = string.format("%.2X", #transforms)
|
||||
transform_string = generate_transforms(transforms)
|
||||
number_transforms = string.format("%.2X", #transforms)
|
||||
|
||||
-- check for aggressive vs Main mode
|
||||
if mode == "Aggressive" then
|
||||
str_aggressive = generate_aggressive(port, proto, id, diffie)
|
||||
payload_after_sa = 0x0400
|
||||
else
|
||||
str_aggressive = ""
|
||||
payload_after_sa = 0x0000
|
||||
end
|
||||
-- check for aggressive vs Main mode
|
||||
if mode == "Aggressive" then
|
||||
str_aggressive = generate_aggressive(port, proto, id, diffie)
|
||||
payload_after_sa = 0x0400
|
||||
else
|
||||
str_aggressive = ""
|
||||
payload_after_sa = 0x0000
|
||||
end
|
||||
|
||||
|
||||
-- calculate lengths
|
||||
l = string.format("%.8X", 48 + transform_string:len() + str_aggressive:len())
|
||||
l_sa = string.format("%.4X", 20 + transform_string:len())
|
||||
l_pro = string.format("%.4X", 8 + transform_string:len())
|
||||
-- calculate lengths
|
||||
l = string.format("%.8X", 48 + transform_string:len() + str_aggressive:len())
|
||||
l_sa = string.format("%.4X", 20 + transform_string:len())
|
||||
l_pro = string.format("%.4X", 8 + transform_string:len())
|
||||
|
||||
-- Build the packet
|
||||
local packet = bin.pack(">HLCCCCIHSHIISHCCCH",
|
||||
generate_random(8) , -- Initiator cookie
|
||||
0x0000000000000000 , -- Responder cookie
|
||||
0x01 , -- Next payload (SA)
|
||||
0x10 , -- Version
|
||||
EXCHANGE_MODE[mode] , -- Exchange type
|
||||
0x00 , -- Flags
|
||||
0x00000000 , -- Message id
|
||||
l , -- packet length
|
||||
-- Build the packet
|
||||
local packet = bin.pack(">HLCCCCIHSHIISHCCCH",
|
||||
generate_random(8), -- Initiator cookie
|
||||
0x0000000000000000, -- Responder cookie
|
||||
0x01, -- Next payload (SA)
|
||||
0x10, -- Version
|
||||
EXCHANGE_MODE[mode], -- Exchange type
|
||||
0x00, -- Flags
|
||||
0x00000000, -- Message id
|
||||
l, -- packet length
|
||||
|
||||
|
||||
-- Security Association
|
||||
payload_after_sa , -- Next payload (Key exchange, if aggressive mode)
|
||||
l_sa , -- Length
|
||||
0x00000001 , -- IPSEC
|
||||
0x00000001 , -- Situation
|
||||
-- Security Association
|
||||
payload_after_sa, -- Next payload (Key exchange, if aggressive mode)
|
||||
l_sa, -- Length
|
||||
0x00000001, -- IPSEC
|
||||
0x00000001, -- Situation
|
||||
|
||||
--## Proposal
|
||||
0x0000 , -- Next payload (None)
|
||||
l_pro , -- Payload length
|
||||
0x01 , -- Proposal number
|
||||
0x01 , -- Protocol ID (ISAKMP)
|
||||
0x00 , -- SPI Size
|
||||
number_transforms -- Proposal transforms
|
||||
)
|
||||
--## Proposal
|
||||
0x0000, -- Next payload (None)
|
||||
l_pro, -- Payload length
|
||||
0x01, -- Proposal number
|
||||
0x01, -- Protocol ID (ISAKMP)
|
||||
0x00, -- SPI Size
|
||||
number_transforms -- Proposal transforms
|
||||
)
|
||||
|
||||
packet = packet .. transform_string -- transform
|
||||
packet = packet .. transform_string -- transform
|
||||
|
||||
if mode == 'Aggressive' then
|
||||
packet = packet .. str_aggressive
|
||||
end
|
||||
if mode == 'Aggressive' then
|
||||
packet = packet .. str_aggressive
|
||||
end
|
||||
|
||||
return packet
|
||||
return packet
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
2020
nselib/informix.lua
2020
nselib/informix.lua
File diff suppressed because it is too large
Load diff
1194
nselib/iscsi.lua
1194
nselib/iscsi.lua
File diff suppressed because it is too large
Load diff
1440
nselib/jdwp.lua
1440
nselib/jdwp.lua
File diff suppressed because it is too large
Load diff
918
nselib/ldap.lua
918
nselib/ldap.lua
File diff suppressed because it is too large
Load diff
|
|
@ -28,7 +28,7 @@ local arg_DB = stdnse.get_script_args("mongodb.db")
|
|||
-- Some lazy shortcuts
|
||||
|
||||
local function dbg(str,...)
|
||||
stdnse.print_debug(3, "MngoDb:"..str, ...)
|
||||
stdnse.print_debug(3, "MngoDb:"..str, ...)
|
||||
end
|
||||
--local dbg =stdnse.print_debug
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ local err =stdnse.print_debug
|
|||
--module("bson", package.seeall)
|
||||
--require("bin")
|
||||
local function dbg_err(str,...)
|
||||
stdnse.print_debug("Bson-ERR:"..str, ...)
|
||||
stdnse.print_debug("Bson-ERR:"..str, ...)
|
||||
end
|
||||
--local err =stdnse.log_error
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ end
|
|||
--@param input the string to pack
|
||||
--@return the packed nullterminated string
|
||||
local function make_nullterminated_string(input)
|
||||
return bin.pack("z",input)
|
||||
return bin.pack("z",input)
|
||||
end
|
||||
|
||||
--Converts an element (key, value) into bson binary data
|
||||
|
|
@ -73,35 +73,35 @@ end
|
|||
--@return result : the packed binary data OR error message
|
||||
local function _element_to_bson(key, value)
|
||||
|
||||
--Some constraints-checking
|
||||
if type(key) ~= 'string' then
|
||||
return false, "Documents must have only string keys, key was " .. type(key)
|
||||
end
|
||||
if key:sub(1,1) == "$" then
|
||||
return false, "key must not start with $: ".. key
|
||||
end
|
||||
if key:find("%.") then
|
||||
return false, ("key %r must not contain '.'"):format(tostring(key))
|
||||
end
|
||||
--Some constraints-checking
|
||||
if type(key) ~= 'string' then
|
||||
return false, "Documents must have only string keys, key was " .. type(key)
|
||||
end
|
||||
if key:sub(1,1) == "$" then
|
||||
return false, "key must not start with $: ".. key
|
||||
end
|
||||
if key:find("%.") then
|
||||
return false, ("key %r must not contain '.'"):format(tostring(key))
|
||||
end
|
||||
|
||||
local name =bin.pack("z",key) -- null-terminated string
|
||||
if type(value) == 'string' then
|
||||
local cstring = bin.pack("z",value) -- null-terminated string
|
||||
local length = bin.pack("<i", cstring:len())
|
||||
local op = bin.pack('H','02')
|
||||
return true, op .. name .. length .. cstring
|
||||
elseif type(value) =='table' then
|
||||
return true, bin.pack('H','02') .. name .. toBson(value)
|
||||
elseif type(value)== 'boolean' then
|
||||
return true, bin.pack('H','08') + name + bin.pack('H',value and '01' or '00')
|
||||
elseif type(value) == 'number' then
|
||||
--return bin.pack('H','10').. name .. bin.pack("<i", value)
|
||||
-- Use 01 - double for - works better than 10
|
||||
return true, bin.pack('H','01') .. name .. bin.pack("<d", value)
|
||||
end
|
||||
local name =bin.pack("z",key) -- null-terminated string
|
||||
if type(value) == 'string' then
|
||||
local cstring = bin.pack("z",value) -- null-terminated string
|
||||
local length = bin.pack("<i", cstring:len())
|
||||
local op = bin.pack('H','02')
|
||||
return true, op .. name .. length .. cstring
|
||||
elseif type(value) =='table' then
|
||||
return true, bin.pack('H','02') .. name .. toBson(value)
|
||||
elseif type(value)== 'boolean' then
|
||||
return true, bin.pack('H','08') + name + bin.pack('H',value and '01' or '00')
|
||||
elseif type(value) == 'number' then
|
||||
--return bin.pack('H','10').. name .. bin.pack("<i", value)
|
||||
-- Use 01 - double for - works better than 10
|
||||
return true, bin.pack('H','01') .. name .. bin.pack("<d", value)
|
||||
end
|
||||
|
||||
local _ = ("cannot convert value of type %s to bson"):format(type(value))
|
||||
return false, _
|
||||
local _ = ("cannot convert value of type %s to bson"):format(type(value))
|
||||
return false, _
|
||||
end
|
||||
|
||||
--Converts a table of elements to binary bson format
|
||||
|
|
@ -110,37 +110,37 @@ end
|
|||
--@return result : a string of binary data OR error message
|
||||
function toBson(dict)
|
||||
|
||||
local elements = ""
|
||||
--Put id first
|
||||
if dict._id then
|
||||
local status,res = _element_to_bson("_id", dict._id)
|
||||
if not status then return false, res end
|
||||
elements = elements..res
|
||||
elseif ( dict._cmd ) then
|
||||
for k, v in pairs(dict._cmd) do
|
||||
local status,res = _element_to_bson(k, v)
|
||||
if not status then return false, res end
|
||||
elements = elements..res
|
||||
end
|
||||
end
|
||||
--Concatenate binary values
|
||||
for key, value in pairs( dict ) do
|
||||
if key ~= "_id" and key ~= "_cmd" then
|
||||
dbg("dictionary to bson : key,value =(%s,%s)",key,value)
|
||||
local status,res = _element_to_bson(key,value)
|
||||
if not status then return false, res end
|
||||
elements = elements..res
|
||||
end
|
||||
end
|
||||
-- Get length
|
||||
local length = #elements + 5
|
||||
local elements = ""
|
||||
--Put id first
|
||||
if dict._id then
|
||||
local status,res = _element_to_bson("_id", dict._id)
|
||||
if not status then return false, res end
|
||||
elements = elements..res
|
||||
elseif ( dict._cmd ) then
|
||||
for k, v in pairs(dict._cmd) do
|
||||
local status,res = _element_to_bson(k, v)
|
||||
if not status then return false, res end
|
||||
elements = elements..res
|
||||
end
|
||||
end
|
||||
--Concatenate binary values
|
||||
for key, value in pairs( dict ) do
|
||||
if key ~= "_id" and key ~= "_cmd" then
|
||||
dbg("dictionary to bson : key,value =(%s,%s)",key,value)
|
||||
local status,res = _element_to_bson(key,value)
|
||||
if not status then return false, res end
|
||||
elements = elements..res
|
||||
end
|
||||
end
|
||||
-- Get length
|
||||
local length = #elements + 5
|
||||
|
||||
if length > 4 * 1024 * 1024 then
|
||||
return false, "document too large - BSON documents are limited to 4 MB"
|
||||
end
|
||||
dbg("Packet length is %d",length)
|
||||
--Final pack
|
||||
return true, bin.pack("I", length) .. elements .. bin.pack('H',"00")
|
||||
if length > 4 * 1024 * 1024 then
|
||||
return false, "document too large - BSON documents are limited to 4 MB"
|
||||
end
|
||||
dbg("Packet length is %d",length)
|
||||
--Final pack
|
||||
return true, bin.pack("I", length) .. elements .. bin.pack('H',"00")
|
||||
end
|
||||
|
||||
-- Reads a null-terminated string. If length is supplied, it is just cut
|
||||
|
|
@ -150,18 +150,18 @@ end
|
|||
--@return the string
|
||||
--@return the remaining data (*without* null-char)
|
||||
local function get_c_string(data,length)
|
||||
if not length then
|
||||
local index = data:find(string.char(0))
|
||||
if index == nil then
|
||||
error({code="C-string did not contain NULL char"})
|
||||
end
|
||||
length = index
|
||||
end
|
||||
local value = data:sub(1,length-1)
|
||||
if not length then
|
||||
local index = data:find(string.char(0))
|
||||
if index == nil then
|
||||
error({code="C-string did not contain NULL char"})
|
||||
end
|
||||
length = index
|
||||
end
|
||||
local value = data:sub(1,length-1)
|
||||
|
||||
--dbg("Found char at pos %d, data is %s c-string is %s",length, data, value)
|
||||
--dbg("Found char at pos %d, data is %s c-string is %s",length, data, value)
|
||||
|
||||
return value, data:sub(length+1)
|
||||
return value, data:sub(length+1)
|
||||
end
|
||||
|
||||
-- Element parser. Parse data elements
|
||||
|
|
@ -170,47 +170,47 @@ end
|
|||
-- @return Unpacked value
|
||||
-- @return error string if error occurred
|
||||
local function parse(code,data)
|
||||
if 1 == code then -- double
|
||||
return bin.unpack("<d", data)
|
||||
elseif 2 == code then -- string
|
||||
-- data length = first four bytes
|
||||
local _,len = bin.unpack("<i",data)
|
||||
-- string data = data[5] -->
|
||||
local value = get_c_string(data:sub(5), len)
|
||||
-- Count position as header (=4) + length of string (=len)+ null char (=1)
|
||||
return 4+len+1,value
|
||||
elseif 3 == code or 4 == code then -- table or array
|
||||
local object, err
|
||||
if 1 == code then -- double
|
||||
return bin.unpack("<d", data)
|
||||
elseif 2 == code then -- string
|
||||
-- data length = first four bytes
|
||||
local _,len = bin.unpack("<i",data)
|
||||
-- string data = data[5] -->
|
||||
local value = get_c_string(data:sub(5), len)
|
||||
-- Count position as header (=4) + length of string (=len)+ null char (=1)
|
||||
return 4+len+1,value
|
||||
elseif 3 == code or 4 == code then -- table or array
|
||||
local object, err
|
||||
|
||||
-- Need to know the length, to return later
|
||||
local _,obj_size = bin.unpack("<i", data)
|
||||
-- Now, get the data object
|
||||
dbg("Recursing into bson array")
|
||||
object, data, err = fromBson(data)
|
||||
dbg("Recurse finished, got data object")
|
||||
-- And return where the parsing stopped
|
||||
return obj_size+1, object
|
||||
--6 = _get_null
|
||||
--7 = _get_oid
|
||||
elseif 8 == code then -- Boolean
|
||||
return 2, data:byte(1) == 1
|
||||
elseif 9 == code then -- int64, UTC datetime
|
||||
return bin.unpack("<l", data)
|
||||
elseif 10 == code then -- nullvalue
|
||||
return 0,nil
|
||||
--11= _get_regex
|
||||
--12= _get_ref
|
||||
--13= _get_string, # code
|
||||
--14= _get_string, # symbol
|
||||
--15= _get_code_w_scope
|
||||
elseif 16 == code then -- 4 byte integer
|
||||
return bin.unpack("<i", data)
|
||||
--17= _get_timestamp
|
||||
elseif 18 == code then -- long
|
||||
return bin.unpack("<l", data)
|
||||
end
|
||||
local err = ("Getter for %d not implemented"):format(code)
|
||||
return 0, data, err
|
||||
-- Need to know the length, to return later
|
||||
local _,obj_size = bin.unpack("<i", data)
|
||||
-- Now, get the data object
|
||||
dbg("Recursing into bson array")
|
||||
object, data, err = fromBson(data)
|
||||
dbg("Recurse finished, got data object")
|
||||
-- And return where the parsing stopped
|
||||
return obj_size+1, object
|
||||
--6 = _get_null
|
||||
--7 = _get_oid
|
||||
elseif 8 == code then -- Boolean
|
||||
return 2, data:byte(1) == 1
|
||||
elseif 9 == code then -- int64, UTC datetime
|
||||
return bin.unpack("<l", data)
|
||||
elseif 10 == code then -- nullvalue
|
||||
return 0,nil
|
||||
--11= _get_regex
|
||||
--12= _get_ref
|
||||
--13= _get_string, # code
|
||||
--14= _get_string, # symbol
|
||||
--15= _get_code_w_scope
|
||||
elseif 16 == code then -- 4 byte integer
|
||||
return bin.unpack("<i", data)
|
||||
--17= _get_timestamp
|
||||
elseif 18 == code then -- long
|
||||
return bin.unpack("<l", data)
|
||||
end
|
||||
local err = ("Getter for %d not implemented"):format(code)
|
||||
return 0, data, err
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -221,38 +221,38 @@ end
|
|||
--@return Residual data not used
|
||||
--@return any error that occurred
|
||||
local function _element_to_dict(data)
|
||||
local element_type, element_name, err, pos, value
|
||||
--local element_size = data:byte(1)
|
||||
element_type = data:byte(1)
|
||||
element_name, data = get_c_string(data:sub(2))
|
||||
local element_type, element_name, err, pos, value
|
||||
--local element_size = data:byte(1)
|
||||
element_type = data:byte(1)
|
||||
element_name, data = get_c_string(data:sub(2))
|
||||
|
||||
dbg(" Read element name '%s' (type:%s), data left: %d",element_name, element_type,data:len())
|
||||
--pos,value,err = parsers.get(element_type)(data)
|
||||
pos,value,err = parse(element_type,data)
|
||||
if(err ~= nil) then
|
||||
dbg_err(err)
|
||||
return nil,nil, data, err
|
||||
end
|
||||
dbg(" Read element name '%s' (type:%s), data left: %d",element_name, element_type,data:len())
|
||||
--pos,value,err = parsers.get(element_type)(data)
|
||||
pos,value,err = parse(element_type,data)
|
||||
if(err ~= nil) then
|
||||
dbg_err(err)
|
||||
return nil,nil, data, err
|
||||
end
|
||||
|
||||
data=data:sub(pos)
|
||||
data=data:sub(pos)
|
||||
|
||||
dbg(" Read element value '%s', data left: %d",tostring(value), data:len())
|
||||
return element_name, value, data
|
||||
dbg(" Read element value '%s', data left: %d",tostring(value), data:len())
|
||||
return element_name, value, data
|
||||
end
|
||||
|
||||
--Reads all elements from binary to BSon
|
||||
--@param data the data to read from
|
||||
--@return the resulting table
|
||||
local function _elements_to_dict(data)
|
||||
local result = {}
|
||||
local key,value
|
||||
while data and data:len() > 1 do
|
||||
key, value, data = _element_to_dict(data)
|
||||
dbg("Parsed (%s='%s'), data left : %d", tostring(key),tostring(value), data:len())
|
||||
if type(value) ~= 'table' then value=tostring(value) end
|
||||
result[key] = value
|
||||
end
|
||||
return result
|
||||
local result = {}
|
||||
local key,value
|
||||
while data and data:len() > 1 do
|
||||
key, value, data = _element_to_dict(data)
|
||||
dbg("Parsed (%s='%s'), data left : %d", tostring(key),tostring(value), data:len())
|
||||
if type(value) ~= 'table' then value=tostring(value) end
|
||||
result[key] = value
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
--Checks if enough data to parse the result is captured
|
||||
|
|
@ -260,21 +260,21 @@ end
|
|||
--@return true if the full bson table is contained in the data, false if data is incomplete
|
||||
--@return required size of packet, if known, otherwise nil
|
||||
function isPacketComplete(data)
|
||||
-- First, we check that the header is complete
|
||||
if data:len() < 4 then
|
||||
local err_msg = "Not enough data in buffer, at least 4 bytes header info expected"
|
||||
return false
|
||||
end
|
||||
-- First, we check that the header is complete
|
||||
if data:len() < 4 then
|
||||
local err_msg = "Not enough data in buffer, at least 4 bytes header info expected"
|
||||
return false
|
||||
end
|
||||
|
||||
local _,obj_size = bin.unpack("<i", data)
|
||||
local _,obj_size = bin.unpack("<i", data)
|
||||
|
||||
dbg("BSon packet size is %s", obj_size)
|
||||
dbg("BSon packet size is %s", obj_size)
|
||||
|
||||
-- Check that all data is read and the packet is complete
|
||||
if data:len() < obj_size then
|
||||
return false,obj_size
|
||||
end
|
||||
return true,obj_size
|
||||
-- Check that all data is read and the packet is complete
|
||||
if data:len() < obj_size then
|
||||
return false,obj_size
|
||||
end
|
||||
return true,obj_size
|
||||
end
|
||||
|
||||
-- Converts bson binary data read from socket into a table
|
||||
|
|
@ -285,18 +285,18 @@ end
|
|||
--@return error message if not enough data was in packet
|
||||
function fromBson(data)
|
||||
|
||||
dbg("Decoding, got %s bytes of data", data:len())
|
||||
local complete, object_size = isPacketComplete(data)
|
||||
dbg("Decoding, got %s bytes of data", data:len())
|
||||
local complete, object_size = isPacketComplete(data)
|
||||
|
||||
if not complete then
|
||||
local err_msg = ("Not enough data in buffer, expected %s but only has %d"):format(object_size or "?", data:len())
|
||||
dbg(err_msg)
|
||||
return {},data, err_msg
|
||||
end
|
||||
if not complete then
|
||||
local err_msg = ("Not enough data in buffer, expected %s but only has %d"):format(object_size or "?", data:len())
|
||||
dbg(err_msg)
|
||||
return {},data, err_msg
|
||||
end
|
||||
|
||||
local element_portion = data:sub(5,object_size)
|
||||
local remainder = data:sub(object_size+1)
|
||||
return _elements_to_dict(element_portion), remainder
|
||||
local element_portion = data:sub(5,object_size)
|
||||
local remainder = data:sub(object_size+1)
|
||||
return _elements_to_dict(element_portion), remainder
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -304,14 +304,14 @@ end
|
|||
-- Test-code for debugging purposes below
|
||||
----------------------------------------------------------------------------------
|
||||
function testBson()
|
||||
local p = toBson({hello="world", test="ok"})
|
||||
local p = toBson({hello="world", test="ok"})
|
||||
|
||||
print( "Encoded something ok")
|
||||
local orig = fromBson(p)
|
||||
print(" Decoded something else ok")
|
||||
for i,v in pairs(orig) do
|
||||
print(i,v)
|
||||
end
|
||||
print( "Encoded something ok")
|
||||
local orig = fromBson(p)
|
||||
print(" Decoded something else ok")
|
||||
for i,v in pairs(orig) do
|
||||
print(i,v)
|
||||
end
|
||||
end
|
||||
--testBson()
|
||||
--------------------------------------------------------------------------------------------------------------
|
||||
|
|
@ -330,15 +330,15 @@ struct {
|
|||
}
|
||||
|
||||
Opcodes :
|
||||
OP_REPLY 1 Reply to a client request. responseTo is set
|
||||
OP_MSG 1000 generic msg command followed by a string
|
||||
OP_UPDATE 2001 update document
|
||||
OP_INSERT 2002 insert new document
|
||||
OP_GET_BY_OID 2003 is this used?
|
||||
OP_QUERY 2004 query a collection
|
||||
OP_GET_MORE 2005 Get more data from a query. See Cursors
|
||||
OP_DELETE 2006 Delete documents
|
||||
OP_KILL_CURSORS 2007 Tell database client is done with a cursor
|
||||
OP_REPLY 1 Reply to a client request. responseTo is set
|
||||
OP_MSG 1000 generic msg command followed by a string
|
||||
OP_UPDATE 2001 update document
|
||||
OP_INSERT 2002 insert new document
|
||||
OP_GET_BY_OID 2003 is this used?
|
||||
OP_QUERY 2004 query a collection
|
||||
OP_GET_MORE 2005 Get more data from a query. See Cursors
|
||||
OP_DELETE 2006 Delete documents
|
||||
OP_KILL_CURSORS 2007 Tell database client is done with a cursor
|
||||
|
||||
Query message :
|
||||
struct {
|
||||
|
|
@ -358,64 +358,64 @@ For more info about the MongoDB wire protocol, see http://www.mongodb.org/displa
|
|||
-- DIY lua-class to create Mongo packets
|
||||
--@usage call MongoData:new({opCode=MongoData.OP.QUERY}) to create query object
|
||||
MongoData ={
|
||||
uniqueRequestId = 12345,
|
||||
-- Opcodes used by Mongo db
|
||||
OP = {
|
||||
REPLY = 1,
|
||||
MSG = 1000,
|
||||
UPDATE = 2001,
|
||||
INSERT = 2002,
|
||||
GET_BY_IOD =2003,
|
||||
QUERY = 2004,
|
||||
GET_MORE = 2005,
|
||||
DELETE = 2006,
|
||||
KILL_CURSORS = 2007,
|
||||
},
|
||||
-- Lua-DIY constructor
|
||||
new = function (self,o,opCode,responseTo)
|
||||
o = o or {} -- create object if user does not provide one
|
||||
setmetatable(o, self) -- DIY inheritance a'la javascript
|
||||
self.__index = self
|
||||
self.valueString = ''
|
||||
self.requestID = MongoData.uniqueRequestId -- Create unique id for message
|
||||
MongoData.uniqueRequestId = MongoData.uniqueRequestId +1
|
||||
return o
|
||||
end
|
||||
uniqueRequestId = 12345,
|
||||
-- Opcodes used by Mongo db
|
||||
OP = {
|
||||
REPLY = 1,
|
||||
MSG = 1000,
|
||||
UPDATE = 2001,
|
||||
INSERT = 2002,
|
||||
GET_BY_IOD = 2003,
|
||||
QUERY = 2004,
|
||||
GET_MORE = 2005,
|
||||
DELETE = 2006,
|
||||
KILL_CURSORS = 2007,
|
||||
},
|
||||
-- Lua-DIY constructor
|
||||
new = function (self,o,opCode,responseTo)
|
||||
o = o or {} -- create object if user does not provide one
|
||||
setmetatable(o, self) -- DIY inheritance a'la javascript
|
||||
self.__index = self
|
||||
self.valueString = ''
|
||||
self.requestID = MongoData.uniqueRequestId -- Create unique id for message
|
||||
MongoData.uniqueRequestId = MongoData.uniqueRequestId +1
|
||||
return o
|
||||
end
|
||||
}
|
||||
--Adds unsigned int32 to the message body
|
||||
--@param value the value to add
|
||||
function MongoData:addUnsignedInt32(value)
|
||||
self.valueString = self.valueString..bin.pack("I",value)
|
||||
self.valueString = self.valueString..bin.pack("I",value)
|
||||
end
|
||||
-- Adds a string to the message body
|
||||
--@param value the string to add
|
||||
function MongoData:addString(value)
|
||||
self.valueString = self.valueString..bin.pack('z',value)
|
||||
self.valueString = self.valueString..bin.pack('z',value)
|
||||
end
|
||||
-- Add a table as a BSon object to the body
|
||||
--@param dict the table to be converted to BSon
|
||||
--@return status : true if ok, false if error occurred
|
||||
--@return Error message if error occurred
|
||||
function MongoData:addBSON(dict)
|
||||
-- status, res = bson.toBson(dict)
|
||||
local status, res = toBson(dict)
|
||||
if not status then
|
||||
dbg(res)
|
||||
return status,res
|
||||
end
|
||||
-- status, res = bson.toBson(dict)
|
||||
local status, res = toBson(dict)
|
||||
if not status then
|
||||
dbg(res)
|
||||
return status,res
|
||||
end
|
||||
|
||||
self.valueString = self.valueString..res
|
||||
return true
|
||||
self.valueString = self.valueString..res
|
||||
return true
|
||||
end
|
||||
-- Returns the data in this packet in a raw string format to be sent on socket
|
||||
-- This method creates necessary header information and puts it with the body
|
||||
function MongoData:data()
|
||||
local header = MongoData:new()
|
||||
header:addUnsignedInt32( self.valueString:len()+4+4+4+4)
|
||||
header:addUnsignedInt32( self.requestID)
|
||||
header:addUnsignedInt32( self.responseTo or 0xFFFFFFFF)
|
||||
header:addUnsignedInt32( self.opCode)
|
||||
return header.valueString .. self.valueString
|
||||
local header = MongoData:new()
|
||||
header:addUnsignedInt32( self.valueString:len()+4+4+4+4)
|
||||
header:addUnsignedInt32( self.requestID)
|
||||
header:addUnsignedInt32( self.responseTo or 0xFFFFFFFF)
|
||||
header:addUnsignedInt32( self.opCode)
|
||||
return header.valueString .. self.valueString
|
||||
end
|
||||
-- Creates a query
|
||||
-- @param collectionName string specifying the collection to run query against
|
||||
|
|
@ -423,54 +423,54 @@ end
|
|||
--@return status : true for OK, false for error
|
||||
--@return packet data OR error message
|
||||
local function createQuery(collectionName, query)
|
||||
local packet = MongoData:new({opCode=MongoData.OP.QUERY})
|
||||
packet:addUnsignedInt32(0); -- options
|
||||
packet:addString(collectionName);
|
||||
packet:addUnsignedInt32(0) -- number to skip
|
||||
packet:addUnsignedInt32(-1) -- number to return : no limit
|
||||
local status, error = packet:addBSON(query)
|
||||
local packet = MongoData:new({opCode=MongoData.OP.QUERY})
|
||||
packet:addUnsignedInt32(0); -- options
|
||||
packet:addString(collectionName);
|
||||
packet:addUnsignedInt32(0) -- number to skip
|
||||
packet:addUnsignedInt32(-1) -- number to return : no limit
|
||||
local status, error = packet:addBSON(query)
|
||||
|
||||
if not status then
|
||||
return status, error
|
||||
end
|
||||
if not status then
|
||||
return status, error
|
||||
end
|
||||
|
||||
return true, packet:data()
|
||||
return true, packet:data()
|
||||
end
|
||||
-- Creates a get last error query
|
||||
-- @param responseTo optional identifier this packet is a response to
|
||||
--@return status : true for OK, false for error
|
||||
--@return packet data OR error message
|
||||
function lastErrorQuery(responseTo)
|
||||
local collectionName = "test.$cmd"
|
||||
local query = {getlasterror=1}
|
||||
return createQuery(collectionName, query)
|
||||
local collectionName = "test.$cmd"
|
||||
local query = {getlasterror=1}
|
||||
return createQuery(collectionName, query)
|
||||
end
|
||||
-- Creates a server status query
|
||||
-- @param responseTo optional identifier this packet is a response to
|
||||
--@return status : true for OK, false for error
|
||||
--@return packet data OR error message
|
||||
function serverStatusQuery(responseTo)
|
||||
local collectionName = "test.$cmd"
|
||||
local query = {serverStatus = 1}
|
||||
return createQuery(collectionName, query)
|
||||
local collectionName = "test.$cmd"
|
||||
local query = {serverStatus = 1}
|
||||
return createQuery(collectionName, query)
|
||||
end
|
||||
-- Creates a optime query
|
||||
-- @param responseTo optional identifier this packet is a response to
|
||||
--@return status : true for OK, false for error
|
||||
--@return packet data OR error message
|
||||
function opTimeQuery(responseTo)
|
||||
local collectionName = "test.$cmd"
|
||||
local query = {getoptime = 1}
|
||||
return createQuery(collectionName, query)
|
||||
local collectionName = "test.$cmd"
|
||||
local query = {getoptime = 1}
|
||||
return createQuery(collectionName, query)
|
||||
end
|
||||
-- Creates a list databases query
|
||||
-- @param responseTo optional identifier this packet is a response to
|
||||
--@return status : true for OK, false for error
|
||||
--@return packet data OR error message
|
||||
function listDbQuery(responseTo)
|
||||
local collectionName = "admin.$cmd"
|
||||
local query = {listDatabases = 1}
|
||||
return createQuery(collectionName, query)
|
||||
local collectionName = "admin.$cmd"
|
||||
local query = {listDatabases = 1}
|
||||
return createQuery(collectionName, query)
|
||||
end
|
||||
-- Creates a build info query
|
||||
-- @param responseTo optional identifier this packet is a response to
|
||||
|
|
@ -479,20 +479,20 @@ end
|
|||
--@return status : true for OK, false for error
|
||||
--@return packet data OR error message
|
||||
function buildInfoQuery(responseTo)
|
||||
local collectionName = "admin.$cmd"
|
||||
local query = {buildinfo = 1}
|
||||
return createQuery(collectionName, query)
|
||||
local collectionName = "admin.$cmd"
|
||||
local query = {buildinfo = 1}
|
||||
return createQuery(collectionName, query)
|
||||
end
|
||||
--Reads an int32 from data
|
||||
--@return int32 value
|
||||
--@return data unread
|
||||
local function parseInt32(data)
|
||||
local pos,val = bin.unpack("<i",data)
|
||||
return val, data:sub(pos)
|
||||
local pos,val = bin.unpack("<i",data)
|
||||
return val, data:sub(pos)
|
||||
end
|
||||
local function parseInt64(data)
|
||||
local pos,val = bin.unpack("<l",data)
|
||||
return val, data:sub(pos)
|
||||
local pos,val = bin.unpack("<l",data)
|
||||
return val, data:sub(pos)
|
||||
end
|
||||
-- Parses response header
|
||||
-- The response header looks like this :
|
||||
|
|
@ -509,44 +509,44 @@ struct {
|
|||
--@param the data from socket
|
||||
--@return a table containing the header data
|
||||
local function parseResponseHeader(data)
|
||||
local response= {}
|
||||
local hdr, rflag, cID, sfrom, nRet, docs
|
||||
local response= {}
|
||||
local hdr, rflag, cID, sfrom, nRet, docs
|
||||
|
||||
-- First std message header
|
||||
hdr ={}
|
||||
hdr["messageLength"], data = parseInt32(data)
|
||||
hdr["requestID"], data = parseInt32(data)
|
||||
hdr["responseTo"], data = parseInt32(data)
|
||||
hdr["opCode"], data = parseInt32(data)
|
||||
response["header"] = hdr
|
||||
-- Some additional fields
|
||||
response["responseFlag"] ,data = parseInt32(data)
|
||||
response["cursorID"] ,data = parseInt64(data)
|
||||
response["startingFrom"] ,data = parseInt32(data)
|
||||
response["numberReturned"] ,data = parseInt32(data)
|
||||
response["bson"] = data
|
||||
return response
|
||||
-- First std message header
|
||||
hdr ={}
|
||||
hdr["messageLength"], data = parseInt32(data)
|
||||
hdr["requestID"], data = parseInt32(data)
|
||||
hdr["responseTo"], data = parseInt32(data)
|
||||
hdr["opCode"], data = parseInt32(data)
|
||||
response["header"] = hdr
|
||||
-- Some additional fields
|
||||
response["responseFlag"] ,data = parseInt32(data)
|
||||
response["cursorID"] ,data = parseInt64(data)
|
||||
response["startingFrom"] ,data = parseInt32(data)
|
||||
response["numberReturned"] ,data = parseInt32(data)
|
||||
response["bson"] = data
|
||||
return response
|
||||
end
|
||||
--Checks if enough data to parse the result is captured
|
||||
--@data binary mongodb data read from socket
|
||||
--@return true if the full mongodb packet is contained in the data, false if data is incomplete
|
||||
--@return required size of packet, if known, otherwise nil
|
||||
function isPacketComplete(data)
|
||||
-- First, we check that the header is complete
|
||||
if data:len() < 4 then
|
||||
local err_msg = "Not enough data in buffer, at least 4 bytes header info expected"
|
||||
return false
|
||||
end
|
||||
-- First, we check that the header is complete
|
||||
if data:len() < 4 then
|
||||
local err_msg = "Not enough data in buffer, at least 4 bytes header info expected"
|
||||
return false
|
||||
end
|
||||
|
||||
local _,obj_size = bin.unpack("<i", data)
|
||||
local _,obj_size = bin.unpack("<i", data)
|
||||
|
||||
dbg("MongoDb Packet size is %s, (got %d)", obj_size,data:len())
|
||||
dbg("MongoDb Packet size is %s, (got %d)", obj_size,data:len())
|
||||
|
||||
-- Check that all data is read and the packet is complete
|
||||
if data:len() < obj_size then
|
||||
return false,obj_size
|
||||
end
|
||||
return true,obj_size
|
||||
-- Check that all data is read and the packet is complete
|
||||
if data:len() < obj_size then
|
||||
return false,obj_size
|
||||
end
|
||||
return true,obj_size
|
||||
end
|
||||
|
||||
-- Sends a packet over a socket, reads the response
|
||||
|
|
@ -555,77 +555,77 @@ end
|
|||
--@return result : table of status ok, error msg if bad
|
||||
--@return if status ok : remaining data read from socket but not used
|
||||
function query(socket, data)
|
||||
--Create an error handler
|
||||
local catch = function()
|
||||
socket:close()
|
||||
stdnse.print_debug(string.format("Query failed"))
|
||||
end
|
||||
local try = nmap.new_try(catch)
|
||||
--Create an error handler
|
||||
local catch = function()
|
||||
socket:close()
|
||||
stdnse.print_debug(string.format("Query failed"))
|
||||
end
|
||||
local try = nmap.new_try(catch)
|
||||
|
||||
try( socket:send( data ) )
|
||||
try( socket:send( data ) )
|
||||
|
||||
local data = ""
|
||||
local result = {}
|
||||
local err_msg
|
||||
local isComplete, pSize
|
||||
while not isComplete do
|
||||
dbg("mongo: waiting for data from socket, got %d bytes so far...",data:len())
|
||||
data = data .. try( socket:receive() )
|
||||
isComplete, pSize = isPacketComplete(data)
|
||||
end
|
||||
-- All required data shold be read now
|
||||
local packetData = data:sub(1,pSize)
|
||||
local residualData = data:sub(pSize+1)
|
||||
local responseHeader = parseResponseHeader(packetData)
|
||||
local data = ""
|
||||
local result = {}
|
||||
local err_msg
|
||||
local isComplete, pSize
|
||||
while not isComplete do
|
||||
dbg("mongo: waiting for data from socket, got %d bytes so far...",data:len())
|
||||
data = data .. try( socket:receive() )
|
||||
isComplete, pSize = isPacketComplete(data)
|
||||
end
|
||||
-- All required data shold be read now
|
||||
local packetData = data:sub(1,pSize)
|
||||
local residualData = data:sub(pSize+1)
|
||||
local responseHeader = parseResponseHeader(packetData)
|
||||
|
||||
if responseHeader["responseFlag"] ~= 0 then
|
||||
dbg("Response flag not zero : %d, some error occurred", responseHeader["responseFlag"])
|
||||
end
|
||||
if responseHeader["responseFlag"] ~= 0 then
|
||||
dbg("Response flag not zero : %d, some error occurred", responseHeader["responseFlag"])
|
||||
end
|
||||
|
||||
local bsonData = responseHeader["bson"]
|
||||
if #bsonData == 0 then
|
||||
dbg("No BSon data returned ")
|
||||
return false, "No Bson data returned"
|
||||
end
|
||||
local bsonData = responseHeader["bson"]
|
||||
if #bsonData == 0 then
|
||||
dbg("No BSon data returned ")
|
||||
return false, "No Bson data returned"
|
||||
end
|
||||
|
||||
-- result, data, err_msg = bson.fromBson(bsonData)
|
||||
result, data, err_msg = fromBson(bsonData)
|
||||
-- result, data, err_msg = bson.fromBson(bsonData)
|
||||
result, data, err_msg = fromBson(bsonData)
|
||||
|
||||
if err_msg then
|
||||
dbg("Got error converting from bson: %s" , err_msg)
|
||||
return false, ("Got error converting from bson: %s"):format(err_msg)
|
||||
end
|
||||
return true,result, residualData
|
||||
if err_msg then
|
||||
dbg("Got error converting from bson: %s" , err_msg)
|
||||
return false, ("Got error converting from bson: %s"):format(err_msg)
|
||||
end
|
||||
return true,result, residualData
|
||||
end
|
||||
|
||||
function login(socket, db, username, password)
|
||||
|
||||
local collectionName = ("%s.$cmd"):format(arg_DB or db)
|
||||
local query = { getnonce = 1 }
|
||||
local status, packet = createQuery(collectionName, query)
|
||||
local response
|
||||
status, response = query(socket, packet)
|
||||
if ( not(status) or not(response.nonce) ) then
|
||||
return false, "Failed to retrieve nonce"
|
||||
end
|
||||
local collectionName = ("%s.$cmd"):format(arg_DB or db)
|
||||
local query = { getnonce = 1 }
|
||||
local status, packet = createQuery(collectionName, query)
|
||||
local response
|
||||
status, response = query(socket, packet)
|
||||
if ( not(status) or not(response.nonce) ) then
|
||||
return false, "Failed to retrieve nonce"
|
||||
end
|
||||
|
||||
local nonce = response.nonce
|
||||
local pwdigest = stdnse.tohex(openssl.md5(username .. ':mongo:' ..password))
|
||||
local digest = stdnse.tohex(openssl.md5(nonce .. username .. pwdigest))
|
||||
local nonce = response.nonce
|
||||
local pwdigest = stdnse.tohex(openssl.md5(username .. ':mongo:' ..password))
|
||||
local digest = stdnse.tohex(openssl.md5(nonce .. username .. pwdigest))
|
||||
|
||||
query = { user = username, nonce = nonce, key = digest }
|
||||
query._cmd = { authenticate = 1 }
|
||||
query = { user = username, nonce = nonce, key = digest }
|
||||
query._cmd = { authenticate = 1 }
|
||||
|
||||
local status, packet = createQuery(collectionName, query)
|
||||
status, response = query(socket, packet)
|
||||
if ( not(status) ) then
|
||||
return status, response
|
||||
elseif ( response.errmsg == "auth fails" ) then
|
||||
return false, "Authentication failed"
|
||||
elseif ( response.errmsg ) then
|
||||
return false, response.errmsg
|
||||
end
|
||||
return status, response
|
||||
local status, packet = createQuery(collectionName, query)
|
||||
status, response = query(socket, packet)
|
||||
if ( not(status) ) then
|
||||
return status, response
|
||||
elseif ( response.errmsg == "auth fails" ) then
|
||||
return false, "Authentication failed"
|
||||
elseif ( response.errmsg ) then
|
||||
return false, response.errmsg
|
||||
end
|
||||
return status, response
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -634,16 +634,16 @@ end
|
|||
-- @return table suitable for <code>stdnse.format_output</code>
|
||||
function queryResultToTable( resultTable )
|
||||
|
||||
local result = {}
|
||||
for k,v in pairs( resultTable ) do
|
||||
if type(v) == 'table' then
|
||||
table.insert(result,k)
|
||||
table.insert(result,queryResultToTable(v))
|
||||
else
|
||||
table.insert(result,(("%s = %s"):format(tostring(k), tostring(v))))
|
||||
end
|
||||
end
|
||||
return result
|
||||
local result = {}
|
||||
for k,v in pairs( resultTable ) do
|
||||
if type(v) == 'table' then
|
||||
table.insert(result,k)
|
||||
table.insert(result,queryResultToTable(v))
|
||||
else
|
||||
table.insert(result,(("%s = %s"):format(tostring(k), tostring(v))))
|
||||
end
|
||||
end
|
||||
return result
|
||||
|
||||
end
|
||||
----------------------------------------------------------------------------------
|
||||
|
|
@ -656,30 +656,30 @@ end
|
|||
-- @param strData the data in a string format
|
||||
|
||||
local function printBuffer(strData)
|
||||
local out = ''
|
||||
local ch
|
||||
for i = 1,strData:len() do
|
||||
out = out .." "
|
||||
ch =strData:byte(i)
|
||||
if(ch < 16) then
|
||||
ch = string.format("0%x",ch)
|
||||
else ch = string.format("%x",ch)
|
||||
end
|
||||
--if ch > 64 and ch < 123 then
|
||||
-- out = out .. string.char(ch)
|
||||
--else
|
||||
out = out .. ch
|
||||
--end
|
||||
end
|
||||
print(out)
|
||||
local out = ''
|
||||
local ch
|
||||
for i = 1,strData:len() do
|
||||
out = out .." "
|
||||
ch =strData:byte(i)
|
||||
if(ch < 16) then
|
||||
ch = string.format("0%x",ch)
|
||||
else ch = string.format("%x",ch)
|
||||
end
|
||||
--if ch > 64 and ch < 123 then
|
||||
-- out = out .. string.char(ch)
|
||||
--else
|
||||
out = out .. ch
|
||||
--end
|
||||
end
|
||||
print(out)
|
||||
end
|
||||
|
||||
-- function test()
|
||||
-- local res
|
||||
-- res = versionQuery()
|
||||
-- print(type(res),res:len(),res)
|
||||
-- local out= bin.unpack('C'..#res,res)
|
||||
-- printBuffer(res)
|
||||
-- local res
|
||||
-- res = versionQuery()
|
||||
-- print(type(res),res:len(),res)
|
||||
-- local out= bin.unpack('C'..#res,res)
|
||||
-- printBuffer(res)
|
||||
-- end
|
||||
--test()
|
||||
|
||||
|
|
|
|||
6254
nselib/msrpc.lua
6254
nselib/msrpc.lua
File diff suppressed because it is too large
Load diff
|
|
@ -31,59 +31,59 @@ _ENV = stdnse.module("msrpcperformance", stdnse.seeall)
|
|||
--@return (status, pos, result) The status (true if successful), the new position in <code>data</code> (or an error
|
||||
-- message), and a table representing the datatype, if any.
|
||||
local function parse_perf_title_database(data, pos)
|
||||
local result = {}
|
||||
local i = 1
|
||||
local result = {}
|
||||
local i = 1
|
||||
|
||||
repeat
|
||||
local number, name
|
||||
pos, number, name = bin.unpack("<zz", data, pos)
|
||||
repeat
|
||||
local number, name
|
||||
pos, number, name = bin.unpack("<zz", data, pos)
|
||||
|
||||
if(number == nil) then
|
||||
return false, "Couldn't parse the title database: end of string encountered early"
|
||||
elseif(tonumber(number) == nil) then -- Not sure if this actually happens, but it doesn't hurt to check
|
||||
stdnse.print_debug(1, "MSRPC: ERROR: Couldn't parse the title database: string found where number expected (%d: '%s')", i, number)
|
||||
return false, "Couldn't parse the title database"
|
||||
end
|
||||
if(number == nil) then
|
||||
return false, "Couldn't parse the title database: end of string encountered early"
|
||||
elseif(tonumber(number) == nil) then -- Not sure if this actually happens, but it doesn't hurt to check
|
||||
stdnse.print_debug(1, "MSRPC: ERROR: Couldn't parse the title database: string found where number expected (%d: '%s')", i, number)
|
||||
return false, "Couldn't parse the title database"
|
||||
end
|
||||
|
||||
result[tonumber(number)] = name
|
||||
i = i + 1
|
||||
until pos >= #data
|
||||
result[tonumber(number)] = name
|
||||
i = i + 1
|
||||
until pos >= #data
|
||||
|
||||
return true, pos, result
|
||||
return true, pos, result
|
||||
end
|
||||
|
||||
---Parses a PERF_DATA_BLOCK, which has the following definition (from "WinPerf.h" on Visual Studio 8):
|
||||
--
|
||||
--<code>
|
||||
-- typedef struct _PERF_DATA_BLOCK {
|
||||
-- WCHAR Signature[4]; // Signature: Unicode "PERF"
|
||||
-- DWORD LittleEndian; // 0 = Big Endian, 1 = Little Endian
|
||||
-- DWORD Version; // Version of these data structures
|
||||
-- // starting at 1
|
||||
-- DWORD Revision; // Revision of these data structures
|
||||
-- // starting at 0 for each Version
|
||||
-- DWORD TotalByteLength; // Total length of data block
|
||||
-- DWORD HeaderLength; // Length of this structure
|
||||
-- DWORD NumObjectTypes; // Number of types of objects
|
||||
-- // being reported
|
||||
-- LONG DefaultObject; // Object Title Index of default
|
||||
-- // object to display when data from
|
||||
-- // this system is retrieved (-1 =
|
||||
-- // none, but this is not expected to
|
||||
-- // be used)
|
||||
-- SYSTEMTIME SystemTime; // Time at the system under
|
||||
-- // measurement
|
||||
-- LARGE_INTEGER PerfTime; // Performance counter value
|
||||
-- // at the system under measurement
|
||||
-- LARGE_INTEGER PerfFreq; // Performance counter frequency
|
||||
-- // at the system under measurement
|
||||
-- LARGE_INTEGER PerfTime100nSec; // Performance counter time in 100 nsec
|
||||
-- // units at the system under measurement
|
||||
-- DWORD SystemNameLength; // Length of the system name
|
||||
-- DWORD SystemNameOffset; // Offset, from beginning of this
|
||||
-- // structure, to name of system
|
||||
-- // being measured
|
||||
-- } PERF_DATA_BLOCK, *PPERF_DATA_BLOCK;
|
||||
-- typedef struct _PERF_DATA_BLOCK {
|
||||
-- WCHAR Signature[4]; // Signature: Unicode "PERF"
|
||||
-- DWORD LittleEndian; // 0 = Big Endian, 1 = Little Endian
|
||||
-- DWORD Version; // Version of these data structures
|
||||
-- // starting at 1
|
||||
-- DWORD Revision; // Revision of these data structures
|
||||
-- // starting at 0 for each Version
|
||||
-- DWORD TotalByteLength; // Total length of data block
|
||||
-- DWORD HeaderLength; // Length of this structure
|
||||
-- DWORD NumObjectTypes; // Number of types of objects
|
||||
-- // being reported
|
||||
-- LONG DefaultObject; // Object Title Index of default
|
||||
-- // object to display when data from
|
||||
-- // this system is retrieved (-1 =
|
||||
-- // none, but this is not expected to
|
||||
-- // be used)
|
||||
-- SYSTEMTIME SystemTime; // Time at the system under
|
||||
-- // measurement
|
||||
-- LARGE_INTEGER PerfTime; // Performance counter value
|
||||
-- // at the system under measurement
|
||||
-- LARGE_INTEGER PerfFreq; // Performance counter frequency
|
||||
-- // at the system under measurement
|
||||
-- LARGE_INTEGER PerfTime100nSec; // Performance counter time in 100 nsec
|
||||
-- // units at the system under measurement
|
||||
-- DWORD SystemNameLength; // Length of the system name
|
||||
-- DWORD SystemNameOffset; // Offset, from beginning of this
|
||||
-- // structure, to name of system
|
||||
-- // being measured
|
||||
-- } PERF_DATA_BLOCK, *PPERF_DATA_BLOCK;
|
||||
--</code>
|
||||
--
|
||||
--@param data The data being processed.
|
||||
|
|
@ -91,47 +91,47 @@ end
|
|||
--@return (status, pos, result) The status (true if successful), the new position in <code>data</code> (or an error
|
||||
-- message), and a table representing the datatype, if any.
|
||||
local function parse_perf_data_block(data, pos)
|
||||
local result = {}
|
||||
local result = {}
|
||||
|
||||
pos, result['Signature'] = msrpctypes.unicode_to_string(data, pos, 4, false)
|
||||
if(result['Signature'] ~= "PERF") then
|
||||
return false, "MSRPC: PERF_DATA_BLOCK signature is missing or incorrect"
|
||||
end
|
||||
pos, result['Signature'] = msrpctypes.unicode_to_string(data, pos, 4, false)
|
||||
if(result['Signature'] ~= "PERF") then
|
||||
return false, "MSRPC: PERF_DATA_BLOCK signature is missing or incorrect"
|
||||
end
|
||||
|
||||
pos, result['LittleEndian'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
if(result['LittleEndian'] ~= 1) then
|
||||
return false, "MSRPC: PERF_DATA_BLOCK returned a non-understood endianness"
|
||||
end
|
||||
pos, result['LittleEndian'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
if(result['LittleEndian'] ~= 1) then
|
||||
return false, "MSRPC: PERF_DATA_BLOCK returned a non-understood endianness"
|
||||
end
|
||||
|
||||
-- Parse the header
|
||||
pos, result['Version'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['Revision'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['TotalByteLength'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['HeaderLength'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['NumObjectTypes'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['DefaultObject'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['SystemTime'] = msrpctypes.unmarshall_SYSTEMTIME(data, pos)
|
||||
pos, result['PerfTime'] = msrpctypes.unmarshall_int64(data, pos)
|
||||
pos, result['PerfFreq'] = msrpctypes.unmarshall_int64(data, pos)
|
||||
pos, result['PerfTime100nSec'] = msrpctypes.unmarshall_int64(data, pos)
|
||||
pos = pos + 4 -- This value doesn't seem to line up, so add 4
|
||||
-- Parse the header
|
||||
pos, result['Version'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['Revision'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['TotalByteLength'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['HeaderLength'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['NumObjectTypes'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['DefaultObject'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['SystemTime'] = msrpctypes.unmarshall_SYSTEMTIME(data, pos)
|
||||
pos, result['PerfTime'] = msrpctypes.unmarshall_int64(data, pos)
|
||||
pos, result['PerfFreq'] = msrpctypes.unmarshall_int64(data, pos)
|
||||
pos, result['PerfTime100nSec'] = msrpctypes.unmarshall_int64(data, pos)
|
||||
pos = pos + 4 -- This value doesn't seem to line up, so add 4
|
||||
|
||||
pos, result['SystemNameLength'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['SystemNameOffset'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['SystemNameLength'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['SystemNameOffset'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
|
||||
-- Ensure that the system name is directly after the header. This technically shouldn't matter, but Microsoft's documentation
|
||||
-- (in WinPref.h) says that the actual object comes "after the PERF_DATA_BLOCK", so it doesn't make sense that the SystemName
|
||||
-- could be anywhere else.
|
||||
if(pos ~= result['SystemNameOffset'] + 1) then
|
||||
return false, "MSRPC: PERF_DATA_BLOCK has SystemName in the wrong location"
|
||||
end
|
||||
-- Ensure that the system name is directly after the header. This technically shouldn't matter, but Microsoft's documentation
|
||||
-- (in WinPref.h) says that the actual object comes "after the PERF_DATA_BLOCK", so it doesn't make sense that the SystemName
|
||||
-- could be anywhere else.
|
||||
if(pos ~= result['SystemNameOffset'] + 1) then
|
||||
return false, "MSRPC: PERF_DATA_BLOCK has SystemName in the wrong location"
|
||||
end
|
||||
|
||||
-- Read the system name from the next location (which happens to be identical to SystemNameOffset, on a proper system)
|
||||
pos, result['SystemName'] = msrpctypes.unicode_to_string(data, pos, result['SystemNameLength'] / 2, true)
|
||||
-- Read the system name from the next location (which happens to be identical to SystemNameOffset, on a proper system)
|
||||
pos, result['SystemName'] = msrpctypes.unicode_to_string(data, pos, result['SystemNameLength'] / 2, true)
|
||||
|
||||
pos = pos + 4 -- Again, we end up not lined up so here we fix it
|
||||
pos = pos + 4 -- Again, we end up not lined up so here we fix it
|
||||
|
||||
return true, pos, result
|
||||
return true, pos, result
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -144,74 +144,74 @@ end
|
|||
-- // type section begins with a _PERF_OBJECT_TYPE structure.
|
||||
-- //
|
||||
-- typedef struct _PERF_OBJECT_TYPE {
|
||||
-- DWORD TotalByteLength; // Length of this object definition
|
||||
-- // including this structure, the
|
||||
-- // counter definitions, and the
|
||||
-- // instance definitions and the
|
||||
-- // counter blocks for each instance:
|
||||
-- // This is the offset from this
|
||||
-- // structure to the next object, if
|
||||
-- // any
|
||||
-- DWORD DefinitionLength; // Length of object definition,
|
||||
-- // which includes this structure
|
||||
-- // and the counter definition
|
||||
-- // structures for this object: this
|
||||
-- // is the offset of the first
|
||||
-- // instance or of the counters
|
||||
-- // for this object if there is
|
||||
-- // no instance
|
||||
-- DWORD HeaderLength; // Length of this structure: this
|
||||
-- // is the offset to the first
|
||||
-- // counter definition for this
|
||||
-- // object
|
||||
-- DWORD ObjectNameTitleIndex;
|
||||
-- // Index to name in Title Database
|
||||
-- DWORD TotalByteLength; // Length of this object definition
|
||||
-- // including this structure, the
|
||||
-- // counter definitions, and the
|
||||
-- // instance definitions and the
|
||||
-- // counter blocks for each instance:
|
||||
-- // This is the offset from this
|
||||
-- // structure to the next object, if
|
||||
-- // any
|
||||
-- DWORD DefinitionLength; // Length of object definition,
|
||||
-- // which includes this structure
|
||||
-- // and the counter definition
|
||||
-- // structures for this object: this
|
||||
-- // is the offset of the first
|
||||
-- // instance or of the counters
|
||||
-- // for this object if there is
|
||||
-- // no instance
|
||||
-- DWORD HeaderLength; // Length of this structure: this
|
||||
-- // is the offset to the first
|
||||
-- // counter definition for this
|
||||
-- // object
|
||||
-- DWORD ObjectNameTitleIndex;
|
||||
-- // Index to name in Title Database
|
||||
-- #ifdef _WIN64
|
||||
-- DWORD ObjectNameTitle; // Should use this as an offset
|
||||
-- DWORD ObjectNameTitle; // Should use this as an offset
|
||||
-- #else
|
||||
-- LPWSTR ObjectNameTitle; // Initially NULL, for use by
|
||||
-- // analysis program to point to
|
||||
-- // retrieved title string
|
||||
-- LPWSTR ObjectNameTitle; // Initially NULL, for use by
|
||||
-- // analysis program to point to
|
||||
-- // retrieved title string
|
||||
-- #endif
|
||||
-- DWORD ObjectHelpTitleIndex;
|
||||
-- // Index to Help in Title Database
|
||||
-- DWORD ObjectHelpTitleIndex;
|
||||
-- // Index to Help in Title Database
|
||||
-- #ifdef _WIN64
|
||||
-- DWORD ObjectHelpTitle; // Should use this as an offset
|
||||
-- DWORD ObjectHelpTitle; // Should use this as an offset
|
||||
-- #else
|
||||
-- LPWSTR ObjectHelpTitle; // Initially NULL, for use by
|
||||
-- // analysis program to point to
|
||||
-- // retrieved title string
|
||||
-- LPWSTR ObjectHelpTitle; // Initially NULL, for use by
|
||||
-- // analysis program to point to
|
||||
-- // retrieved title string
|
||||
-- #endif
|
||||
-- DWORD DetailLevel; // Object level of detail (for
|
||||
-- // controlling display complexity);
|
||||
-- // will be min of detail levels
|
||||
-- // for all this object's counters
|
||||
-- DWORD NumCounters; // Number of counters in each
|
||||
-- // counter block (one counter
|
||||
-- // block per instance)
|
||||
-- LONG DefaultCounter; // Default counter to display when
|
||||
-- // this object is selected, index
|
||||
-- // starting at 0 (-1 = none, but
|
||||
-- // this is not expected to be used)
|
||||
-- LONG NumInstances; // Number of object instances
|
||||
-- // for which counters are being
|
||||
-- // returned from the system under
|
||||
-- // measurement. If the object defined
|
||||
-- // will never have any instance data
|
||||
-- // structures (PERF_INSTANCE_DEFINITION)
|
||||
-- // then this value should be -1, if the
|
||||
-- // object can have 0 or more instances,
|
||||
-- // but has none present, then this
|
||||
-- // should be 0, otherwise this field
|
||||
-- // contains the number of instances of
|
||||
-- // this counter.
|
||||
-- DWORD CodePage; // 0 if instance strings are in
|
||||
-- // UNICODE, else the Code Page of
|
||||
-- // the instance names
|
||||
-- LARGE_INTEGER PerfTime; // Sample Time in "Object" units
|
||||
-- //
|
||||
-- LARGE_INTEGER PerfFreq; // Frequency of "Object" units in
|
||||
-- // counts per second.
|
||||
-- DWORD DetailLevel; // Object level of detail (for
|
||||
-- // controlling display complexity);
|
||||
-- // will be min of detail levels
|
||||
-- // for all this object's counters
|
||||
-- DWORD NumCounters; // Number of counters in each
|
||||
-- // counter block (one counter
|
||||
-- // block per instance)
|
||||
-- LONG DefaultCounter; // Default counter to display when
|
||||
-- // this object is selected, index
|
||||
-- // starting at 0 (-1 = none, but
|
||||
-- // this is not expected to be used)
|
||||
-- LONG NumInstances; // Number of object instances
|
||||
-- // for which counters are being
|
||||
-- // returned from the system under
|
||||
-- // measurement. If the object defined
|
||||
-- // will never have any instance data
|
||||
-- // structures (PERF_INSTANCE_DEFINITION)
|
||||
-- // then this value should be -1, if the
|
||||
-- // object can have 0 or more instances,
|
||||
-- // but has none present, then this
|
||||
-- // should be 0, otherwise this field
|
||||
-- // contains the number of instances of
|
||||
-- // this counter.
|
||||
-- DWORD CodePage; // 0 if instance strings are in
|
||||
-- // UNICODE, else the Code Page of
|
||||
-- // the instance names
|
||||
-- LARGE_INTEGER PerfTime; // Sample Time in "Object" units
|
||||
-- //
|
||||
-- LARGE_INTEGER PerfFreq; // Frequency of "Object" units in
|
||||
-- // counts per second.
|
||||
-- } PERF_OBJECT_TYPE, *PPERF_OBJECT_TYPE;
|
||||
--</code>
|
||||
--
|
||||
|
|
@ -220,69 +220,69 @@ end
|
|||
--@return (status, pos, result) The status (true if successful), the new position in <code>data</code> (or an error
|
||||
-- message), and a table representing the datatype, if any.
|
||||
local function parse_perf_object_type(data, pos)
|
||||
local result = {}
|
||||
local result = {}
|
||||
|
||||
pos, result['TotalByteLength'] = msrpctypes.unmarshall_int32(data, pos) -- Offset to the next object
|
||||
pos, result['DefinitionLength'] = msrpctypes.unmarshall_int32(data, pos) -- Offset to the first instance (or counter, if no instances)
|
||||
pos, result['HeaderLength'] = msrpctypes.unmarshall_int32(data, pos) -- Offset to the first counter definition
|
||||
pos, result['ObjectNameTitleIndex'] = msrpctypes.unmarshall_int32(data, pos) -- Index in the Title Database
|
||||
pos, result['ObjectNameTitle'] = msrpctypes.unmarshall_int32(data, pos) -- TODO: will this work with 64-bit?
|
||||
pos, result['ObjectHelpTitleIndex'] = msrpctypes.unmarshall_int32(data, pos) -- Index in the Help Database
|
||||
pos, result['ObjectHelpTitle'] = msrpctypes.unmarshall_int32(data, pos) -- TODO: will this workw ith 64-bit?
|
||||
pos, result['DetailLevel'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['NumCounters'] = msrpctypes.unmarshall_int32(data, pos) -- The number of counters in each counter block
|
||||
pos, result['DefaultCounter'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['NumInstances'] = msrpctypes.unmarshall_int32(data, pos) -- Numer of object instances for which counters are being returned
|
||||
pos, result['CodePage'] = msrpctypes.unmarshall_int32(data, pos) -- 0 if strings are in UNICODE, otherwise the Code Page
|
||||
-- if(result['CodePage'] ~= 0) then
|
||||
-- return false, string.format("Unknown Code Page for data: %d\n", result['CodePage'])
|
||||
-- end
|
||||
pos, result['PerfTime'] = msrpctypes.unmarshall_int64(data, pos) -- Sample time in "Object" units
|
||||
pos, result['PerfFreq'] = msrpctypes.unmarshall_int64(data, pos) -- Frequency of "Object" units in counts/second
|
||||
pos, result['TotalByteLength'] = msrpctypes.unmarshall_int32(data, pos) -- Offset to the next object
|
||||
pos, result['DefinitionLength'] = msrpctypes.unmarshall_int32(data, pos) -- Offset to the first instance (or counter, if no instances)
|
||||
pos, result['HeaderLength'] = msrpctypes.unmarshall_int32(data, pos) -- Offset to the first counter definition
|
||||
pos, result['ObjectNameTitleIndex'] = msrpctypes.unmarshall_int32(data, pos) -- Index in the Title Database
|
||||
pos, result['ObjectNameTitle'] = msrpctypes.unmarshall_int32(data, pos) -- TODO: will this work with 64-bit?
|
||||
pos, result['ObjectHelpTitleIndex'] = msrpctypes.unmarshall_int32(data, pos) -- Index in the Help Database
|
||||
pos, result['ObjectHelpTitle'] = msrpctypes.unmarshall_int32(data, pos) -- TODO: will this workw ith 64-bit?
|
||||
pos, result['DetailLevel'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['NumCounters'] = msrpctypes.unmarshall_int32(data, pos) -- The number of counters in each counter block
|
||||
pos, result['DefaultCounter'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['NumInstances'] = msrpctypes.unmarshall_int32(data, pos) -- Numer of object instances for which counters are being returned
|
||||
pos, result['CodePage'] = msrpctypes.unmarshall_int32(data, pos) -- 0 if strings are in UNICODE, otherwise the Code Page
|
||||
-- if(result['CodePage'] ~= 0) then
|
||||
-- return false, string.format("Unknown Code Page for data: %d\n", result['CodePage'])
|
||||
-- end
|
||||
pos, result['PerfTime'] = msrpctypes.unmarshall_int64(data, pos) -- Sample time in "Object" units
|
||||
pos, result['PerfFreq'] = msrpctypes.unmarshall_int64(data, pos) -- Frequency of "Object" units in counts/second
|
||||
|
||||
return true, pos, result
|
||||
return true, pos, result
|
||||
end
|
||||
|
||||
|
||||
---Parse a PERF_COUNTER_DEFINITION structure. From Microsoft's documentation:
|
||||
--
|
||||
--<code>
|
||||
-- // There is one of the following for each of the
|
||||
-- // PERF_OBJECT_TYPE.NumCounters. The Unicode names in this structure MUST
|
||||
-- // come from a message file.
|
||||
-- typedef struct _PERF_COUNTER_DEFINITION {
|
||||
-- DWORD ByteLength; // Length in bytes of this structure
|
||||
-- DWORD CounterNameTitleIndex;
|
||||
-- // Index of Counter name into
|
||||
-- // Title Database
|
||||
-- #ifdef _WIN64
|
||||
-- DWORD CounterNameTitle;
|
||||
-- #else
|
||||
-- LPWSTR CounterNameTitle; // Initially NULL, for use by
|
||||
-- // analysis program to point to
|
||||
-- // retrieved title string
|
||||
-- #endif
|
||||
-- DWORD CounterHelpTitleIndex;
|
||||
-- // Index of Counter Help into
|
||||
-- // Title Database
|
||||
-- #ifdef _WIN64
|
||||
-- DWORD CounterHelpTitle;
|
||||
-- #else
|
||||
-- LPWSTR CounterHelpTitle; // Initially NULL, for use by
|
||||
-- // analysis program to point to
|
||||
-- // retrieved title string
|
||||
-- #endif
|
||||
-- LONG DefaultScale; // Power of 10 by which to scale
|
||||
-- // chart line if vertical axis is 100
|
||||
-- // 0 ==> 1, 1 ==> 10, -1 ==>1/10, etc.
|
||||
-- DWORD DetailLevel; // Counter level of detail (for
|
||||
-- // controlling display complexity)
|
||||
-- DWORD CounterType; // Type of counter
|
||||
-- DWORD CounterSize; // Size of counter in bytes
|
||||
-- DWORD CounterOffset; // Offset from the start of the
|
||||
-- // PERF_COUNTER_BLOCK to the first
|
||||
-- // byte of this counter
|
||||
-- } PERF_COUNTER_DEFINITION, *PPERF_COUNTER_DEFINITION;
|
||||
-- // There is one of the following for each of the
|
||||
-- // PERF_OBJECT_TYPE.NumCounters. The Unicode names in this structure MUST
|
||||
-- // come from a message file.
|
||||
-- typedef struct _PERF_COUNTER_DEFINITION {
|
||||
-- DWORD ByteLength; // Length in bytes of this structure
|
||||
-- DWORD CounterNameTitleIndex;
|
||||
-- // Index of Counter name into
|
||||
-- // Title Database
|
||||
-- #ifdef _WIN64
|
||||
-- DWORD CounterNameTitle;
|
||||
-- #else
|
||||
-- LPWSTR CounterNameTitle; // Initially NULL, for use by
|
||||
-- // analysis program to point to
|
||||
-- // retrieved title string
|
||||
-- #endif
|
||||
-- DWORD CounterHelpTitleIndex;
|
||||
-- // Index of Counter Help into
|
||||
-- // Title Database
|
||||
-- #ifdef _WIN64
|
||||
-- DWORD CounterHelpTitle;
|
||||
-- #else
|
||||
-- LPWSTR CounterHelpTitle; // Initially NULL, for use by
|
||||
-- // analysis program to point to
|
||||
-- // retrieved title string
|
||||
-- #endif
|
||||
-- LONG DefaultScale; // Power of 10 by which to scale
|
||||
-- // chart line if vertical axis is 100
|
||||
-- // 0 ==> 1, 1 ==> 10, -1 ==>1/10, etc.
|
||||
-- DWORD DetailLevel; // Counter level of detail (for
|
||||
-- // controlling display complexity)
|
||||
-- DWORD CounterType; // Type of counter
|
||||
-- DWORD CounterSize; // Size of counter in bytes
|
||||
-- DWORD CounterOffset; // Offset from the start of the
|
||||
-- // PERF_COUNTER_BLOCK to the first
|
||||
-- // byte of this counter
|
||||
-- } PERF_COUNTER_DEFINITION, *PPERF_COUNTER_DEFINITION;
|
||||
--</code>
|
||||
--
|
||||
--@param data The data being processed.
|
||||
|
|
@ -290,23 +290,23 @@ end
|
|||
--@return (status, pos, result) The status (true if successful), the new position in <code>data</code> (or an error
|
||||
-- message), and a table representing the datatype, if any.
|
||||
local function parse_perf_counter_definition(data, pos)
|
||||
local result = {}
|
||||
local initial_pos = pos
|
||||
local result = {}
|
||||
local initial_pos = pos
|
||||
|
||||
pos, result['ByteLength'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['CounterNameTitleIndex'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['CounterNameTitle'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['CounterHelpTitleIndex'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['CounterHelpTitle'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['DefaultScale'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['DetailLevel'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['CounterType'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['CounterSize'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['CounterOffset'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['ByteLength'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['CounterNameTitleIndex'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['CounterNameTitle'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['CounterHelpTitleIndex'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['CounterHelpTitle'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['DefaultScale'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['DetailLevel'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['CounterType'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['CounterSize'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['CounterOffset'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
|
||||
pos = initial_pos + result['ByteLength']
|
||||
pos = initial_pos + result['ByteLength']
|
||||
|
||||
return true, pos, result
|
||||
return true, pos, result
|
||||
end
|
||||
|
||||
---Parse the actual counter value. This is a fairly simple function, it takes a counter
|
||||
|
|
@ -321,57 +321,57 @@ end
|
|||
--@return (status, pos, result) The status (true if successful), the new position in <code>data</code> (or an error
|
||||
-- message), and a table representing the datatype, if any.
|
||||
local function parse_perf_counter(data, pos, counter_definition)
|
||||
local result
|
||||
local result
|
||||
|
||||
if(counter_definition['CounterSize'] == 4) then
|
||||
pos, result = msrpctypes.unmarshall_int32(data, pos)
|
||||
elseif(counter_definition['CounterSize'] == 8) then
|
||||
pos, result = msrpctypes.unmarshall_int64(data, pos)
|
||||
-- pos, result = bin.unpack("<d", data, pos)
|
||||
else
|
||||
pos, result = msrpctypes.unmarshall_raw(data, pos, counter_definition['CounterSize'])
|
||||
end
|
||||
if(counter_definition['CounterSize'] == 4) then
|
||||
pos, result = msrpctypes.unmarshall_int32(data, pos)
|
||||
elseif(counter_definition['CounterSize'] == 8) then
|
||||
pos, result = msrpctypes.unmarshall_int64(data, pos)
|
||||
-- pos, result = bin.unpack("<d", data, pos)
|
||||
else
|
||||
pos, result = msrpctypes.unmarshall_raw(data, pos, counter_definition['CounterSize'])
|
||||
end
|
||||
|
||||
return true, pos, result
|
||||
return true, pos, result
|
||||
end
|
||||
|
||||
---Parse a PERF_INSTANCE_DEFINITION structure. From Microsoft's documentation:
|
||||
--
|
||||
--<code>
|
||||
-- // If (PERF_DATA_BLOCK.NumInstances >= 0) then there will be
|
||||
-- // PERF_DATA_BLOCK.NumInstances of a (PERF_INSTANCE_DEFINITION
|
||||
-- // followed by a PERF_COUNTER_BLOCK followed by the counter data fields)
|
||||
-- // for each instance.
|
||||
-- //
|
||||
-- // If (PERF_DATA_BLOCK.NumInstances < 0) then the counter definition
|
||||
-- // strucutre above will be followed by only a PERF_COUNTER_BLOCK and the
|
||||
-- // counter data for that COUNTER.
|
||||
-- typedef struct _PERF_INSTANCE_DEFINITION {
|
||||
-- DWORD ByteLength; // Length in bytes of this structure,
|
||||
-- // including the subsequent name
|
||||
-- DWORD ParentObjectTitleIndex;
|
||||
-- // Title Index to name of "parent"
|
||||
-- // object (e.g., if thread, then
|
||||
-- // process is parent object type);
|
||||
-- // if logical drive, the physical
|
||||
-- // drive is parent object type
|
||||
-- DWORD ParentObjectInstance;
|
||||
-- // Index to instance of parent object
|
||||
-- // type which is the parent of this
|
||||
-- // instance.
|
||||
-- LONG UniqueID; // A unique ID used instead of
|
||||
-- // matching the name to identify
|
||||
-- // this instance, -1 = none
|
||||
-- DWORD NameOffset; // Offset from beginning of
|
||||
-- // this struct to the Unicode name
|
||||
-- // of this instance
|
||||
-- DWORD NameLength; // Length in bytes of name; 0 = none
|
||||
-- // this length includes the characters
|
||||
-- // in the string plus the size of the
|
||||
-- // terminating NULL char. It does not
|
||||
-- // include any additional pad bytes to
|
||||
-- // correct structure alignment
|
||||
-- } PERF_INSTANCE_DEFINITION, *PPERF_INSTANCE_DEFINITION;
|
||||
-- // If (PERF_DATA_BLOCK.NumInstances >= 0) then there will be
|
||||
-- // PERF_DATA_BLOCK.NumInstances of a (PERF_INSTANCE_DEFINITION
|
||||
-- // followed by a PERF_COUNTER_BLOCK followed by the counter data fields)
|
||||
-- // for each instance.
|
||||
-- //
|
||||
-- // If (PERF_DATA_BLOCK.NumInstances < 0) then the counter definition
|
||||
-- // strucutre above will be followed by only a PERF_COUNTER_BLOCK and the
|
||||
-- // counter data for that COUNTER.
|
||||
-- typedef struct _PERF_INSTANCE_DEFINITION {
|
||||
-- DWORD ByteLength; // Length in bytes of this structure,
|
||||
-- // including the subsequent name
|
||||
-- DWORD ParentObjectTitleIndex;
|
||||
-- // Title Index to name of "parent"
|
||||
-- // object (e.g., if thread, then
|
||||
-- // process is parent object type);
|
||||
-- // if logical drive, the physical
|
||||
-- // drive is parent object type
|
||||
-- DWORD ParentObjectInstance;
|
||||
-- // Index to instance of parent object
|
||||
-- // type which is the parent of this
|
||||
-- // instance.
|
||||
-- LONG UniqueID; // A unique ID used instead of
|
||||
-- // matching the name to identify
|
||||
-- // this instance, -1 = none
|
||||
-- DWORD NameOffset; // Offset from beginning of
|
||||
-- // this struct to the Unicode name
|
||||
-- // of this instance
|
||||
-- DWORD NameLength; // Length in bytes of name; 0 = none
|
||||
-- // this length includes the characters
|
||||
-- // in the string plus the size of the
|
||||
-- // terminating NULL char. It does not
|
||||
-- // include any additional pad bytes to
|
||||
-- // correct structure alignment
|
||||
-- } PERF_INSTANCE_DEFINITION, *PPERF_INSTANCE_DEFINITION;
|
||||
--</code>
|
||||
--
|
||||
--@param data The data being processed.
|
||||
|
|
@ -379,33 +379,33 @@ end
|
|||
--@return (status, pos, result) The status (true if successful), the new position in <code>data</code> (or an error
|
||||
-- message), and a table representing the datatype, if any.
|
||||
local function parse_perf_instance_definition(data, pos)
|
||||
local result = {}
|
||||
local result = {}
|
||||
|
||||
-- Remember where we started. I noticed that where the counter part starts can move around, so we have to
|
||||
-- determine it by adding ByteLength to the initial position
|
||||
local initial_pos = pos
|
||||
-- Remember where we started. I noticed that where the counter part starts can move around, so we have to
|
||||
-- determine it by adding ByteLength to the initial position
|
||||
local initial_pos = pos
|
||||
|
||||
pos, result['ByteLength'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['ParentObjectTitleIndex'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['ParentObjectInstance'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['UniqueID'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['NameOffset'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['NameLength'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['ByteLength'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['ParentObjectTitleIndex'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['ParentObjectInstance'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['UniqueID'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['NameOffset'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['NameLength'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
|
||||
pos, result['InstanceName'] = msrpctypes.unicode_to_string(data, pos, result['NameLength'] / 2, true)
|
||||
pos, result['InstanceName'] = msrpctypes.unicode_to_string(data, pos, result['NameLength'] / 2, true)
|
||||
|
||||
pos = initial_pos + result['ByteLength']
|
||||
pos = initial_pos + result['ByteLength']
|
||||
|
||||
return true, pos, result
|
||||
return true, pos, result
|
||||
end
|
||||
|
||||
---Parse a PERF_COUNTER_BLOCK structure. From Microsoft's documentation:
|
||||
--
|
||||
--<code>
|
||||
-- typedef struct _PERF_COUNTER_BLOCK {
|
||||
-- DWORD ByteLength; // Length in bytes of this structure,
|
||||
-- // including the following counters
|
||||
-- } PERF_COUNTER_BLOCK, *PPERF_COUNTER_BLOCK;
|
||||
-- typedef struct _PERF_COUNTER_BLOCK {
|
||||
-- DWORD ByteLength; // Length in bytes of this structure,
|
||||
-- // including the following counters
|
||||
-- } PERF_COUNTER_BLOCK, *PPERF_COUNTER_BLOCK;
|
||||
--
|
||||
--</code>
|
||||
--
|
||||
|
|
@ -414,11 +414,11 @@ end
|
|||
--@return (status, pos, result) The status (true if successful), the new position in <code>data</code> (or an error
|
||||
-- message), and a table representing the datatype, if any.
|
||||
local function parse_perf_counter_block(data, pos)
|
||||
local result = {}
|
||||
local result = {}
|
||||
|
||||
pos, result['ByteLength'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
pos, result['ByteLength'] = msrpctypes.unmarshall_int32(data, pos)
|
||||
|
||||
return true, pos, result
|
||||
return true, pos, result
|
||||
end
|
||||
|
||||
---Retrieve the parsed performance data from the given host for the requested object values. To get a list of possible
|
||||
|
|
@ -430,186 +430,186 @@ end
|
|||
--@param objects [optional] The space-separated list of object numbers to retrieve. Default: only retrieve the database.
|
||||
function get_performance_data(host, objects)
|
||||
|
||||
-- Create the SMB session
|
||||
local status, smbstate = msrpc.start_smb(host, msrpc.WINREG_PATH)
|
||||
if(status == false) then
|
||||
return false, smbstate
|
||||
end
|
||||
-- Create the SMB session
|
||||
local status, smbstate = msrpc.start_smb(host, msrpc.WINREG_PATH)
|
||||
if(status == false) then
|
||||
return false, smbstate
|
||||
end
|
||||
|
||||
-- Bind to WINREG service
|
||||
local status, bind_result = msrpc.bind(smbstate, msrpc.WINREG_UUID, msrpc.WINREG_VERSION, nil)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, bind_result
|
||||
end
|
||||
-- Bind to WINREG service
|
||||
local status, bind_result = msrpc.bind(smbstate, msrpc.WINREG_UUID, msrpc.WINREG_VERSION, nil)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, bind_result
|
||||
end
|
||||
|
||||
-- Open HKEY_PERFORMANCE_DATA
|
||||
local status, openhkpd_result = msrpc.winreg_openhkpd(smbstate)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, openhkpd_result
|
||||
end
|
||||
-- Open HKEY_PERFORMANCE_DATA
|
||||
local status, openhkpd_result = msrpc.winreg_openhkpd(smbstate)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, openhkpd_result
|
||||
end
|
||||
|
||||
local status, queryvalue_result = msrpc.winreg_queryvalue(smbstate, openhkpd_result['handle'], "Counter 009")
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, queryvalue_result
|
||||
end
|
||||
local status, queryvalue_result = msrpc.winreg_queryvalue(smbstate, openhkpd_result['handle'], "Counter 009")
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, queryvalue_result
|
||||
end
|
||||
|
||||
-- Parse the title database
|
||||
local pos = 1
|
||||
local status
|
||||
local result = {}
|
||||
status, pos, result['title_database'] = parse_perf_title_database(queryvalue_result['value'], pos)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, pos
|
||||
end
|
||||
result['title_database'][0] = "<null>"
|
||||
-- Parse the title database
|
||||
local pos = 1
|
||||
local status
|
||||
local result = {}
|
||||
status, pos, result['title_database'] = parse_perf_title_database(queryvalue_result['value'], pos)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, pos
|
||||
end
|
||||
result['title_database'][0] = "<null>"
|
||||
|
||||
|
||||
if(objects ~= nil and #objects > 0) then
|
||||
-- Query for the objects
|
||||
local status, queryvalue_result = msrpc.winreg_queryvalue(smbstate, openhkpd_result['handle'], objects)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, queryvalue_result
|
||||
end
|
||||
if(objects ~= nil and #objects > 0) then
|
||||
-- Query for the objects
|
||||
local status, queryvalue_result = msrpc.winreg_queryvalue(smbstate, openhkpd_result['handle'], objects)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, queryvalue_result
|
||||
end
|
||||
|
||||
-- Parse the header
|
||||
pos = 1
|
||||
local status, data_block
|
||||
status, pos, data_block = parse_perf_data_block(queryvalue_result['value'], pos)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, pos
|
||||
end
|
||||
-- Parse the header
|
||||
pos = 1
|
||||
local status, data_block
|
||||
status, pos, data_block = parse_perf_data_block(queryvalue_result['value'], pos)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, pos
|
||||
end
|
||||
|
||||
-- Move past the header
|
||||
pos = 1 + data_block['HeaderLength']
|
||||
-- Move past the header
|
||||
pos = 1 + data_block['HeaderLength']
|
||||
|
||||
-- Parse the data sections
|
||||
for i = 1, data_block['NumObjectTypes'], 1 do
|
||||
local object_start = pos
|
||||
-- Parse the data sections
|
||||
for i = 1, data_block['NumObjectTypes'], 1 do
|
||||
local object_start = pos
|
||||
|
||||
local counter_definitions = {}
|
||||
local object_instances = {}
|
||||
local counter_definitions = {}
|
||||
local counter_definitions = {}
|
||||
local object_instances = {}
|
||||
local counter_definitions = {}
|
||||
|
||||
-- Get the type of the object (this is basically the class definition -- info about the object instances)
|
||||
local status, object_type
|
||||
status, pos, object_type = parse_perf_object_type(queryvalue_result['value'], pos)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, pos
|
||||
end
|
||||
-- Get the type of the object (this is basically the class definition -- info about the object instances)
|
||||
local status, object_type
|
||||
status, pos, object_type = parse_perf_object_type(queryvalue_result['value'], pos)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, pos
|
||||
end
|
||||
|
||||
-- Start setting up the result object
|
||||
--stdnse.print_debug("Index = %d\n", object_type['ObjectNameTitleIndex'])
|
||||
local object_name = result['title_database'][object_type['ObjectNameTitleIndex']]
|
||||
result[object_name] = {}
|
||||
-- Start setting up the result object
|
||||
--stdnse.print_debug("Index = %d\n", object_type['ObjectNameTitleIndex'])
|
||||
local object_name = result['title_database'][object_type['ObjectNameTitleIndex']]
|
||||
result[object_name] = {}
|
||||
|
||||
--stdnse.print_debug("\n\nOBJECT: %s\n", object_name)
|
||||
--stdnse.print_debug(" Counters: %d\n", object_type['NumCounters'])
|
||||
--stdnse.print_debug(" Instances: %d\n", object_type['NumInstances'])
|
||||
--stdnse.print_debug("-----------------\n")
|
||||
--stdnse.print_debug("\n\nOBJECT: %s\n", object_name)
|
||||
--stdnse.print_debug(" Counters: %d\n", object_type['NumCounters'])
|
||||
--stdnse.print_debug(" Instances: %d\n", object_type['NumInstances'])
|
||||
--stdnse.print_debug("-----------------\n")
|
||||
|
||||
-- Bring the position to the beginning of the counter definitions
|
||||
pos = object_start + object_type['HeaderLength']
|
||||
-- Bring the position to the beginning of the counter definitions
|
||||
pos = object_start + object_type['HeaderLength']
|
||||
|
||||
-- Parse the counter definitions
|
||||
for j = 1, object_type['NumCounters'], 1 do
|
||||
status, pos, counter_definitions[j] = parse_perf_counter_definition(queryvalue_result['value'], pos)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, pos
|
||||
end
|
||||
--stdnse.print_debug(" Counter definition #%2d: [%d bytes] %s\n", j, counter_definitions[j]['CounterSize'], result['title_database'][counter_definitions[j]['CounterNameTitleIndex']])
|
||||
end
|
||||
-- Parse the counter definitions
|
||||
for j = 1, object_type['NumCounters'], 1 do
|
||||
status, pos, counter_definitions[j] = parse_perf_counter_definition(queryvalue_result['value'], pos)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, pos
|
||||
end
|
||||
--stdnse.print_debug(" Counter definition #%2d: [%d bytes] %s\n", j, counter_definitions[j]['CounterSize'], result['title_database'][counter_definitions[j]['CounterNameTitleIndex']])
|
||||
end
|
||||
|
||||
-- Bring the position to the beginning of the instances (or counters)
|
||||
pos = object_start + object_type['DefinitionLength']
|
||||
-- Bring the position to the beginning of the instances (or counters)
|
||||
pos = object_start + object_type['DefinitionLength']
|
||||
|
||||
-- Check if we have any instances (sometimes we don't -- if we don't, the value returned is a negative)
|
||||
if(bit.band(object_type['NumInstances'], 0x80000000) == 0) then
|
||||
-- Parse the object instances and counters
|
||||
for j = 1, object_type['NumInstances'], 1 do
|
||||
local instance_start = pos
|
||||
-- Check if we have any instances (sometimes we don't -- if we don't, the value returned is a negative)
|
||||
if(bit.band(object_type['NumInstances'], 0x80000000) == 0) then
|
||||
-- Parse the object instances and counters
|
||||
for j = 1, object_type['NumInstances'], 1 do
|
||||
local instance_start = pos
|
||||
|
||||
-- Instance definition
|
||||
local status
|
||||
status, pos, object_instances[j] = parse_perf_instance_definition(queryvalue_result['value'], pos)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, pos
|
||||
end
|
||||
-- Instance definition
|
||||
local status
|
||||
status, pos, object_instances[j] = parse_perf_instance_definition(queryvalue_result['value'], pos)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, pos
|
||||
end
|
||||
|
||||
-- Set up the instance array
|
||||
local instance_name = object_instances[j]['InstanceName']
|
||||
result[object_name][instance_name] = {}
|
||||
-- Set up the instance array
|
||||
local instance_name = object_instances[j]['InstanceName']
|
||||
result[object_name][instance_name] = {}
|
||||
|
||||
-- Bring the pos to the start of the counter block
|
||||
pos = instance_start + object_instances[j]['ByteLength']
|
||||
-- Bring the pos to the start of the counter block
|
||||
pos = instance_start + object_instances[j]['ByteLength']
|
||||
|
||||
--stdnse.print_debug("\n INSTANCE: %s\n", instance_name)
|
||||
--stdnse.print_debug(" Length: %d\n", object_instances[j]['ByteLength'])
|
||||
--stdnse.print_debug(" NameOffset: %d\n", object_instances[j]['NameOffset'])
|
||||
--stdnse.print_debug(" NameLength: %d\n", object_instances[j]['NameLength'])
|
||||
--stdnse.print_debug(" --------------\n")
|
||||
--stdnse.print_debug("\n INSTANCE: %s\n", instance_name)
|
||||
--stdnse.print_debug(" Length: %d\n", object_instances[j]['ByteLength'])
|
||||
--stdnse.print_debug(" NameOffset: %d\n", object_instances[j]['NameOffset'])
|
||||
--stdnse.print_debug(" NameLength: %d\n", object_instances[j]['NameLength'])
|
||||
--stdnse.print_debug(" --------------\n")
|
||||
|
||||
-- The counter block
|
||||
local status, counter_block
|
||||
status, pos, counter_block = parse_perf_counter_block(queryvalue_result['value'], pos)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, pos
|
||||
end
|
||||
-- The counter block
|
||||
local status, counter_block
|
||||
status, pos, counter_block = parse_perf_counter_block(queryvalue_result['value'], pos)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, pos
|
||||
end
|
||||
|
||||
for k = 1, object_type['NumCounters'], 1 do
|
||||
-- Each individual counter
|
||||
local status, counter_result
|
||||
status, pos, counter_result = parse_perf_counter(queryvalue_result['value'], pos, counter_definitions[k])
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, pos
|
||||
end
|
||||
for k = 1, object_type['NumCounters'], 1 do
|
||||
-- Each individual counter
|
||||
local status, counter_result
|
||||
status, pos, counter_result = parse_perf_counter(queryvalue_result['value'], pos, counter_definitions[k])
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, pos
|
||||
end
|
||||
|
||||
local counter_name = result['title_database'][counter_definitions[k]['CounterNameTitleIndex']]
|
||||
--stdnse.print_debug(" %s: %s\n", counter_name, counter_result)
|
||||
local counter_name = result['title_database'][counter_definitions[k]['CounterNameTitleIndex']]
|
||||
--stdnse.print_debug(" %s: %s\n", counter_name, counter_result)
|
||||
|
||||
-- Save it in the result
|
||||
result[object_name][instance_name][counter_name] = counter_result
|
||||
end
|
||||
-- Save it in the result
|
||||
result[object_name][instance_name][counter_name] = counter_result
|
||||
end
|
||||
|
||||
-- Bring the pos to the end of the next section
|
||||
pos = instance_start + object_instances[j]['ByteLength'] + counter_block['ByteLength']
|
||||
end
|
||||
else
|
||||
for k = 1, object_type['NumCounters'], 1 do
|
||||
-- Each individual counter
|
||||
local status, counter_result
|
||||
status, pos, counter_result = parse_perf_counter(queryvalue_result['value'], pos, counter_definitions[k])
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, pos
|
||||
end
|
||||
-- Bring the pos to the end of the next section
|
||||
pos = instance_start + object_instances[j]['ByteLength'] + counter_block['ByteLength']
|
||||
end
|
||||
else
|
||||
for k = 1, object_type['NumCounters'], 1 do
|
||||
-- Each individual counter
|
||||
local status, counter_result
|
||||
status, pos, counter_result = parse_perf_counter(queryvalue_result['value'], pos, counter_definitions[k])
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, pos
|
||||
end
|
||||
|
||||
local counter_name = result['title_database'][counter_definitions[k]['CounterNameTitleIndex']]
|
||||
--stdnse.print_debug(" %s: %s\n", counter_name, counter_result)
|
||||
local counter_name = result['title_database'][counter_definitions[k]['CounterNameTitleIndex']]
|
||||
--stdnse.print_debug(" %s: %s\n", counter_name, counter_result)
|
||||
|
||||
-- Save it in the result
|
||||
result[object_name][counter_name] = counter_result
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Save it in the result
|
||||
result[object_name][counter_name] = counter_result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Blank out the database
|
||||
result['title_database'] = nil
|
||||
end
|
||||
-- Blank out the database
|
||||
result['title_database'] = nil
|
||||
end
|
||||
|
||||
msrpc.stop_smb(smbstate)
|
||||
msrpc.stop_smb(smbstate)
|
||||
|
||||
return true, result
|
||||
return true, result
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
5152
nselib/mssql.lua
5152
nselib/mssql.lua
File diff suppressed because it is too large
Load diff
606
nselib/mysql.lua
606
nselib/mysql.lua
|
|
@ -29,52 +29,52 @@ local HAVE_SSL, openssl = pcall(require,'openssl')
|
|||
|
||||
Capabilities =
|
||||
{
|
||||
LongPassword = 0x1,
|
||||
FoundRows = 0x2,
|
||||
LongColumnFlag = 0x4,
|
||||
ConnectWithDatabase = 0x8,
|
||||
DontAllowDatabaseTableColumn = 0x10,
|
||||
SupportsCompression = 0x20,
|
||||
ODBCClient = 0x40,
|
||||
SupportsLoadDataLocal = 0x80,
|
||||
IgnoreSpaceBeforeParenthesis = 0x100,
|
||||
Speaks41ProtocolNew = 0x200,
|
||||
InteractiveClient = 0x400,
|
||||
SwitchToSSLAfterHandshake = 0x800,
|
||||
IgnoreSigpipes = 0x1000,
|
||||
SupportsTransactions = 0x2000,
|
||||
Speaks41ProtocolOld = 0x4000,
|
||||
Support41Auth = 0x8000
|
||||
LongPassword = 0x1,
|
||||
FoundRows = 0x2,
|
||||
LongColumnFlag = 0x4,
|
||||
ConnectWithDatabase = 0x8,
|
||||
DontAllowDatabaseTableColumn = 0x10,
|
||||
SupportsCompression = 0x20,
|
||||
ODBCClient = 0x40,
|
||||
SupportsLoadDataLocal = 0x80,
|
||||
IgnoreSpaceBeforeParenthesis = 0x100,
|
||||
Speaks41ProtocolNew = 0x200,
|
||||
InteractiveClient = 0x400,
|
||||
SwitchToSSLAfterHandshake = 0x800,
|
||||
IgnoreSigpipes = 0x1000,
|
||||
SupportsTransactions = 0x2000,
|
||||
Speaks41ProtocolOld = 0x4000,
|
||||
Support41Auth = 0x8000
|
||||
}
|
||||
|
||||
ExtCapabilities =
|
||||
{
|
||||
SupportsMultipleStatments = 0x1,
|
||||
SupportsMultipleResults = 0x2
|
||||
SupportsMultipleStatments = 0x1,
|
||||
SupportsMultipleResults = 0x2
|
||||
}
|
||||
|
||||
Charset =
|
||||
{
|
||||
latin1_COLLATE_latin1_swedish_ci = 0x8
|
||||
latin1_COLLATE_latin1_swedish_ci = 0x8
|
||||
}
|
||||
|
||||
ServerStatus =
|
||||
{
|
||||
InTransaction = 0x1,
|
||||
AutoCommit = 0x2,
|
||||
MoreResults = 0x4,
|
||||
MultiQuery = 0x8,
|
||||
BadIndexUsed = 0x10,
|
||||
NoIndexUsed = 0x20,
|
||||
CursorExists = 0x40,
|
||||
LastRowSebd = 0x80,
|
||||
DatabaseDropped = 0x100,
|
||||
NoBackslashEscapes = 0x200
|
||||
InTransaction = 0x1,
|
||||
AutoCommit = 0x2,
|
||||
MoreResults = 0x4,
|
||||
MultiQuery = 0x8,
|
||||
BadIndexUsed = 0x10,
|
||||
NoIndexUsed = 0x20,
|
||||
CursorExists = 0x40,
|
||||
LastRowSebd = 0x80,
|
||||
DatabaseDropped = 0x100,
|
||||
NoBackslashEscapes = 0x200
|
||||
}
|
||||
|
||||
Command =
|
||||
{
|
||||
Query = 3
|
||||
Query = 3
|
||||
}
|
||||
|
||||
local MAXPACKET = 16777216
|
||||
|
|
@ -87,14 +87,14 @@ local HEADER_SIZE = 4
|
|||
-- @return response table containing the fields <code>len</code> and <code>packetno</code>
|
||||
local function decodeHeader( data, pos )
|
||||
|
||||
local response = {}
|
||||
local pos, tmp = pos or 1, 0
|
||||
local response = {}
|
||||
local pos, tmp = pos or 1, 0
|
||||
|
||||
pos, tmp = bin.unpack( "I", data, pos )
|
||||
response.len = bit.band( tmp,255 )
|
||||
response.number = bit.rshift( tmp, 24 )
|
||||
pos, tmp = bin.unpack( "I", data, pos )
|
||||
response.len = bit.band( tmp,255 )
|
||||
response.number = bit.rshift( tmp, 24 )
|
||||
|
||||
return pos, response
|
||||
return pos, response
|
||||
end
|
||||
|
||||
--- Recieves the server greeting upon intial connection
|
||||
|
|
@ -106,43 +106,43 @@ end
|
|||
-- <code>status</code> or error message on failure (status == false)
|
||||
function receiveGreeting( socket )
|
||||
|
||||
local catch = function() socket:close() stdnse.print_debug("receiveGreeting(): failed") end
|
||||
local try = nmap.new_try(catch)
|
||||
local data = try( socket:receive_bytes(HEADER_SIZE) )
|
||||
local pos, response, tmp, _
|
||||
local catch = function() socket:close() stdnse.print_debug("receiveGreeting(): failed") end
|
||||
local try = nmap.new_try(catch)
|
||||
local data = try( socket:receive_bytes(HEADER_SIZE) )
|
||||
local pos, response, tmp, _
|
||||
|
||||
pos, response = decodeHeader( data, 1 )
|
||||
pos, response = decodeHeader( data, 1 )
|
||||
|
||||
-- do we need to read the remainder
|
||||
if ( #data - HEADER_SIZE < response.len ) then
|
||||
local tmp = try( socket:receive_bytes( response.len - #data + HEADER_SIZE ) )
|
||||
data = data .. tmp
|
||||
end
|
||||
-- do we need to read the remainder
|
||||
if ( #data - HEADER_SIZE < response.len ) then
|
||||
local tmp = try( socket:receive_bytes( response.len - #data + HEADER_SIZE ) )
|
||||
data = data .. tmp
|
||||
end
|
||||
|
||||
local is_error
|
||||
pos, is_error = bin.unpack( "C", data, pos )
|
||||
local is_error
|
||||
pos, is_error = bin.unpack( "C", data, pos )
|
||||
|
||||
if ( is_error == 0xff ) then
|
||||
pos, response.errorcode = bin.unpack( "S", data, pos )
|
||||
pos, response.errormsg = bin.unpack("A" .. (#data - pos + 1), data, pos )
|
||||
if ( is_error == 0xff ) then
|
||||
pos, response.errorcode = bin.unpack( "S", data, pos )
|
||||
pos, response.errormsg = bin.unpack("A" .. (#data - pos + 1), data, pos )
|
||||
|
||||
return false, response.errormsg
|
||||
end
|
||||
return false, response.errormsg
|
||||
end
|
||||
|
||||
pos, response.proto = bin.unpack( "C", data, pos )
|
||||
pos, response.version = bin.unpack( "z", data, pos )
|
||||
pos, response.threadid = bin.unpack( "I", data, pos )
|
||||
pos, response.salt, _ = bin.unpack( "A8C", data, pos )
|
||||
pos, response.capabilities = bin.unpack( "S", data, pos )
|
||||
pos, response.charset = bin.unpack( "C", data, pos )
|
||||
pos, response.status = bin.unpack( "S", data, pos )
|
||||
pos, _ = bin.unpack( "A13", data, pos )
|
||||
pos, tmp = bin.unpack( "A12", data, pos )
|
||||
pos, response.proto = bin.unpack( "C", data, pos )
|
||||
pos, response.version = bin.unpack( "z", data, pos )
|
||||
pos, response.threadid = bin.unpack( "I", data, pos )
|
||||
pos, response.salt, _ = bin.unpack( "A8C", data, pos )
|
||||
pos, response.capabilities = bin.unpack( "S", data, pos )
|
||||
pos, response.charset = bin.unpack( "C", data, pos )
|
||||
pos, response.status = bin.unpack( "S", data, pos )
|
||||
pos, _ = bin.unpack( "A13", data, pos )
|
||||
pos, tmp = bin.unpack( "A12", data, pos )
|
||||
|
||||
response.salt = response.salt .. tmp
|
||||
response.errorcode = 0
|
||||
response.salt = response.salt .. tmp
|
||||
response.errorcode = 0
|
||||
|
||||
return true, response
|
||||
return true, response
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -153,28 +153,28 @@ end
|
|||
-- @param salt string containing the servers salt as obtained from <code>receiveGreeting</code>
|
||||
-- @return reply string containing the raw hashed value
|
||||
local function createLoginHash(pass, salt)
|
||||
local hash_stage1
|
||||
local hash_stage2
|
||||
local hash_stage3
|
||||
local reply = ""
|
||||
local pos, b1, b2, b3, _ = 1, 0, 0, 0
|
||||
local hash_stage1
|
||||
local hash_stage2
|
||||
local hash_stage3
|
||||
local reply = ""
|
||||
local pos, b1, b2, b3, _ = 1, 0, 0, 0
|
||||
|
||||
if ( not(HAVE_SSL) ) then
|
||||
return nil
|
||||
end
|
||||
if ( not(HAVE_SSL) ) then
|
||||
return nil
|
||||
end
|
||||
|
||||
hash_stage1 = openssl.sha1( pass )
|
||||
hash_stage2 = openssl.sha1( hash_stage1 )
|
||||
hash_stage3 = openssl.sha1( salt .. hash_stage2 )
|
||||
hash_stage1 = openssl.sha1( pass )
|
||||
hash_stage2 = openssl.sha1( hash_stage1 )
|
||||
hash_stage3 = openssl.sha1( salt .. hash_stage2 )
|
||||
|
||||
for pos=1, hash_stage1:len() do
|
||||
_, b1 = bin.unpack( "C", hash_stage1, pos )
|
||||
_, b2 = bin.unpack( "C", hash_stage3, pos )
|
||||
for pos=1, hash_stage1:len() do
|
||||
_, b1 = bin.unpack( "C", hash_stage1, pos )
|
||||
_, b2 = bin.unpack( "C", hash_stage3, pos )
|
||||
|
||||
reply = reply .. string.char( bit.bxor( b2, b1 ) )
|
||||
end
|
||||
reply = reply .. string.char( bit.bxor( b2, b1 ) )
|
||||
end
|
||||
|
||||
return reply
|
||||
return reply
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -183,9 +183,9 @@ end
|
|||
--
|
||||
-- @param socket already connected to the remote server
|
||||
-- @param params table with additional options to the loginrequest
|
||||
-- current supported fields are <code>charset</code> and <code>authversion</code>
|
||||
-- authversion is either "pre41" or "post41" (default is post41)
|
||||
-- currently only post41 authentication is supported
|
||||
-- current supported fields are <code>charset</code> and <code>authversion</code>
|
||||
-- authversion is either "pre41" or "post41" (default is post41)
|
||||
-- currently only post41 authentication is supported
|
||||
-- @param username string containing the username of the user that is authenticating
|
||||
-- @param password string containing the users password or nil if empty
|
||||
-- @param salt string containing the servers salt as recieved from <code>receiveGreeting</code>
|
||||
|
|
@ -193,84 +193,84 @@ end
|
|||
-- @return response table or error message on failure
|
||||
function loginRequest( socket, params, username, password, salt )
|
||||
|
||||
local catch = function() socket:close() stdnse.print_debug("loginRequest(): failed") end
|
||||
local try = nmap.new_try(catch)
|
||||
local packetno = 1
|
||||
local authversion = params.authversion or "post41"
|
||||
local username = username or ""
|
||||
local catch = function() socket:close() stdnse.print_debug("loginRequest(): failed") end
|
||||
local try = nmap.new_try(catch)
|
||||
local packetno = 1
|
||||
local authversion = params.authversion or "post41"
|
||||
local username = username or ""
|
||||
|
||||
if not(HAVE_SSL) then
|
||||
return false, "No OpenSSL"
|
||||
end
|
||||
if not(HAVE_SSL) then
|
||||
return false, "No OpenSSL"
|
||||
end
|
||||
|
||||
if authversion ~= "post41" then
|
||||
return false, "Unsupported authentication version: " .. authversion
|
||||
end
|
||||
if authversion ~= "post41" then
|
||||
return false, "Unsupported authentication version: " .. authversion
|
||||
end
|
||||
|
||||
local clicap = Capabilities.LongPassword
|
||||
clicap = clicap + Capabilities.LongColumnFlag
|
||||
clicap = clicap + Capabilities.SupportsLoadDataLocal
|
||||
clicap = clicap + Capabilities.Speaks41ProtocolNew
|
||||
clicap = clicap + Capabilities.InteractiveClient
|
||||
clicap = clicap + Capabilities.SupportsTransactions
|
||||
clicap = clicap + Capabilities.Support41Auth
|
||||
local clicap = Capabilities.LongPassword
|
||||
clicap = clicap + Capabilities.LongColumnFlag
|
||||
clicap = clicap + Capabilities.SupportsLoadDataLocal
|
||||
clicap = clicap + Capabilities.Speaks41ProtocolNew
|
||||
clicap = clicap + Capabilities.InteractiveClient
|
||||
clicap = clicap + Capabilities.SupportsTransactions
|
||||
clicap = clicap + Capabilities.Support41Auth
|
||||
|
||||
local extcapabilities = ExtCapabilities.SupportsMultipleStatments
|
||||
extcapabilities = extcapabilities + ExtCapabilities.SupportsMultipleResults
|
||||
local extcapabilities = ExtCapabilities.SupportsMultipleStatments
|
||||
extcapabilities = extcapabilities + ExtCapabilities.SupportsMultipleResults
|
||||
|
||||
local packet = bin.pack( "S", clicap )
|
||||
packet = packet .. bin.pack( "S", extcapabilities )
|
||||
packet = packet .. bin.pack( "I", MAXPACKET )
|
||||
packet = packet .. bin.pack( "C", Charset.latin1_COLLATE_latin1_swedish_ci )
|
||||
packet = packet .. bin.pack( "A", string.char(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) )
|
||||
packet = packet .. bin.pack( "z", username )
|
||||
local packet = bin.pack( "S", clicap )
|
||||
packet = packet .. bin.pack( "S", extcapabilities )
|
||||
packet = packet .. bin.pack( "I", MAXPACKET )
|
||||
packet = packet .. bin.pack( "C", Charset.latin1_COLLATE_latin1_swedish_ci )
|
||||
packet = packet .. bin.pack( "A", string.char(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) )
|
||||
packet = packet .. bin.pack( "z", username )
|
||||
|
||||
if ( password ~= nil and password:len() > 0 ) then
|
||||
local hash = createLoginHash( password, salt )
|
||||
packet = packet .. bin.pack( "A", string.char( 0x14 ) .. hash )
|
||||
else
|
||||
packet = packet .. bin.pack( "C", 0 )
|
||||
end
|
||||
if ( password ~= nil and password:len() > 0 ) then
|
||||
local hash = createLoginHash( password, salt )
|
||||
packet = packet .. bin.pack( "A", string.char( 0x14 ) .. hash )
|
||||
else
|
||||
packet = packet .. bin.pack( "C", 0 )
|
||||
end
|
||||
|
||||
local tmp = packet:len() + bit.lshift( packetno, 24 )
|
||||
local tmp = packet:len() + bit.lshift( packetno, 24 )
|
||||
|
||||
packet = bin.pack( "I", tmp ) .. packet
|
||||
packet = bin.pack( "I", tmp ) .. packet
|
||||
|
||||
try( socket:send(packet) )
|
||||
packet = try( socket:receive_bytes(HEADER_SIZE) )
|
||||
local pos, response = decodeHeader( packet )
|
||||
try( socket:send(packet) )
|
||||
packet = try( socket:receive_bytes(HEADER_SIZE) )
|
||||
local pos, response = decodeHeader( packet )
|
||||
|
||||
-- do we need to read the remainder
|
||||
if ( #packet - HEADER_SIZE < response.len ) then
|
||||
local tmp = try( socket:receive_bytes( response.len - #packet + HEADER_SIZE ) )
|
||||
packet = packet .. tmp
|
||||
end
|
||||
-- do we need to read the remainder
|
||||
if ( #packet - HEADER_SIZE < response.len ) then
|
||||
local tmp = try( socket:receive_bytes( response.len - #packet + HEADER_SIZE ) )
|
||||
packet = packet .. tmp
|
||||
end
|
||||
|
||||
local is_error
|
||||
local is_error
|
||||
|
||||
pos, is_error = bin.unpack( "C", packet, pos )
|
||||
pos, is_error = bin.unpack( "C", packet, pos )
|
||||
|
||||
if is_error > 0 then
|
||||
pos, response.errorcode = bin.unpack( "S", packet, pos )
|
||||
if is_error > 0 then
|
||||
pos, response.errorcode = bin.unpack( "S", packet, pos )
|
||||
|
||||
local has_sqlstate
|
||||
pos, has_sqlstate = bin.unpack( "C", packet, pos )
|
||||
local has_sqlstate
|
||||
pos, has_sqlstate = bin.unpack( "C", packet, pos )
|
||||
|
||||
if has_sqlstate == 35 then
|
||||
pos, response.sqlstate = bin.unpack( "A5", packet, pos )
|
||||
end
|
||||
if has_sqlstate == 35 then
|
||||
pos, response.sqlstate = bin.unpack( "A5", packet, pos )
|
||||
end
|
||||
|
||||
pos, response.errormessage = bin.unpack( "z", packet, pos )
|
||||
pos, response.errormessage = bin.unpack( "z", packet, pos )
|
||||
|
||||
return false, response.errormessage
|
||||
else
|
||||
response.errorcode = 0
|
||||
pos, response.affectedrows = bin.unpack( "C", packet, pos )
|
||||
pos, response.serverstatus = bin.unpack( "S", packet, pos )
|
||||
pos, response.warnings = bin.unpack( "S", packet, pos )
|
||||
end
|
||||
return false, response.errormessage
|
||||
else
|
||||
response.errorcode = 0
|
||||
pos, response.affectedrows = bin.unpack( "C", packet, pos )
|
||||
pos, response.serverstatus = bin.unpack( "S", packet, pos )
|
||||
pos, response.warnings = bin.unpack( "S", packet, pos )
|
||||
end
|
||||
|
||||
return true, response
|
||||
return true, response
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -283,42 +283,42 @@ end
|
|||
-- the position should point to the data in this buffer (ie. after the header)
|
||||
-- @return pos number containing the position after the field was decoded
|
||||
-- @return field table containing <code>catalog</code>, <code>database</code>, <code>table</code>,
|
||||
-- <code>origt_table</code>, <code>name</code>, <code>orig_name</code>,
|
||||
-- <code>length</code> and <code>type</code>
|
||||
-- <code>origt_table</code>, <code>name</code>, <code>orig_name</code>,
|
||||
-- <code>length</code> and <code>type</code>
|
||||
function decodeField( data, pos )
|
||||
|
||||
local header, len
|
||||
local def, _
|
||||
local field = {}
|
||||
local header, len
|
||||
local def, _
|
||||
local field = {}
|
||||
|
||||
pos, len = bin.unpack( "C", data, pos )
|
||||
pos, field.catalog = bin.unpack( "A" .. len, data, pos )
|
||||
pos, len = bin.unpack( "C", data, pos )
|
||||
pos, field.catalog = bin.unpack( "A" .. len, data, pos )
|
||||
|
||||
pos, len = bin.unpack( "C", data, pos )
|
||||
pos, field.database = bin.unpack( "A" .. len, data, pos )
|
||||
pos, len = bin.unpack( "C", data, pos )
|
||||
pos, field.database = bin.unpack( "A" .. len, data, pos )
|
||||
|
||||
pos, len = bin.unpack( "C", data, pos )
|
||||
pos, field.table = bin.unpack( "A" .. len, data, pos )
|
||||
pos, len = bin.unpack( "C", data, pos )
|
||||
pos, field.table = bin.unpack( "A" .. len, data, pos )
|
||||
|
||||
pos, len = bin.unpack( "C", data, pos )
|
||||
pos, field.orig_table = bin.unpack( "A" .. len, data, pos )
|
||||
pos, len = bin.unpack( "C", data, pos )
|
||||
pos, field.orig_table = bin.unpack( "A" .. len, data, pos )
|
||||
|
||||
pos, len = bin.unpack( "C", data, pos )
|
||||
pos, field.name = bin.unpack( "A" .. len, data, pos )
|
||||
pos, len = bin.unpack( "C", data, pos )
|
||||
pos, field.name = bin.unpack( "A" .. len, data, pos )
|
||||
|
||||
pos, len = bin.unpack( "C", data, pos )
|
||||
pos, field.orig_name = bin.unpack( "A" .. len, data, pos )
|
||||
pos, len = bin.unpack( "C", data, pos )
|
||||
pos, field.orig_name = bin.unpack( "A" .. len, data, pos )
|
||||
|
||||
-- should be 0x0C
|
||||
pos, _ = bin.unpack( "C", data, pos )
|
||||
-- should be 0x0C
|
||||
pos, _ = bin.unpack( "C", data, pos )
|
||||
|
||||
-- charset, in my case 0x0800
|
||||
pos, _ = bin.unpack( "S", data, pos )
|
||||
-- charset, in my case 0x0800
|
||||
pos, _ = bin.unpack( "S", data, pos )
|
||||
|
||||
pos, field.length = bin.unpack( "I", data, pos )
|
||||
pos, field.type = bin.unpack( "A6", data, pos )
|
||||
pos, field.length = bin.unpack( "I", data, pos )
|
||||
pos, field.type = bin.unpack( "A6", data, pos )
|
||||
|
||||
return pos, field
|
||||
return pos, field
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -330,81 +330,81 @@ end
|
|||
-- @return table containing the following <code>header</code>, <code>fields</code> and <code>data</code>
|
||||
function decodeQueryResponse( socket )
|
||||
|
||||
local catch = function() socket:close() stdnse.print_debug("decodeQueryResponse(): failed") end
|
||||
local try = nmap.new_try(catch)
|
||||
local data, header, pos
|
||||
local rs, blocks = {}, {}
|
||||
local block_start, block_end
|
||||
local EOF_MARKER = 254
|
||||
local catch = function() socket:close() stdnse.print_debug("decodeQueryResponse(): failed") end
|
||||
local try = nmap.new_try(catch)
|
||||
local data, header, pos
|
||||
local rs, blocks = {}, {}
|
||||
local block_start, block_end
|
||||
local EOF_MARKER = 254
|
||||
|
||||
data = try( socket:receive_bytes(HEADER_SIZE) )
|
||||
pos, header = decodeHeader( data, pos )
|
||||
data = try( socket:receive_bytes(HEADER_SIZE) )
|
||||
pos, header = decodeHeader( data, pos )
|
||||
|
||||
--
|
||||
-- First, Let's attempt to read the "Result Set Header Packet"
|
||||
--
|
||||
if data:len() < header.len then
|
||||
data = data .. try( socket:receive_bytes( header.len - #data + HEADER_SIZE ) )
|
||||
end
|
||||
--
|
||||
-- First, Let's attempt to read the "Result Set Header Packet"
|
||||
--
|
||||
if data:len() < header.len then
|
||||
data = data .. try( socket:receive_bytes( header.len - #data + HEADER_SIZE ) )
|
||||
end
|
||||
|
||||
rs.header = data:sub( 1, HEADER_SIZE + header.len )
|
||||
rs.header = data:sub( 1, HEADER_SIZE + header.len )
|
||||
|
||||
-- abort on MySQL error
|
||||
if rs.header:sub(HEADER_SIZE + 1, HEADER_SIZE + 1) == string.char(0xFF) then
|
||||
-- is this a 4.0 or 4.1 error message
|
||||
if rs.header:find("#") then
|
||||
return false, rs.header:sub(HEADER_SIZE+10)
|
||||
else
|
||||
return false, rs.header:sub(HEADER_SIZE+4)
|
||||
end
|
||||
end
|
||||
-- abort on MySQL error
|
||||
if rs.header:sub(HEADER_SIZE + 1, HEADER_SIZE + 1) == string.char(0xFF) then
|
||||
-- is this a 4.0 or 4.1 error message
|
||||
if rs.header:find("#") then
|
||||
return false, rs.header:sub(HEADER_SIZE+10)
|
||||
else
|
||||
return false, rs.header:sub(HEADER_SIZE+4)
|
||||
end
|
||||
end
|
||||
|
||||
pos = HEADER_SIZE + header.len + 1
|
||||
pos = HEADER_SIZE + header.len + 1
|
||||
|
||||
-- Second, Let's attempt to read the "Field Packets" and "Row Data Packets"
|
||||
-- They're separated by an "EOF Packet"
|
||||
for i=1,2 do
|
||||
-- Second, Let's attempt to read the "Field Packets" and "Row Data Packets"
|
||||
-- They're separated by an "EOF Packet"
|
||||
for i=1,2 do
|
||||
|
||||
-- marks the start of our block
|
||||
block_start = pos
|
||||
-- marks the start of our block
|
||||
block_start = pos
|
||||
|
||||
while true do
|
||||
while true do
|
||||
|
||||
if data:len() - pos < HEADER_SIZE then
|
||||
data = data .. try( socket:receive_bytes( HEADER_SIZE - ( data:len() - pos ) ) )
|
||||
end
|
||||
if data:len() - pos < HEADER_SIZE then
|
||||
data = data .. try( socket:receive_bytes( HEADER_SIZE - ( data:len() - pos ) ) )
|
||||
end
|
||||
|
||||
pos, header = decodeHeader( data, pos )
|
||||
pos, header = decodeHeader( data, pos )
|
||||
|
||||
if data:len() - pos < header.len - 1 then
|
||||
data = data .. try( socket:receive_bytes( header.len - ( data:len() - pos ) ) )
|
||||
end
|
||||
if data:len() - pos < header.len - 1 then
|
||||
data = data .. try( socket:receive_bytes( header.len - ( data:len() - pos ) ) )
|
||||
end
|
||||
|
||||
if header.len > 0 then
|
||||
local _, b = bin.unpack("C", data, pos )
|
||||
if header.len > 0 then
|
||||
local _, b = bin.unpack("C", data, pos )
|
||||
|
||||
-- Is this the EOF packet?
|
||||
if b == EOF_MARKER then
|
||||
-- we don't want the EOF Packet included
|
||||
block_end = pos - HEADER_SIZE
|
||||
pos = pos + header.len
|
||||
break
|
||||
end
|
||||
end
|
||||
-- Is this the EOF packet?
|
||||
if b == EOF_MARKER then
|
||||
-- we don't want the EOF Packet included
|
||||
block_end = pos - HEADER_SIZE
|
||||
pos = pos + header.len
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
pos = pos + header.len
|
||||
pos = pos + header.len
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
blocks[i] = data:sub( block_start, block_end )
|
||||
blocks[i] = data:sub( block_start, block_end )
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
rs.fields = blocks[1]
|
||||
rs.data = blocks[2]
|
||||
rs.fields = blocks[1]
|
||||
rs.data = blocks[2]
|
||||
|
||||
return true, rs
|
||||
return true, rs
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -419,20 +419,20 @@ end
|
|||
-- or string containing error message if status is false
|
||||
function decodeFieldPackets( data, count )
|
||||
|
||||
local pos, header
|
||||
local field, fields = {}, {}
|
||||
local pos, header
|
||||
local field, fields = {}, {}
|
||||
|
||||
if count < 1 then
|
||||
return false, "Field count was less than one, aborting"
|
||||
end
|
||||
if count < 1 then
|
||||
return false, "Field count was less than one, aborting"
|
||||
end
|
||||
|
||||
for i=1, count do
|
||||
pos, header = decodeHeader( data, pos )
|
||||
pos, field = decodeField( data, pos )
|
||||
table.insert( fields, field )
|
||||
end
|
||||
for i=1, count do
|
||||
pos, header = decodeHeader( data, pos )
|
||||
pos, field = decodeField( data, pos )
|
||||
table.insert( fields, field )
|
||||
end
|
||||
|
||||
return true, fields
|
||||
return true, fields
|
||||
end
|
||||
|
||||
-- Decodes the result set header
|
||||
|
|
@ -443,15 +443,15 @@ end
|
|||
-- @return number containing the amount of fields
|
||||
function decodeResultSetHeader( data )
|
||||
|
||||
local _, fields
|
||||
local _, fields
|
||||
|
||||
if data:len() ~= HEADER_SIZE + 1 then
|
||||
return false, "Result set header was incorrect"
|
||||
end
|
||||
if data:len() ~= HEADER_SIZE + 1 then
|
||||
return false, "Result set header was incorrect"
|
||||
end
|
||||
|
||||
_, fields = bin.unpack( "C", data, HEADER_SIZE + 1 )
|
||||
_, fields = bin.unpack( "C", data, HEADER_SIZE + 1 )
|
||||
|
||||
return true, fields
|
||||
return true, fields
|
||||
end
|
||||
|
||||
--- Decodes the row data
|
||||
|
|
@ -464,23 +464,23 @@ end
|
|||
-- @return rows table containing row tables
|
||||
function decodeDataPackets( data, count )
|
||||
|
||||
local len, pos = 0, 1, 1
|
||||
local header, row, rows = {}, {}, {}
|
||||
local len, pos = 0, 1, 1
|
||||
local header, row, rows = {}, {}, {}
|
||||
|
||||
while pos < data:len() do
|
||||
row = {}
|
||||
pos, header = decodeHeader( data, pos )
|
||||
while pos < data:len() do
|
||||
row = {}
|
||||
pos, header = decodeHeader( data, pos )
|
||||
|
||||
for i=1, count do
|
||||
pos, len = bin.unpack("C", data, pos )
|
||||
pos, row[i] = bin.unpack("A" .. len, data, pos)
|
||||
end
|
||||
for i=1, count do
|
||||
pos, len = bin.unpack("C", data, pos )
|
||||
pos, row[i] = bin.unpack("A" .. len, data, pos)
|
||||
end
|
||||
|
||||
table.insert( rows, row )
|
||||
table.insert( rows, row )
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return true, rows
|
||||
return true, rows
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -492,54 +492,54 @@ end
|
|||
-- @return rows table containing row tabels as decoded by <code>decodeDataPackets</code>
|
||||
function sqlQuery( socket, query )
|
||||
|
||||
local catch = function() socket:close() stdnse.print_debug("sqlQuery(): failed") end
|
||||
local try = nmap.new_try(catch)
|
||||
local packetno = 0
|
||||
local querylen = query:len() + 1
|
||||
local packet, packet_len, pos, header
|
||||
local status, fields, field_count, rows, rs
|
||||
local catch = function() socket:close() stdnse.print_debug("sqlQuery(): failed") end
|
||||
local try = nmap.new_try(catch)
|
||||
local packetno = 0
|
||||
local querylen = query:len() + 1
|
||||
local packet, packet_len, pos, header
|
||||
local status, fields, field_count, rows, rs
|
||||
|
||||
packet = bin.pack("ICA", querylen, Command.Query, query )
|
||||
packet = bin.pack("ICA", querylen, Command.Query, query )
|
||||
|
||||
--
|
||||
-- http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Result_Set_Header_Packet
|
||||
--
|
||||
-- (Result Set Header Packet) the number of columns
|
||||
-- (Field Packets) column descriptors
|
||||
-- (EOF Packet) marker: end of Field Packets
|
||||
-- (Row Data Packets) row contents
|
||||
-- (EOF Packet) marker: end of Data Packets
|
||||
--
|
||||
-- http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Result_Set_Header_Packet
|
||||
--
|
||||
-- (Result Set Header Packet) the number of columns
|
||||
-- (Field Packets) column descriptors
|
||||
-- (EOF Packet) marker: end of Field Packets
|
||||
-- (Row Data Packets) row contents
|
||||
-- (EOF Packet) marker: end of Data Packets
|
||||
|
||||
try( socket:send(packet) )
|
||||
try( socket:send(packet) )
|
||||
|
||||
--
|
||||
-- Let's read all the data into a table
|
||||
-- This way we avoid the hustle with reading from the socket
|
||||
status, rs = decodeQueryResponse( socket )
|
||||
--
|
||||
-- Let's read all the data into a table
|
||||
-- This way we avoid the hustle with reading from the socket
|
||||
status, rs = decodeQueryResponse( socket )
|
||||
|
||||
if not status then
|
||||
return false, rs
|
||||
end
|
||||
if not status then
|
||||
return false, rs
|
||||
end
|
||||
|
||||
status, field_count = decodeResultSetHeader(rs.header)
|
||||
status, field_count = decodeResultSetHeader(rs.header)
|
||||
|
||||
if not status then
|
||||
return false, field_count
|
||||
end
|
||||
if not status then
|
||||
return false, field_count
|
||||
end
|
||||
|
||||
status, fields = decodeFieldPackets(rs.fields, field_count)
|
||||
status, fields = decodeFieldPackets(rs.fields, field_count)
|
||||
|
||||
if not status then
|
||||
return false, fields
|
||||
end
|
||||
if not status then
|
||||
return false, fields
|
||||
end
|
||||
|
||||
status, rows = decodeDataPackets(rs.data, field_count)
|
||||
status, rows = decodeDataPackets(rs.data, field_count)
|
||||
|
||||
if not status then
|
||||
return false, rows
|
||||
end
|
||||
if not status then
|
||||
return false, rows
|
||||
end
|
||||
|
||||
return true, { cols = fields, rows = rows }
|
||||
return true, { cols = fields, rows = rows }
|
||||
end
|
||||
|
||||
---
|
||||
|
|
@ -550,24 +550,24 @@ end
|
|||
-- - <code>noheaders</code> - does not include column names in result
|
||||
-- @return string containing the formated resultset table
|
||||
function formatResultset(rs, options)
|
||||
options = options or {}
|
||||
if ( not(rs) or not(rs.cols) or not(rs.rows) ) then
|
||||
return
|
||||
end
|
||||
options = options or {}
|
||||
if ( not(rs) or not(rs.cols) or not(rs.rows) ) then
|
||||
return
|
||||
end
|
||||
|
||||
local restab = tab.new(#rs.cols)
|
||||
local colnames = {}
|
||||
local restab = tab.new(#rs.cols)
|
||||
local colnames = {}
|
||||
|
||||
if ( not(options.noheaders) ) then
|
||||
for _, col in ipairs(rs.cols) do table.insert(colnames, col.name) end
|
||||
tab.addrow(restab, table.unpack(colnames))
|
||||
end
|
||||
if ( not(options.noheaders) ) then
|
||||
for _, col in ipairs(rs.cols) do table.insert(colnames, col.name) end
|
||||
tab.addrow(restab, table.unpack(colnames))
|
||||
end
|
||||
|
||||
for _, row in ipairs(rs.rows) do
|
||||
tab.addrow(restab, table.unpack(row))
|
||||
end
|
||||
for _, row in ipairs(rs.rows) do
|
||||
tab.addrow(restab, table.unpack(row))
|
||||
end
|
||||
|
||||
return tab.dump(restab)
|
||||
return tab.dump(restab)
|
||||
end
|
||||
|
||||
return _ENV;
|
||||
|
|
|
|||
1884
nselib/ncp.lua
1884
nselib/ncp.lua
File diff suppressed because it is too large
Load diff
1388
nselib/packet.lua
1388
nselib/packet.lua
File diff suppressed because it is too large
Load diff
916
nselib/pgsql.lua
916
nselib/pgsql.lua
File diff suppressed because it is too large
Load diff
1638
nselib/pppoe.lua
1638
nselib/pppoe.lua
File diff suppressed because it is too large
Load diff
2170
nselib/rmi.lua
2170
nselib/rmi.lua
File diff suppressed because it is too large
Load diff
|
|
@ -254,30 +254,30 @@ Comm = {
|
|||
--
|
||||
-- @return status boolean true
|
||||
SetVersion = function(self, version)
|
||||
if self.checkprogver then
|
||||
if (RPC_version[self.program] and RPC_args[self.program] and
|
||||
nmap.registry.args and nmap.registry.args[RPC_args[self.program].ver]) then
|
||||
self.version = tonumber(nmap.registry.args[RPC_args[self.program].ver])
|
||||
elseif (not(self.version) and version) then
|
||||
self.version = version
|
||||
end
|
||||
else
|
||||
self.version = version
|
||||
end
|
||||
return true, nil
|
||||
if self.checkprogver then
|
||||
if (RPC_version[self.program] and RPC_args[self.program] and
|
||||
nmap.registry.args and nmap.registry.args[RPC_args[self.program].ver]) then
|
||||
self.version = tonumber(nmap.registry.args[RPC_args[self.program].ver])
|
||||
elseif (not(self.version) and version) then
|
||||
self.version = version
|
||||
end
|
||||
else
|
||||
self.version = version
|
||||
end
|
||||
return true, nil
|
||||
end,
|
||||
|
||||
--- Sets the verification of the specified program and version support
|
||||
-- before trying to connecting.
|
||||
-- @param check boolean to enable or disable checking of program and version support.
|
||||
SetCheckProgVer = function(self, check)
|
||||
self.checkprogver = check
|
||||
self.checkprogver = check
|
||||
end,
|
||||
|
||||
--- Sets the RPC program ID to use.
|
||||
-- @param progid number Program ID to set.
|
||||
SetProgID = function(self, progid)
|
||||
self.program_id = progid
|
||||
self.program_id = progid
|
||||
end,
|
||||
|
||||
--- Checks if data contains enough bytes to read the <code>needed</code> amount
|
||||
|
|
|
|||
1250
nselib/sip.lua
1250
nselib/sip.lua
File diff suppressed because it is too large
Load diff
5944
nselib/smb.lua
5944
nselib/smb.lua
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
128
nselib/smtp.lua
128
nselib/smtp.lua
|
|
@ -596,80 +596,80 @@ end
|
|||
-- error message on failures.
|
||||
|
||||
login = function(socket, username, password, mech)
|
||||
assert(mech == "LOGIN" or mech == "PLAIN" or mech == "CRAM-MD5"
|
||||
or mech == "DIGEST-MD5" or mech == "NTLM",
|
||||
("Unsupported authentication mechanism (%s)"):format(mech or "nil"))
|
||||
local status, response = query(socket, "AUTH", mech)
|
||||
if ( not(status) ) then
|
||||
return false, "ERROR: Failed to send AUTH to server"
|
||||
end
|
||||
assert(mech == "LOGIN" or mech == "PLAIN" or mech == "CRAM-MD5"
|
||||
or mech == "DIGEST-MD5" or mech == "NTLM",
|
||||
("Unsupported authentication mechanism (%s)"):format(mech or "nil"))
|
||||
local status, response = query(socket, "AUTH", mech)
|
||||
if ( not(status) ) then
|
||||
return false, "ERROR: Failed to send AUTH to server"
|
||||
end
|
||||
|
||||
if ( mech == "LOGIN" ) then
|
||||
local tmp = response:match("334 (.*)")
|
||||
if ( not(tmp) ) then
|
||||
return false, "ERROR: Failed to decode LOGIN response"
|
||||
end
|
||||
tmp = base64.dec(tmp):lower()
|
||||
if ( not(tmp:match("^username")) ) then
|
||||
return false, ("ERROR: Expected \"Username\", but received (%s)"):format(tmp)
|
||||
end
|
||||
status, response = query(socket, base64.enc(username))
|
||||
if ( not(status) ) then
|
||||
return false, "ERROR: Failed to read LOGIN response"
|
||||
end
|
||||
tmp = response:match("334 (.*)")
|
||||
if ( not(tmp) ) then
|
||||
return false, "ERROR: Failed to decode LOGIN response"
|
||||
end
|
||||
tmp = base64.dec(tmp):lower()
|
||||
if ( not(tmp:match("^password")) ) then
|
||||
return false, ("ERROR: Expected \"password\", but received (%s)"):format(tmp)
|
||||
end
|
||||
status, response = query(socket, base64.enc(password))
|
||||
if ( not(status) ) then
|
||||
return false, "ERROR: Failed to read LOGIN response"
|
||||
end
|
||||
if ( response:match("^235") ) then
|
||||
return true, "Login success"
|
||||
end
|
||||
return false, response
|
||||
end
|
||||
if ( mech == "LOGIN" ) then
|
||||
local tmp = response:match("334 (.*)")
|
||||
if ( not(tmp) ) then
|
||||
return false, "ERROR: Failed to decode LOGIN response"
|
||||
end
|
||||
tmp = base64.dec(tmp):lower()
|
||||
if ( not(tmp:match("^username")) ) then
|
||||
return false, ("ERROR: Expected \"Username\", but received (%s)"):format(tmp)
|
||||
end
|
||||
status, response = query(socket, base64.enc(username))
|
||||
if ( not(status) ) then
|
||||
return false, "ERROR: Failed to read LOGIN response"
|
||||
end
|
||||
tmp = response:match("334 (.*)")
|
||||
if ( not(tmp) ) then
|
||||
return false, "ERROR: Failed to decode LOGIN response"
|
||||
end
|
||||
tmp = base64.dec(tmp):lower()
|
||||
if ( not(tmp:match("^password")) ) then
|
||||
return false, ("ERROR: Expected \"password\", but received (%s)"):format(tmp)
|
||||
end
|
||||
status, response = query(socket, base64.enc(password))
|
||||
if ( not(status) ) then
|
||||
return false, "ERROR: Failed to read LOGIN response"
|
||||
end
|
||||
if ( response:match("^235") ) then
|
||||
return true, "Login success"
|
||||
end
|
||||
return false, response
|
||||
end
|
||||
|
||||
|
||||
if ( mech == "NTLM" ) then
|
||||
-- sniffed of the wire, seems to always be the same
|
||||
-- decodes to some NTLMSSP blob greatness
|
||||
status, response = query(socket, "TlRMTVNTUAABAAAAB7IIogYABgA3AAAADwAPACgAAAAFASgKAAAAD0FCVVNFLUFJUi5MT0NBTERPTUFJTg==")
|
||||
if ( not(status) ) then return false, "ERROR: Failed to receieve NTLM challenge" end
|
||||
end
|
||||
if ( mech == "NTLM" ) then
|
||||
-- sniffed of the wire, seems to always be the same
|
||||
-- decodes to some NTLMSSP blob greatness
|
||||
status, response = query(socket, "TlRMTVNTUAABAAAAB7IIogYABgA3AAAADwAPACgAAAAFASgKAAAAD0FCVVNFLUFJUi5MT0NBTERPTUFJTg==")
|
||||
if ( not(status) ) then return false, "ERROR: Failed to receieve NTLM challenge" end
|
||||
end
|
||||
|
||||
|
||||
local chall = response:match("^334 (.*)")
|
||||
chall = (chall and base64.dec(chall))
|
||||
if (not(chall)) then return false, "ERROR: Failed to retrieve challenge" end
|
||||
local chall = response:match("^334 (.*)")
|
||||
chall = (chall and base64.dec(chall))
|
||||
if (not(chall)) then return false, "ERROR: Failed to retrieve challenge" end
|
||||
|
||||
-- All mechanisms expect username and pass
|
||||
-- add the otheronce for those who need them
|
||||
local mech_params = { username, password, chall, "smtp" }
|
||||
local auth_data = sasl.Helper:new(mech):encode(table.unpack(mech_params))
|
||||
auth_data = base64.enc(auth_data)
|
||||
-- All mechanisms expect username and pass
|
||||
-- add the otheronce for those who need them
|
||||
local mech_params = { username, password, chall, "smtp" }
|
||||
local auth_data = sasl.Helper:new(mech):encode(table.unpack(mech_params))
|
||||
auth_data = base64.enc(auth_data)
|
||||
|
||||
status, response = query(socket, auth_data)
|
||||
if ( not(status) ) then
|
||||
return false, ("ERROR: Failed to authenticate using SASL %s"):format(mech)
|
||||
end
|
||||
status, response = query(socket, auth_data)
|
||||
if ( not(status) ) then
|
||||
return false, ("ERROR: Failed to authenticate using SASL %s"):format(mech)
|
||||
end
|
||||
|
||||
if ( mech == "DIGEST-MD5" ) then
|
||||
local rspauth = response:match("^334 (.*)")
|
||||
if ( rspauth ) then
|
||||
rspauth = base64.dec(rspauth)
|
||||
status, response = query(socket,"")
|
||||
end
|
||||
end
|
||||
if ( mech == "DIGEST-MD5" ) then
|
||||
local rspauth = response:match("^334 (.*)")
|
||||
if ( rspauth ) then
|
||||
rspauth = base64.dec(rspauth)
|
||||
status, response = query(socket,"")
|
||||
end
|
||||
end
|
||||
|
||||
if ( response:match("^235") ) then return true, "Login success" end
|
||||
if ( response:match("^235") ) then return true, "Login success" end
|
||||
|
||||
return false, response
|
||||
return false, response
|
||||
end
|
||||
|
||||
return _ENV;
|
||||
|
|
|
|||
|
|
@ -647,9 +647,9 @@ local function format_output_sub(status, data, indent)
|
|||
local lines = splitlines(value)
|
||||
|
||||
for j, line in ipairs(lines) do
|
||||
insert(output, format("%s %s%s\n",
|
||||
format_get_indent(indent, i == #data and j == #lines),
|
||||
prefix, line))
|
||||
insert(output, format("%s %s%s\n",
|
||||
format_get_indent(indent, i == #data and j == #lines),
|
||||
prefix, line))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1019,65 +1019,65 @@ do end -- no function here, see nse_main.lua
|
|||
--@param port_range a port range string in Nmap standard format (ex. "T:80,1-30,U:31337,21-25")
|
||||
--@returns boolean indicating whether the port is in the port range
|
||||
function in_port_range(port,port_range)
|
||||
assert(port and type(port.number)=="number" and type(port.protocol)=="string" and
|
||||
(port.protocol=="udp" or port.protocol=="tcp"),"Port structure missing or invalid: port={ number=<port_number>, protocol=<port_protocol> }")
|
||||
assert((type(port_range)=="string" or type(port_range)=="number") and port_range~="","Incorrect port range specification.")
|
||||
assert(port and type(port.number)=="number" and type(port.protocol)=="string" and
|
||||
(port.protocol=="udp" or port.protocol=="tcp"),"Port structure missing or invalid: port={ number=<port_number>, protocol=<port_protocol> }")
|
||||
assert((type(port_range)=="string" or type(port_range)=="number") and port_range~="","Incorrect port range specification.")
|
||||
|
||||
-- Proto - true for TCP, false for UDP
|
||||
local proto
|
||||
if(port.protocol=="tcp") then proto = true else proto = false end
|
||||
-- Proto - true for TCP, false for UDP
|
||||
local proto
|
||||
if(port.protocol=="tcp") then proto = true else proto = false end
|
||||
|
||||
--TCP flag for iteration - true for TCP, false for UDP, if not specified we presume TCP
|
||||
local tcp_flag = true
|
||||
--TCP flag for iteration - true for TCP, false for UDP, if not specified we presume TCP
|
||||
local tcp_flag = true
|
||||
|
||||
-- in case the port_range is a single number
|
||||
if type(port_range)=="number" then
|
||||
if proto and port_range==port.number then return true
|
||||
else return false
|
||||
end
|
||||
end
|
||||
-- in case the port_range is a single number
|
||||
if type(port_range)=="number" then
|
||||
if proto and port_range==port.number then return true
|
||||
else return false
|
||||
end
|
||||
end
|
||||
|
||||
--clean the string a bit
|
||||
port_range=port_range:gsub("%s+","")
|
||||
--clean the string a bit
|
||||
port_range=port_range:gsub("%s+","")
|
||||
|
||||
-- single_pr - single port range
|
||||
for i, single_pr in ipairs(strsplit(",",port_range)) do
|
||||
if single_pr:match("T:") then
|
||||
tcp_flag = true
|
||||
single_pr = single_pr:gsub("T:","")
|
||||
else
|
||||
if single_pr:match("U:") then
|
||||
tcp_flag = false
|
||||
single_pr = single_pr:gsub("U:","")
|
||||
end
|
||||
end
|
||||
-- single_pr - single port range
|
||||
for i, single_pr in ipairs(strsplit(",",port_range)) do
|
||||
if single_pr:match("T:") then
|
||||
tcp_flag = true
|
||||
single_pr = single_pr:gsub("T:","")
|
||||
else
|
||||
if single_pr:match("U:") then
|
||||
tcp_flag = false
|
||||
single_pr = single_pr:gsub("U:","")
|
||||
end
|
||||
end
|
||||
|
||||
-- compare ports only when the port's protocol is the same as
|
||||
-- the current single port range
|
||||
if tcp_flag == proto then
|
||||
local pone = single_pr:match("^(%d+)$")
|
||||
if pone then
|
||||
pone = tonumber(pone)
|
||||
assert(pone>-1 and pone<65536, "Port range number out of range (0-65535).")
|
||||
-- compare ports only when the port's protocol is the same as
|
||||
-- the current single port range
|
||||
if tcp_flag == proto then
|
||||
local pone = single_pr:match("^(%d+)$")
|
||||
if pone then
|
||||
pone = tonumber(pone)
|
||||
assert(pone>-1 and pone<65536, "Port range number out of range (0-65535).")
|
||||
|
||||
if pone == port.number then
|
||||
return true
|
||||
end
|
||||
else
|
||||
local pstart, pend = single_pr:match("^(%d+)%-(%d+)$")
|
||||
pstart, pend = tonumber(pstart), tonumber(pend)
|
||||
assert(pstart,"Incorrect port range specification.")
|
||||
assert(pstart<=pend,"Incorrect port range specification, the starting port should have a smaller value than the ending port.")
|
||||
assert(pstart>-1 and pstart<65536 and pend>-1 and pend<65536, "Port range number out of range (0-65535).")
|
||||
if pone == port.number then
|
||||
return true
|
||||
end
|
||||
else
|
||||
local pstart, pend = single_pr:match("^(%d+)%-(%d+)$")
|
||||
pstart, pend = tonumber(pstart), tonumber(pend)
|
||||
assert(pstart,"Incorrect port range specification.")
|
||||
assert(pstart<=pend,"Incorrect port range specification, the starting port should have a smaller value than the ending port.")
|
||||
assert(pstart>-1 and pstart<65536 and pend>-1 and pend<65536, "Port range number out of range (0-65535).")
|
||||
|
||||
if port.number >=pstart and port.number <= pend then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- if no match is found then the port doesn't belong to the port_range
|
||||
return false
|
||||
if port.number >=pstart and port.number <= pend then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- if no match is found then the port doesn't belong to the port_range
|
||||
return false
|
||||
end
|
||||
|
||||
--- Module function that mimics some behavior of Lua 5.1 module function.
|
||||
|
|
@ -1244,12 +1244,12 @@ end
|
|||
--@return Boolean true if the item was found, false if not
|
||||
--@return The index or key where the value was found, or nil
|
||||
function contains(tab, item)
|
||||
for k, val in pairs(tab) do
|
||||
if val == item then
|
||||
return true, k
|
||||
end
|
||||
end
|
||||
return false, nil
|
||||
for k, val in pairs(tab) do
|
||||
if val == item then
|
||||
return true, k
|
||||
end
|
||||
end
|
||||
return false, nil
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
2776
nselib/tns.lua
2776
nselib/tns.lua
File diff suppressed because it is too large
Load diff
|
|
@ -204,7 +204,7 @@ Response = {
|
|||
parse = function(self)
|
||||
local pos
|
||||
pos, self.action, self.trans_id, self.conn_id,
|
||||
self.proto_version, self.vendor_id, self.network_id,
|
||||
self.proto_version, self.vendor_id, self.network_id,
|
||||
self.instance_id = bin.unpack(">IIH8CCII", self.data)
|
||||
end,
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue