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