1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00

Remove trailing whitespace in lua files

Whitespace is not significant, so this should not be a problem.
https://secwiki.org/w/Nmap/Code_Standards
This commit is contained in:
dmiller
2014-01-23 21:51:58 +00:00
parent 86ac3c0a19
commit 620f9fdb34
499 changed files with 11134 additions and 11134 deletions

View File

@@ -219,7 +219,7 @@ local lua = lpeg.locale {
-- This is an expression which is always truncated to 1 result, and so we can remove
-- redundant parenthesis.
_single_exp = P "(" * V "whitespace" * V "_single_exp" * V "whitespace" * P ")" * -(V "whitespace" * (V "suffix" + V "binop")) +
_single_exp = P "(" * V "whitespace" * V "_single_exp" * V "whitespace" * P ")" * -(V "whitespace" * (V "suffix" + V "binop")) +
V "exp";
_oneline_exp = Cg(Cg(Cc " ", "newline") * Cg(Cc "", "indent") * Cg(Cc "", "indent_space") * V "_single_exp");

View File

@@ -330,7 +330,7 @@ do
if not self.worker then
-- Structure table and unstructured string outputs.
local tab, str
if r2 then
tab, str = r1, tostring(r2);
elseif type(r1) == "string" then
@@ -340,7 +340,7 @@ do
else
tab, str = r1, nil;
end
if self.type == "prerule" or self.type == "postrule" then
cnse.script_set_output(self.id, tab, str);
elseif self.type == "hostrule" then
@@ -572,12 +572,12 @@ do
local postrule = rules.postrule;
-- Assert that categories is an array of strings
for i, category in ipairs(rawget(env, "categories")) do
assert(type(category) == "string",
assert(type(category) == "string",
filename.." has non-string entries in the 'categories' array");
end
-- Assert that dependencies is an array of strings
for i, dependency in ipairs(rawget(env, "dependencies")) do
assert(type(dependency) == "string",
assert(type(dependency) == "string",
filename.." has non-string entries in the 'dependencies' array");
end
-- Return the script
@@ -624,7 +624,7 @@ end
-- Arguments:
-- rules The array of rules to use for loading scripts.
-- Returns:
-- chosen_scripts The array of scripts loaded for the given rules.
-- chosen_scripts The array of scripts loaded for the given rules.
local function get_chosen_scripts (rules)
check_rules(rules);
@@ -745,7 +745,7 @@ local function get_chosen_scripts (rules)
" -> script rule expression not supported.");
end
-- The script rule matches a category or a pattern
if found then
if found then
used_rules[rule_table.original_rule] = true;
script_params.forced = not not forced_rules[rule_table.original_rule];
local t, path = cnse.fetchscript(filename);
@@ -806,7 +806,7 @@ local function get_chosen_scripts (rules)
local chain = {}; -- chain of script names
local function calculate_runlevel (script)
chain[#chain+1] = script.short_basename;
if script.runlevel == false then -- circular dependency
if script.runlevel == false then -- circular dependency
error("circular dependency in chain `"..concat(chain, "->").."`");
else
script.runlevel = false; -- placeholder
@@ -1174,7 +1174,7 @@ do -- Load script arguments (--script-args)
"' is invalid or is unterminated by a valid seperator");
end
end
-- Takes 'str' at index 'start' and parses a table.
-- Takes 'str' at index 'start' and parses a table.
-- Returns the table and the place in the string it finished reading.
local function parse_table (str, start)
local _, j = find(str, "^%s*{", start);
@@ -1303,13 +1303,13 @@ local function main (hosts, scantype)
-- parent A table that contains the parent thread table (it self).
-- close_handlers
-- A table that contains the thread destructor handlers.
-- info A string that contains the script name and the thread
-- info A string that contains the script name and the thread
-- debug information.
-- args A table that contains the arguments passed to scripts,
-- args A table that contains the arguments passed to scripts,
-- arguments can be host and port tables.
-- env A table that contains the global script environment:
-- categories, description, author, license, nmap table,
-- action function, rule functions, SCRIPT_PATH,
-- action function, rule functions, SCRIPT_PATH,
-- SCRIPT_NAME, SCRIPT_TYPE (pre|host|port|post rule).
-- identifier
-- A string to identify the thread address.

View File

@@ -1,6 +1,6 @@
---
-- This library was written by Patrik Karlsson <patrik@cqure.net> to facilitate
-- communication with the Apple AFP Service. It is not feature complete and
-- communication with the Apple AFP Service. It is not feature complete and
-- still missing several functions.
--
-- The library currently supports
@@ -44,7 +44,7 @@
-- status, response = helper:CloseSession()
-- </code>
--
-- Here's the longer version, with some explanatory text. To start using the Helper class,
-- Here's the longer version, with some explanatory text. To start using the Helper class,
-- the script has to create it's own instance. We do this by issuing the following:
-- <code>
-- helper = afp.Helper:new()
@@ -93,7 +93,7 @@
--
-- Version 0.5
--
--
-- Created 01/03/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 01/20/2010 - v0.2 - updated all bitmaps to hex for better readability
-- Revised 02/15/2010 - v0.3 - added a bunch of new functions and re-designed the code to be OO
@@ -241,25 +241,25 @@ ACLS = {
OwnerSearch = 0x1,
OwnerRead = 0x2,
OwnerWrite = 0x4,
GroupSearch = 0x100,
GroupRead = 0x200,
GroupWrite = 0x400,
EveryoneSearch = 0x10000,
EveryoneRead = 0x20000,
EveryoneWrite = 0x40000,
UserSearch = 0x100000,
UserRead = 0x200000,
UserWrite = 0x400000,
BlankAccess = 0x10000000,
UserIsOwner = 0x80000000
}
-- User authentication modules
UAM =
UAM =
{
NoUserAuth = "No User Authent",
ClearText = "Cleartxt Passwrd",
@@ -271,11 +271,11 @@ UAM =
Reconnect = "Recon1",
}
ERROR =
ERROR =
{
SocketError = 1000,
CustomError = 0xdeadbeef,
FPNoErr = 0,
FPAccessDenied = -5000,
FPAuthContinue = -5001,
@@ -331,7 +331,7 @@ SERVERFLAGS =
SuperClient = 0x8000
}
local ERROR_MSG = {
local ERROR_MSG = {
[ERROR.FPAccessDenied]="Access Denied",
[ERROR.FPAuthContinue]="Authentication is not yet complete",
[ERROR.FPBadUAM]="Specified UAM is unknown",
@@ -356,28 +356,28 @@ end
-- Response class returned by all functions in Proto
Response = {
new = function(self,o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end,
--- Sets the error code
--
-- @param code number containing the error code
setErrorCode = function( self, code )
self.error_code = code
end,
--- Gets the error code
--
-- @return code number containing the error code
getErrorCode = function( self )
return self.error_code
end,
--- Gets the error message
--
-- @return msg string containing the error
@@ -388,7 +388,7 @@ Response = {
return ERROR_MSG[self.error_code] or ("Unknown error (%d) occured"):format(self.error_code)
end
end,
--- Sets the error message
--
-- @param msg string containing the error message
@@ -396,35 +396,35 @@ Response = {
self.error_code = ERROR.CustomError
self.error_msg = msg
end,
--- Sets the result
--
-- @param result result to set
setResult = function(self, result)
self.result = result
end,
--- Get the result
--
-- @return result
-- @return result
getResult = function(self)
return self.result
end,
--- Sets the packet
setPacket = function( self, packet )
self.packet = packet
end,
getPacket = function( self )
return self.packet
end,
--- Gets the packet data
getPacketData = function(self)
return self.packet.data
end,
--- Gets the packet header
getPacketHeader = function(self)
return self.packet.header
@@ -436,9 +436,9 @@ Response = {
-- For more details consult:
-- http://developer.apple.com/mac/library/documentation/Networking/Reference/AFP_Reference/Reference/reference.html
Proto = {
RequestId = 1,
new = function(self,o)
o = o or {}
setmetatable(o, self)
@@ -455,7 +455,7 @@ Proto = {
-- @param command number should be one of the commands in the COMMAND table
-- @param data_offset number holding the offset to the data
-- @param data the actual data of the request
create_fp_packet = function( self, command, data_offset, data )
create_fp_packet = function( self, command, data_offset, data )
local reserved = 0
local data = data or ""
local data_len = data:len()
@@ -493,7 +493,7 @@ Proto = {
local packet = {}
local buf = ""
local status, response
status, buf = self.socket:receive_bytes(16)
if ( not status ) then
response = Response:new()
@@ -501,7 +501,7 @@ Proto = {
response:setErrorMessage(buf)
return response
end
packet.header = self:parse_fp_header( buf )
while buf:len() < packet.header.length + packet.header.raw:len() do
local tmp
@@ -548,7 +548,7 @@ Proto = {
return self:read_fp_packet()
end,
--- Sends an DSICloseSession request to the server and handles the response
--- Sends an DSICloseSession request to the server and handles the response
dsi_close_session = function( self )
local data_offset = 0
local option = 0x01 -- Attention Quantum
@@ -586,7 +586,7 @@ Proto = {
data = data .. bin.pack(">CIP", unicode_names, unicode_hint, src_path )
data = data .. bin.pack(">CIP", unicode_names, unicode_hint, dst_path )
data = data .. bin.pack(">CIP", unicode_names, unicode_hint, new_name )
packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
self:send_fp_packet( packet )
return self:read_fp_packet()
@@ -597,7 +597,7 @@ Proto = {
--
-- @return status (true or false)
-- @return table with server information (if status is true) or error string
-- (if status is false)
-- (if status is false)
fp_get_server_info = function(self)
local packet
local data_offset = 0
@@ -800,7 +800,7 @@ Proto = {
--- Sends an FPGetUserInfo AFP request to the server and handles the response
--
-- @return response object with the following result <code>user_bitmap</code> and
-- @return response object with the following result <code>user_bitmap</code> and
-- <code>uid</code> fields
fp_get_user_info = function( self )
@@ -821,14 +821,14 @@ Proto = {
end
pos, response.result.user_bitmap, response.result.uid = bin.unpack(">S>I", packet.data)
return response
end,
--- Sends an FPGetSrvrParms AFP request to the server and handles the response
--
-- @return response object with the following result <code>server_time</code>,
-- <code>vol_count</code>, <code>volumes</code> fields
-- <code>vol_count</code>, <code>volumes</code> fields
fp_get_srvr_parms = function(self)
local packet, status, data
local data_offset = 0
@@ -890,7 +890,7 @@ Proto = {
response:setErrorMessage("OpenSSL not available, aborting ...")
return response
end
-- currently we only support AFP3.3
if afp_version == nil or ( afp_version ~= "AFP3.3" and afp_version ~= "AFP3.2" and afp_version ~= "AFP3.1" ) then
response = Response:new()
@@ -934,7 +934,7 @@ Proto = {
end
_, Id, Mb, EncData = bin.unpack(">SH16A32", response.packet.data )
Mb = openssl.bignum_hex2bn( Mb )
K = openssl.bignum_mod_exp (Mb, Ra, p)
K_bin = openssl.bignum_bn2bin(K)
@@ -942,7 +942,7 @@ Proto = {
nonce = openssl.bignum_add( openssl.bignum_bin2bn(nonce), openssl.bignum_dec2bn("1") )
PlainText = openssl.bignum_bn2bin(nonce) .. Util.ZeroPad(password, 64)
auth_response = openssl.encrypt( "cast5-cbc", K_bin, dhx_c2civ, PlainText, true)
data = bin.pack( "CC>SA", COMMAND.FPLoginCont, 0, Id, auth_response )
packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
self:send_fp_packet( packet )
@@ -956,13 +956,13 @@ Proto = {
return response
end,
-- Terminates sessions and frees server resources established by FPLoginand FPLoginExt.
-- Terminates sessions and frees server resources established by FPLoginand FPLoginExt.
--
-- @return response object
fp_logout = function( self )
local packet, data, response
local data_offset, pad = 0, 0
data = bin.pack("CC", COMMAND.FPLogout, pad)
packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
self:send_fp_packet( packet )
@@ -973,7 +973,7 @@ Proto = {
--
-- @param bitmap number bitmask of volume information to request
-- @param volume_name string containing the volume name to query
-- @return response object with the following result <code>bitmap</code> and
-- @return response object with the following result <code>bitmap</code> and
-- <code>volume_id</code> fields
fp_open_vol = function( self, bitmap, volume_name )
local packet, status, pos, data
@@ -1002,7 +1002,7 @@ Proto = {
-- @param dir_bitmap number bitmask of directory information to query
-- @param path string containing the name of the directory to query
-- @return response object with the following result <code>file_bitmap</code>, <code>dir_bitmap</code>,
-- <code>file_type</code> and (<code>dir<code> or <code>file</code> tables) depending on whether
-- <code>file_type</code> and (<code>dir<code> or <code>file</code> tables) depending on whether
-- <code>did</code> is a file or directory
fp_get_file_dir_parms = function( self, volume_id, did, file_bitmap, dir_bitmap, path )
@@ -1042,7 +1042,7 @@ Proto = {
-- file
pos, parms.file = Util.decode_file_bitmap( parms.file_bitmap, response.packet.data, pos )
end
response:setResult(parms)
return response
end,
@@ -1103,7 +1103,7 @@ Proto = {
record.type = ftype
table.insert(records, record)
end
response:setResult(records)
return response
end,
@@ -1123,7 +1123,7 @@ Proto = {
local data_offset = 0
local pad = 0
local response, fork = {}, {}
local data = bin.pack( "CC>S>I>S>S", COMMAND.FPOpenFork, flag, volume_id, did, file_bitmap, access_mode )
if path.type == PATH_TYPE.LongName then
@@ -1132,7 +1132,7 @@ Proto = {
if path.type == PATH_TYPE.UTF8Name then
local unicode_hint = 0x08000103
data = data .. bin.pack( "C>I>SA", path.type, unicode_hint, path.len, path.name )
data = data .. bin.pack( "C>I>SA", path.type, unicode_hint, path.len, path.name )
end
packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
@@ -1147,7 +1147,7 @@ Proto = {
response:setResult(fork)
return response
end,
--- FPCloseFork
--
-- @param fork number containing the fork to close
@@ -1164,7 +1164,7 @@ Proto = {
self:send_fp_packet( packet )
return self:read_fp_packet( )
end,
--- FPCreateDir
--
-- @param vol_id number containing the volume id
@@ -1235,7 +1235,7 @@ Proto = {
fp_write_ext = function( self, flag, fork, offset, count, fdata )
local packet
local data_offset = 20
local data
local data
if count > fdata:len() then
local err = Response:new()
@@ -1253,7 +1253,7 @@ Proto = {
self:send_fp_packet( packet )
return self:read_fp_packet( )
end,
--- FPCreateFile
--
-- @param flag number where 0 indicates a soft create and 1 indicates a hard create.
@@ -1291,15 +1291,15 @@ Proto = {
packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
self:send_fp_packet( packet )
response = self:read_fp_packet( )
if response:getErrorCode() ~= ERROR.FPNoErr then
return response
end
-- Netatalk returns the name with 1-byte length prefix,
-- Mac OS has a 2-byte (UTF-8) length prefix
local _, len = bin.unpack("C", response.packet.data)
-- if length is zero assume 2-byte length (UTF-8 name)
if len == 0 then
response:setResult( select(2, bin.unpack(">P", response.packet.data )) )
@@ -1308,7 +1308,7 @@ Proto = {
end
return response
end,
--- FPMapName
--
-- @param subfunc number containing the subfunction to call
@@ -1323,18 +1323,18 @@ Proto = {
packet = self:create_fp_packet( REQUEST.Command, data_offset, data )
self:send_fp_packet( packet )
response = self:read_fp_packet( )
if response:getErrorCode() ~= ERROR.FPNoErr then
return response
end
response:setResult( select(2, bin.unpack(">I", response.packet.data)))
return response
end,
}
--- The helper class wraps the protocol class and their functions. It contains
-- high-level functions with descriptive names, facilitating the use and
-- high-level functions with descriptive names, facilitating the use and
-- minimizing the need to fully understand the AFP low-level protocol details.
Helper = {
@@ -1356,22 +1356,22 @@ Helper = {
-- @return string containing error message (if status is false)
OpenSession = function( self, host, port )
local status, response
self.socket = nmap.new_socket()
self.socket:set_timeout( 5000 )
status = self.socket:connect(host, port)
if not status then
return false, "Socket connection failed"
end
self.proto = Proto:new( { socket=self.socket} )
response = self.proto:dsi_open_session(self.socket)
if response:getErrorCode() ~= ERROR.FPNoErr then
self.socket:close()
return false, response:getErrorMessage()
end
return true
end,
@@ -1382,7 +1382,7 @@ Helper = {
CloseSession = function( self )
local status, packet = self.proto:dsi_close_session( )
self.socket:close()
return status, packet
end,
@@ -1397,18 +1397,18 @@ Helper = {
--- Logs in to an AFP service
--
-- @param username (optional) string containing the username
-- @param username (optional) string containing the username
-- @param password (optional) string containing the user password
-- @param options table containing additional options <code>uam</code>
Login = function( self, username, password, options )
local uam = ( options and options.UAM ) and options.UAM or "DHCAST128"
local response
-- username and password arguments override the ones supplied using the
-- script arguments afp.username and afp.password
local username = username or self.username
local password = password or self.password
if ( username and uam == "DHCAST128" ) then
response = self.proto:fp_login( "AFP3.1", "DHCAST128", username, password )
elseif( username ) then
@@ -1416,22 +1416,22 @@ Helper = {
else
response = self.proto:fp_login( "AFP3.1", "No User Authent" )
end
if response:getErrorCode() ~= ERROR.FPNoErr then
return false, response:getErrorMessage()
end
return true, "Success"
end,
--- Logs out from the AFP service
Logout = function(self)
return self.proto:fp_logout()
end,
--- Walks the directory tree specified by <code>str_path</code> and returns the node information
--
-- @param str_path string containing the directory
-- @param str_path string containing the directory
-- @return status boolean true on success, otherwise false
-- @return item table containing node information <code>DirectoryId</code> and <code>DirectoryName</code>
WalkDirTree = function( self, str_path )
@@ -1461,7 +1461,7 @@ Helper = {
return true, item
end,
--- Reads a file on the AFP server
--
-- @param str_path string containing the AFP sharepoint, path and filename eg. HR/Documents/File.doc
@@ -1477,12 +1477,12 @@ Helper = {
if ( not status ) then
return false, response
end
vol_id = response.VolumeId
did = response.DirectoryId
path = { ['type']=PATH_TYPE.LongName, name=p.file, len=p.file:len() }
response = self.proto:fp_open_fork(0, vol_id, did, 0, ACCESS_MODE.Read, path )
if response:getErrorCode() ~= ERROR.FPNoErr then
return false, response:getErrorMessage()
@@ -1499,15 +1499,15 @@ Helper = {
content = content .. response.result
offset = offset + count
end
response = self.proto:fp_close_fork( fork )
if response:getErrorCode() ~= ERROR.FPNoErr then
return false, response:getErrorMessage()
end
return true, content
end,
--- Writes a file to the AFP server
--
-- @param str_path string containing the AFP sharepoint, path and filename eg. HR/Documents/File.doc
@@ -1519,15 +1519,15 @@ Helper = {
local offset, count = 1, 1024
local status, vol_id, did, path
local p = Util.SplitPath( str_path )
status, response = self:WalkDirTree( p.dir )
vol_id = response.VolumeId
did = response.DirectoryId
if ( not status ) then
return false, response
end
path = { ['type']=PATH_TYPE.LongName, name=p.file, len=p.file:len() }
status, response = self.proto:fp_create_file( 0, vol_id, did, path )
@@ -1543,12 +1543,12 @@ Helper = {
end
fork = response.result.fork_id
response = self.proto:fp_write_ext( 0, fork, 0, fdata:len(), fdata )
return true, nil
end,
--- Maps a user id (uid) to a user name
--
-- @param uid number containing the uid to resolve
@@ -1562,7 +1562,7 @@ Helper = {
end
return true, response.result
end,
--- Maps a group id (gid) to group name
--
-- @param gid number containing the gid to lookup
@@ -1576,7 +1576,7 @@ Helper = {
end
return true, response.result
end,
--- Maps a username to a UID
--
-- @param name string containing the username to map to an UID
@@ -1589,7 +1589,7 @@ Helper = {
return false, response:getErrorMessage()
end
return true, response.result
end,
end,
--- List the contents of a directory
--
@@ -1609,9 +1609,9 @@ Helper = {
local f_bm = FILE_BITMAP.NodeId + FILE_BITMAP.ParentDirId + FILE_BITMAP.LongName
local d_bm = DIR_BITMAP.NodeId + DIR_BITMAP.ParentDirId + DIR_BITMAP.LongName
local path = { ['type']=PATH_TYPE.LongName, name="", len=0 }
local TYPE_DIR = 0x80
if ( parent == nil ) then
status, response = self:WalkDirTree( str_path )
if ( not status ) then
@@ -1624,17 +1624,17 @@ Helper = {
parent.dir_name = response.DirectoryName or ""
parent.out_tbl = {}
end
if ( options and options.max_depth and options.max_depth > 0 and options.max_depth < depth ) then
return false, "Max Depth Reached"
end
response = self.proto:fp_enumerate_ext2( parent.vol_id, parent.did, f_bm, d_bm, 1000, 1, 52800, path)
response = self.proto:fp_enumerate_ext2( parent.vol_id, parent.did, f_bm, d_bm, 1000, 1, 52800, path)
if response:getErrorCode() ~= ERROR.FPNoErr then
return false, response:getErrorMessage()
end
records = response.result or {}
local dir_item = {}
@@ -1652,36 +1652,36 @@ Helper = {
end
table.insert( parent.out_tbl, dir_item )
return true, parent.out_tbl
end,
--- Displays a directory tree
--
-- @param str_path string containing the sharepoint and the directory
-- @param options table options containing zero or more of the options
-- <code>max_depth</code> and <code>dironly</code>
-- @return dirtree table containing the directories
-- @return dirtree table containing the directories
DirTree = function( self, str_path, options )
local options = options or {}
options.dironly = true
return self:Dir( str_path, options )
end,
--- List the AFP sharepoints
--
-- @return volumes table containing the sharepoints
ListShares = function( self )
local response
response = self.proto:fp_get_srvr_parms( )
if response:getErrorCode() ~= ERROR.FPNoErr then
return false, response:getErrorMessage()
end
return true, response.result.volumes
end,
--- Determine the sharepoint permissions
--
-- @param vol_name string containing the name of the volume
@@ -1689,18 +1689,18 @@ Helper = {
-- @return acls table containing the volume acls as returned by <code>acls_to_long_string</code>
GetSharePermissions = function( self, vol_name )
local status, response, vol_id, acls
response = self.proto:fp_open_vol( VOL_BITMAP.ID, vol_name )
if response:getErrorCode() == ERROR.FPNoErr then
local vol_id
local path = {}
vol_id = response.result.volume_id
vol_id = response.result.volume_id
path.type = PATH_TYPE.LongName
path.name = ""
path.len = path.name:len()
response = self.proto:fp_get_file_dir_parms( vol_id, 2, FILE_BITMAP.ALL, DIR_BITMAP.ALL, path )
if response:getErrorCode() == ERROR.FPNoErr then
if ( response.result.dir and response.result.dir.AccessRights ) then
@@ -1710,10 +1710,10 @@ Helper = {
end
self.proto:fp_close_vol( vol_id )
end
return true, acls
end,
--- Gets the Unix permissions of a file
-- @param vol_name string containing the name of the volume
-- @param str_path string containing the name of the file
@@ -1726,18 +1726,18 @@ Helper = {
-- @return err string (on failure) containing the error message
GetFileUnixPermissions = function(self, vol_name, str_path)
local response = self.proto:fp_open_vol( VOL_BITMAP.ID, vol_name )
if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
return false, response:getErrorMessage()
end
local vol_id = response.result.volume_id
local path = { type = PATH_TYPE.LongName, name = str_path, len = #str_path }
response = self.proto:fp_get_file_dir_parms( vol_id, 2, FILE_BITMAP.UnixPrivileges, DIR_BITMAP.UnixPrivileges, path )
if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
return false, response:getErrorMessage()
end
local item = ( response.result.file ) and response.result.file or response.result.dir
local item_type = ( response.result.file ) and "-" or "d"
local privs = ( item.UnixPrivileges and item.UnixPrivileges.ua_permissions ) and
@@ -1749,7 +1749,7 @@ Helper = {
return true, { uid = uid, gid = gid, privs = str_privs }
end
end,
--- Gets the Unix permissions of a file
-- @param vol_name string containing the name of the volume
-- @param str_path string containing the name of the file
@@ -1758,24 +1758,24 @@ Helper = {
-- @return err string (on failure) containing the error message
GetFileSize = function( self, vol_name, str_path )
local response = self.proto:fp_open_vol( VOL_BITMAP.ID, vol_name )
if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
return false, response:getErrorMessage()
end
local vol_id = response.result.volume_id
local path = { type = PATH_TYPE.LongName, name = str_path, len = #str_path }
response = self.proto:fp_get_file_dir_parms( vol_id, 2, FILE_BITMAP.ExtendedDataForkSize, 0, path )
if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
return false, response:getErrorMessage()
end
return true, ( response.result.file and
response.result.file.ExtendedDataForkSize) and
response.result.file.ExtendedDataForkSize) and
response.result.file.ExtendedDataForkSize or 0
end,
--- Returns the creation, modification and backup dates of a file
-- @param vol_name string containing the name of the volume
-- @param str_path string containing the name of the file
@@ -1787,11 +1787,11 @@ Helper = {
-- @return err string (on failure) containing the error message
GetFileDates = function( self, vol_name, str_path )
local response = self.proto:fp_open_vol( VOL_BITMAP.ID, vol_name )
if ( response:getErrorCode() ~= ERROR.FPNoErr ) then
return false, response:getErrorMessage()
end
local vol_id = response.result.volume_id
local path = { type = PATH_TYPE.LongName, name = str_path, len = #str_path }
local f_bm = FILE_BITMAP.CreationDate + FILE_BITMAP.ModificationDate + FILE_BITMAP.BackupDate
@@ -1802,7 +1802,7 @@ Helper = {
end
local item = ( response.result.file ) and response.result.file or response.result.dir
local diff = os.time{year=2000, month=1, day=1, hour=0} - os.time{year=1970, month=1, day=1, hour=0}
local create = os.date("%Y-%m-%d %H:%M", item.CreationDate + diff)
local backup = os.date("%Y-%m-%d %H:%M", item.BackupDate )
@@ -1817,28 +1817,28 @@ Helper = {
-- @return status boolean true on success, false on failure
-- @return dirId number containing the new directory id
CreateDir = function( self, str_path )
local status, response, vol_id, did
local status, response, vol_id, did
local p = Util.SplitPath( str_path )
local path = { ['type']=PATH_TYPE.LongName, name=p.file, len=p.file:len() }
status, response = self:WalkDirTree( p.dir )
if not status then
return false, response
end
response = self.proto:fp_create_dir( response.VolumeId, response.DirectoryId, path )
if response:getErrorCode() ~= ERROR.FPNoErr then
return false, response:getErrorMessage()
end
return true, response
end,
}
--- Util class, containing some static functions used by Helper and Proto
Util =
Util =
{
--- Pads a string with zeroes
--
@@ -1853,10 +1853,10 @@ Util =
for i=1, len - str:len() do
str = str .. string.char(0)
end
return str
end,
--- Splits a path into two pieces, directory and file
--
-- @param str_path string containing the path to split
@@ -1864,20 +1864,20 @@ Util =
SplitPath = function( str_path )
local elements = stdnse.strsplit("/", str_path)
local dir, file = "", ""
if #elements < 2 then
return nil
end
file = elements[#elements]
table.remove( elements, #elements )
dir = stdnse.strjoin( "/", elements )
return { ['dir']=dir, ['file']=file }
end,
--- Converts a group bitmask of Search, Read and Write to table
--
-- @param acls number containing bitmasked acls
@@ -1888,7 +1888,7 @@ Util =
if bit.band( acls, ACLS.OwnerSearch ) == ACLS.OwnerSearch then
table.insert( acl_table, "Search")
end
end
if bit.band( acls, ACLS.OwnerRead ) == ACLS.OwnerRead then
table.insert( acl_table, "Read")
@@ -1961,8 +1961,8 @@ Util =
return owner .. group .. other
end,
--- Decodes a file bitmap
--
-- @param bitmap number containing the bitmap
@@ -2024,10 +2024,10 @@ Util =
end
if ( bit.band( bitmap, FILE_BITMAP.ExtendedResourceForkSize ) == FILE_BITMAP.ExtendedResourceForkSize ) then
pos, file.ExtendedResourceForkSize = bin.unpack(">L", data, pos )
end
end
if ( bit.band( bitmap, FILE_BITMAP.UnixPrivileges ) == FILE_BITMAP.UnixPrivileges ) then
local unixprivs = {}
pos, unixprivs.uid, unixprivs.gid,
pos, unixprivs.uid, unixprivs.gid,
unixprivs.permissions, unixprivs.ua_permissions = bin.unpack(">IIII", data, pos )
file.UnixPrivileges = unixprivs
end
@@ -2105,13 +2105,13 @@ Util =
if ( bit.band( bitmap, DIR_BITMAP.UnixPrivileges ) == DIR_BITMAP.UnixPrivileges ) then
local unixprivs = {}
pos, unixprivs.uid, unixprivs.gid,
pos, unixprivs.uid, unixprivs.gid,
unixprivs.permissions, unixprivs.ua_permissions = bin.unpack(">I>I>I>I", data, pos )
dir.UnixPrivileges = unixprivs
end
return pos, dir
end,
}

View File

@@ -17,10 +17,10 @@ _ENV = stdnse.module("ajp", stdnse.seeall)
--
AJP = {
-- The magic prefix that has to be present in all requests
Magic = 0x1234,
-- Methods encoded as numeric values
Method = {
['OPTIONS'] = 1,
@@ -51,7 +51,7 @@ AJP = {
['BASELINE_CONTROL'] = 26,
['MKACTIVITY'] = 27,
},
-- Request codes
Code = {
FORWARD_REQUEST = 2,
@@ -62,7 +62,7 @@ AJP = {
PING = 8,
CPING = 10,
},
-- Request attributes
Attribute = {
CONTEXT = 0x01,
@@ -78,9 +78,9 @@ AJP = {
SSL_KEY_SIZE = 0x0B,
ARE_DONE = 0xFF,
},
ForwardRequest = {
-- Common headers encoded as numeric values
Header = {
['accept'] = 0xA001,
@@ -97,7 +97,7 @@ AJP = {
['pragma'] = 0xA00C,
['referer'] = 0xA00D,
['user-agent'] = 0xA00E,
},
},
new = function(self, host, port, method, uri, headers, attributes, options)
local o = {
@@ -118,11 +118,11 @@ AJP = {
}
setmetatable(o, self)
self.__index = self
return o
return o
end,
__tostring = function(self)
-- encodes a string, prefixing it with a 2-byte length
-- and suffixing it with a zero. P-encoding can't be used
-- as the zero terminator should not be counted in the length
@@ -144,7 +144,7 @@ AJP = {
if ( not(self.headers['host']) ) then
self.headers['host'] = stdnse.get_hostname(self.host)
end
-- add keep-alive connection header if missing
if ( not(self.headers['connection']) ) then
self.headers['connection'] = "keep-alive"
@@ -153,12 +153,12 @@ AJP = {
local p_url = url.parse(self.uri)
-- save the magic and data for last
local data = bin.pack(">CCAAAAASCS", self.code, self.method,
local data = bin.pack(">CCAAAAASCS", self.code, self.method,
encstr(self.version), encstr(p_url.path), encstr(self.raddr),
encstr(self.rhost), encstr(self.srv),
self.port, (self.is_ssl and 1 or 0),
headerCount())
-- encode headers
for k, v in pairs(self.headers) do
local header = AJP.ForwardRequest.Header[k:lower()] or k
@@ -167,27 +167,27 @@ AJP = {
else
data = data .. bin.pack(">S", header)
end
data = data .. encstr(v)
end
-- encode attributes
if ( p_url.query ) then
data = data .. bin.pack("C", AJP.Attribute.QUERY_STRING)
data = data .. encstr(p_url.query)
end
-- terminate the attribute list
data = data .. bin.pack("C", AJP.Attribute.ARE_DONE)
-- returns the AJP request as a string
return bin.pack(">SSA", AJP.Magic, #data, data)
end,
},
Response = {
Header = {
['Content-Type'] = 0xA001,
['Content-Language'] = 0xA002,
@@ -201,51 +201,51 @@ AJP = {
['Status'] = 0xA00A,
['WWW-Authenticate'] = 0xA00B,
},
SendHeaders = {
new = function(self)
local o = { headers = {}, rawheaders = {} }
setmetatable(o, self)
self.__index = self
return o
end,
parse = function(data)
local sh = AJP.Response.SendHeaders:new()
local pos = 6
local status_msg, hdr_count
pos, sh.status = bin.unpack(">S", data, pos)
pos, status_msg = bin.unpack(">P", data, pos)
pos = pos + 1
sh['status-line'] = ("AJP/1.3 %d %s"):format(sh.status, status_msg)
pos, hdr_count = bin.unpack(">S", data, pos)
local function headerById(id)
for k, v in pairs(AJP.Response.Header) do
if ( v == id ) then return k end
end
end
for i=1, hdr_count do
local key, val, len
pos, len = bin.unpack(">S", data, pos)
if ( len < 0xA000 ) then
pos, key = bin.unpack("A"..len, data, pos)
pos = pos + 1
else
key = headerById(len)
end
pos, val = bin.unpack(">P", data, pos)
pos = pos + 1
sh.headers[key:lower()] = val
-- to keep the order, in which the headers were received,
-- add them to the rawheader table as well. This is based
-- on the same principle as the http library, however the
@@ -255,16 +255,16 @@ AJP = {
end
return sh
end,
},
},
}
-- The Comm class handles sending and receiving AJP requests/responses
Comm = {
-- Creates a new Comm instance
new = function(self, host, port, options)
local o = { host = host, port = port, options = options or {}}
@@ -272,7 +272,7 @@ Comm = {
self.__index = self
return o
end,
-- Connects to the AJP server
--
-- @return status true on success, false on failure
@@ -282,7 +282,7 @@ Comm = {
self.socket:set_timeout(self.options.timeout or 5000)
return self.socket:connect(self.host, self.port)
end,
-- Sends a request to the server
--
-- @param req instance of object that can be serialized with tostring
@@ -291,7 +291,7 @@ Comm = {
send = function(self, req)
return self.socket:send(tostring(req))
end,
-- Receives an AJP response from the server
--
-- @return status true on succes, false on failure
@@ -317,7 +317,7 @@ Comm = {
if ( not(status) ) then
return false, "Failed to receive response from server"
end
local pos, code = bin.unpack("C", data)
if ( AJP.Code.SEND_HEADERS == code ) then
local sh = AJP.Response.SendHeaders.parse(buf .. data)
@@ -330,22 +330,22 @@ Comm = {
end
return true, response
end,
-- Closes the socket
close = function(self)
return self.socket:close()
end,
}
Helper = {
--- Creates a new AJP Helper instance
--
-- @param host table
-- @param port table
-- @param opt
-- @param opt
-- @return o new Helper instance
new = function(self, host, port, opt)
local o = { host = host, port = port, opt = opt or {} }
@@ -362,18 +362,18 @@ Helper = {
self.comm = Comm:new(self.host, self.port, self.opt)
return self.comm:connect()
end,
getOption = function(self, options, key)
-- first check options, then global self.opt
if ( options and options[key] ) then
return options[key]
elseif ( self.opt and self.opt[key] ) then
return self.opt[key]
end
end,
--- Sends an AJP request to the server
--
-- @param url string containing the URL to query
@@ -388,22 +388,22 @@ Helper = {
if ( not(status) ) then
return false, "Failed to get socket information"
end
local request = AJP.ForwardRequest:new(self.host, self.port, method, url, headers, attributes, { raddr = rhost })
if ( not(self.comm:send(request)) ) then
return false, "Failed to send request to server"
end
local status, result = self.comm:receive()
-- support Basic authentication
if ( status and result.status == 401 and result.headers['www-authenticate'] ) then
local auth = self:getOption(options, "auth")
if ( not(auth) or not(auth.username) and not(auth.password) ) then
stdnse.print_debug(2, "No authentication information")
return status, result
end
local challenges = http.parse_www_authenticate(result.headers['www-authenticate'])
local scheme
for _, challenge in ipairs(challenges or {}) do
@@ -412,7 +412,7 @@ Helper = {
break
end
end
if ( not(scheme) ) then
stdnse.print_debug(2, "Could not find a supported authentication scheme")
elseif ( "basic" ~= scheme ) then
@@ -426,7 +426,7 @@ Helper = {
end
status, result = self.comm:receive()
end
end
return status, result
end,
@@ -443,7 +443,7 @@ Helper = {
get = function(self, url, headers, attributes, options)
return self:request("GET", url, headers, attributes, options)
end,
--- Sends an AJP HEAD request to the server
--
-- @param url string containing the URL to query
@@ -456,7 +456,7 @@ Helper = {
head = function(self, url, headers, attributes, options)
return self:request("HEAD", url, headers, attributes, options)
end,
--- Sends an AJP TRACE request to the server
--
-- @param url string containing the URL to query
@@ -469,7 +469,7 @@ Helper = {
trace = function(self, url, headers, attributes, options)
return self:request("TRACE", url, headers, attributes, options)
end,
--- Sends an AJP PUT request to the server
--
-- @param url string containing the URL to query
@@ -495,7 +495,7 @@ Helper = {
delete = function(self, url, headers, attributes, options)
return self:request("DELETE", url, headers, attributes, options)
end,
--- Sends an AJP OPTIONS request to the server
--
-- @param url string containing the URL to query
@@ -508,18 +508,18 @@ Helper = {
options = function(self, url, headers, attributes, options)
return self:request("OPTIONS", url, headers, attributes, options)
end,
-- should only work against 127.0.0.1
shutdownContainer = function(self)
self.comm:send(bin.pack("H", "1234000107"))
self.comm:receive()
end,
--- Disconnects from the server
close = function(self)
return self.comm:close()
end,
}
return _ENV;
return _ENV;

View File

@@ -50,12 +50,12 @@ ASN1Decoder = {
setStopOnError = function(self, val)
self.stoponerror = val
end,
--- Registers the base simple type decoders
--
--
registerBaseDecoders = function(self)
self.decoder = {}
-- Boolean
self.decoder["01"] = function( self, encStr, elen, pos )
local val = bin.unpack("H", encStr, pos)
@@ -85,7 +85,7 @@ ASN1Decoder = {
self.decoder["06"] = function( self, encStr, elen, pos )
return self:decodeOID( encStr, elen, pos )
end
-- Context specific tags
--
self.decoder["30"] = function( self, encStr, elen, pos )
@@ -104,7 +104,7 @@ ASN1Decoder = {
end,
--- Decodes the ASN.1's built-in simple types
--
--
-- @param encStr Encoded string.
-- @param pos Current position in the string.
-- @return The position after decoding
@@ -169,7 +169,7 @@ ASN1Decoder = {
end
return pos, seq
end,
-- Decode one component of an OID from a byte string. 7 bits of the component
-- are stored in each octet, most significant first, with the eigth bit set in
-- all octets but the last. These encoding rules come from
@@ -186,7 +186,7 @@ ASN1Decoder = {
return pos, n
end,
--- Decodes an OID from a sequence of bytes.
--
-- @param encStr Encoded string.
@@ -216,7 +216,7 @@ ASN1Decoder = {
return pos, oid
end,
---
-- Decodes length part of encoded value according to ASN.1 basic encoding
-- rules.
@@ -240,7 +240,7 @@ ASN1Decoder = {
end
return pos, elen
end,
---
-- Decodes an Integer according to ASN.1 basic encoding rules.
-- @param encStr Encoded string.
@@ -257,7 +257,7 @@ ASN1Decoder = {
end
return pos, value
end,
---
-- Decodes an SNMP packet or a part of it according to ASN.1 basic encoding
-- rules.
@@ -270,7 +270,7 @@ ASN1Decoder = {
_, result = self:decode(encStr, pos)
return result
end,
}
--- The encoder class
@@ -288,7 +288,7 @@ ASN1Encoder = {
---
-- Encodes an ASN1 sequence, the value of 30 below breaks down as
-- 0x30 = 00110000 = 00 1 10000
-- hex binary Universal Constructed value Data Type = SEQUENCE (16)
-- hex binary Universal Constructed value Data Type = SEQUENCE (16)
encodeSeq = function(self, seqData)
return bin.pack('HAA' , '30', self.encodeLength(#seqData), seqData)
end,
@@ -309,7 +309,7 @@ ASN1Encoder = {
return ''
end,
--- Allows for registration of additional tag encoders
--
-- @param tagEncoders table containing encoding functions @see tagEncoders
@@ -319,20 +319,20 @@ ASN1Encoder = {
self.encoder[k] = v
end
end,
-- ASN.1 Simple types encoders
registerBaseEncoders = function(self)
self.encoder = {}
-- Bolean encoder
self.encoder['boolean'] = function( self, val )
if val then
if val then
return bin.pack('H','01 01 FF')
else
else
return bin.pack('H', '01 01 00')
end
end
-- Table encoder
self.encoder['table'] = function( self, val )
assert('table' == type(val), "val is not a table")
@@ -340,7 +340,7 @@ ASN1Encoder = {
assert(val.value ~= nil, "Table is missing the value field")
return bin.pack("HAA", val.type, self.encodeLength(#val.value), val.value)
end
-- Integer encoder
self.encoder['number'] = function( self, val )
local ival = self.encodeInt(val)
@@ -358,9 +358,9 @@ ASN1Encoder = {
self.encoder['nil'] = function( self, val )
return bin.pack('H', '05 00')
end
end,
-- Encode one component of an OID as a byte string. 7 bits of the component are
-- stored in each octet, most significant first, with the eigth bit set in all
-- octets but the last. These encoding rules come from
@@ -412,7 +412,7 @@ ASN1Encoder = {
return bin.pack("x")
end
end,
---
-- Encodes the length part of a ASN.1 encoding triplet using the "primitive,
-- definite-length" method.
@@ -459,7 +459,7 @@ end
-- Converts an integer to a BER encoded type table
--
-- @param i number containing the value to decode
-- @return table with the following entries <code>class</code>, <code>constructed</code>,
-- @return table with the following entries <code>class</code>, <code>constructed</code>,
-- <code>primitive</code> and <code>number</code>
function intToBER( i )
local ber = {}
@@ -478,7 +478,7 @@ function intToBER( i )
ber.number = i - ber.class - 32
else
ber.primitive = true
ber.number = i - ber.class
ber.number = i - ber.class
end
return ber
end

View File

@@ -1,6 +1,6 @@
---
-- Base32 encoding and decoding. Follows RFC 4648.
--
--
-- @author Philip Pickering <pgpickering@gmail.com>
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
-- @ported base64 to base32 <john.r.bond@gmail.com>
@@ -25,9 +25,9 @@ local b32standard = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '2', '3', '4', '5', '6', '7',
'Y', 'Z', '2', '3', '4', '5', '6', '7',
}
local b32dcstandard = {} -- efficency
b32dcstandard['A'] = '00000'
b32dcstandard['B'] = '00001'
@@ -108,7 +108,7 @@ local b32dctable = b32dcstandard
local append = table.insert
local substr = string.sub
local bpack = bin.pack
local bpack = bin.pack
local bunpack = bin.unpack
local concat = table.concat
@@ -155,13 +155,13 @@ function enc(bdata, hexExtend)
append(b32dataBuf, b32enc5bit(bitstring .. "0000"))
append(b32dataBuf, '====')
elseif #bitstring == 2 then
append(b32dataBuf, b32enc5bit(bitstring .. "000") )
append(b32dataBuf, b32enc5bit(bitstring .. "000") )
append(b32dataBuf, '=')
elseif #bitstring == 3 then
append(b32dataBuf, b32enc5bit(bitstring .. "00") )
append(b32dataBuf, b32enc5bit(bitstring .. "00") )
append(b32dataBuf, "======")
elseif #bitstring == 4 then
append(b32dataBuf, b32enc5bit(bitstring .. "0") )
append(b32dataBuf, b32enc5bit(bitstring .. "0") )
append(b32dataBuf, '===')
end
return concat(b32dataBuf)

View File

@@ -22,10 +22,10 @@ local b64table = {
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'
}
local b64dctable = {} -- efficency
b64dctable['A'] = '000000'
b64dctable['B'] = '000001'
@@ -95,7 +95,7 @@ b64dctable['/'] = '111111'
local append = table.insert
local substr = string.sub
local bpack = bin.pack
local bpack = bin.pack
local bunpack = bin.unpack
local concat = table.concat
@@ -107,7 +107,7 @@ local function b64enc6bit(bits)
-- local byte
-- local _, byte = bunpack("C", bpack("B", "00" .. bits))
--
-- more efficient, does the same (nb: add one to byte moved up one line):
local byte = tonumber(bits, 2) + 1
return b64table[byte]
@@ -146,7 +146,7 @@ function enc(bdata)
end
end
if #nbyte == 2 then
append(b64dataBuf, b64enc6bit(nbyte .. "0000") )
append(b64dataBuf, b64enc6bit(nbyte .. "0000") )
append(b64dataBuf, "==")
elseif #nbyte == 4 then
append(b64dataBuf, b64enc6bit(nbyte .. "00"))

View File

@@ -26,7 +26,7 @@
--
-- Version 0.2
--
--
-- Created 11/09/2011 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 17/02/2012 - v0.2 - fixed count parsing
-- - changed version/verack handling to support
@@ -43,9 +43,9 @@ _ENV = stdnse.module("bitcoin", stdnse.seeall)
-- A class that supports the BitCoin network address structure
NetworkAddress = {
NODE_NETWORK = 1,
-- Creates a new instance of the NetworkAddress class
-- @param host table as received by the action method
-- @param port table as received by the action method
@@ -60,20 +60,20 @@ NetworkAddress = {
self.__index = self
return o
end,
-- Creates a new instance of NetworkAddress based on the data string
-- @param data string of bytes
-- @return na instance of NetworkAddress
fromString = function(data)
assert(26 == #data, "Expected 26 bytes of data")
local na = NetworkAddress:new()
local _
_, na.service, na.ipv6_prefix, na.host, na.port = bin.unpack("<LH12I>S", data)
na.host = ipOps.fromdword(na.host)
return na
end,
-- Converts the NetworkAddress instance to string
-- @return data string containing the NetworkAddress instance
__tostring = function(self)
@@ -85,10 +85,10 @@ NetworkAddress = {
-- The request class container
Request = {
-- The version request
Version = {
-- Creates a new instance of the Version request
-- @param host table as received by the action method
-- @param port table as received by the action method
@@ -96,7 +96,7 @@ Request = {
-- @param lport number containing the source port
-- @return o instance of Version
new = function(self, host, port, lhost, lport)
local o = {
local o = {
host = host,
port = port,
lhost= lhost,
@@ -106,7 +106,7 @@ Request = {
self.__index = self
return o
end,
-- Converts the Version request to a string
-- @return data as string
__tostring = function(self)
@@ -115,7 +115,7 @@ Request = {
local len = 85
-- ver: 0.4.0
local ver = 0x9c40
-- NODE_NETWORK = 1
local services = 1
local timestamp = os.time()
@@ -132,20 +132,20 @@ Request = {
-- Checksum is first 4 bytes of sha256(sha256(payload))
local checksum = openssl.digest("sha256", payload)
checksum = openssl.digest("sha256", checksum)
-- Construct the header without checksum
local header = bin.pack("<IAI", magic, cmd, len)
local header = bin.pack("<IAI", magic, cmd, len)
-- After 2012-02-20, version messages require checksums
header = header .. bin.pack("A", checksum:sub(1,4))
return header .. payload
end,
},
-- The GetAddr request
GetAddr = {
-- Creates a new instance of the Version request
-- @param host table as received by the action method
-- @param port table as received by the action method
@@ -153,7 +153,7 @@ Request = {
-- @param lport number containing the source port
-- @return o instance of Version
new = function(self, host, port, lhost, lport)
local o = {
local o = {
host = host,
port = port,
lhost= lhost,
@@ -163,7 +163,7 @@ Request = {
self.__index = self
return o
end,
-- Converts the Version request to a string
-- @return data as string
__tostring = function(self)
@@ -175,27 +175,27 @@ Request = {
return bin.pack("<IAII", magic, cmd, len, chksum)
end
},
VerAck = {
new = function(self)
local o = {}
setmetatable(o, self)
self.__index = self
return o
end,
__tostring = function(self)
return bin.pack("<IAII", 0xD9B4BEF9, "verack\0\0\0\0\0\0", 0, 0xe2e0f65d)
end,
}
}
-- The response class container
Response = {
Header = {
size = 24,
new = function(self)
@@ -213,21 +213,21 @@ Response = {
parse = function(data)
local header = Response.Header:new()
local pos
pos, header.magic, header.cmd, header.length, header.checksum = bin.unpack(">IA12II", data)
return header
end,
},
Alert = {
type = "Alert",
-- Creates a new instance of Version based on data string
-- @param data string containing the raw response
-- @return o instance of Version
new = function(self, data)
local o = {
local o = {
data = data,
}
setmetatable(o, self)
@@ -240,24 +240,24 @@ Response = {
parse = function(self)
local pos = Response.Header.size + 1
self.header = Response.Header.parse(self.data)
local p_length
pos, p_length = Util.decodeVarInt(self.data, pos)
local data
pos, data = bin.unpack("A" .. p_length, self.data, pos)
--
-- TODO: Alert decoding goes here
--
return
end,
end,
},
-- The version response message
Version = {
-- Creates a new instance of Version based on data string
-- @param data string containing the raw response
-- @return o instance of Version
@@ -268,7 +268,7 @@ Response = {
o:parse()
return o
end,
-- Parses the raw data and builds the Version instance
parse = function(self)
local pos, ra, sa
@@ -277,7 +277,7 @@ Response = {
pos, self.magic, self.cmd, self.len, self.checksum, self.ver_raw, self.service,
self.timestamp, ra, sa, self.nodeid,
self.subver, self.lastblock = bin.unpack("<IA12IIILLA26A26H8CI", self.data)
local function decode_bitcoin_version(n)
if ( n < 31300 ) then
local minor, micro = n / 100, n % 100
@@ -287,16 +287,16 @@ Response = {
return ("0.%d.%d"):format(minor, micro)
end
end
self.ver = decode_bitcoin_version(self.ver_raw)
self.sa = NetworkAddress.fromString(sa)
self.ra = NetworkAddress.fromString(ra)
end,
end,
},
-- The verack response message
VerAck = {
-- Creates a new instance of VerAck based on data string
-- @param data string containing the raw response
-- @return o instance of Version
@@ -307,7 +307,7 @@ Response = {
o:parse()
return o
end,
-- Parses the raw data and builds the VerAck instance
parse = function(self)
local pos
@@ -318,7 +318,7 @@ Response = {
-- The Addr response message
Addr = {
-- Creates a new instance of VerAck based on data string
-- @param data string containing the raw response
-- @return o instance of Addr
@@ -329,13 +329,13 @@ Response = {
o:parse()
return o
end,
-- Parses the raw data and builds the Addr instance
parse = function(self)
local pos, count
pos, self.magic, self.cmd, self.len, self.chksum = bin.unpack("<IA12II", self.data)
pos, self.magic, self.cmd, self.len, self.chksum = bin.unpack("<IA12II", self.data)
pos, count = Util.decodeVarInt(self.data, pos)
self.addresses = {}
for c=1, count do
if ( self.version > 31402 ) then
@@ -345,13 +345,13 @@ Response = {
table.insert(self.addresses, { ts = timestamp, address = na })
end
end
end,
end,
},
-- The inventory server packet
Inv = {
-- Creates a new instance of VerAck based on data string
-- @param data string containing the raw response
-- @return o instance of Addr
@@ -362,14 +362,14 @@ Response = {
o:parse()
return o
end,
-- Parses the raw data and builds the Addr instance
parse = function(self)
local pos, count
pos, self.magic, self.cmd, self.len = bin.unpack("<IA12II", self.data)
end,
end,
},
-- Receives the packet and decodes it
-- @param socket BCSocket instance
-- @param version number containing the server version
@@ -381,10 +381,10 @@ Response = {
if ( not(status) ) then
return false, "Failed to read the packet header"
end
local pos, magic, cmd, len, checksum = bin.unpack("<IA12II", header)
local data = ""
-- the verack has no payload
if ( 0 ~= len ) then
status, data = socket:recv(len)
@@ -394,7 +394,7 @@ Response = {
end
return Response.decode(header .. data, version)
end,
-- Decodes the raw packet data
-- @param data string containing the raw packet
-- @param version number containing the server version
@@ -416,7 +416,7 @@ Response = {
else
return false, ("Unknown command (%s)"):format(cmd)
end
end,
end,
}
Util = {
@@ -438,23 +438,23 @@ Util = {
return pos, count
end
end
}
-- A buffered socket implementation
BCSocket =
{
{
retries = 3,
-- Creates a new BCSocket instance
-- Creates a new BCSocket instance
-- @param host table as received by the action method
-- @param port table as received by the action method
-- @param options table containing additional options
-- <code>timeout</code> - the socket timeout in ms
-- @return instance of BCSocket
new = function(self, host, port, options)
local o = {
local o = {
host = host,
port = port,
timeout = "table" == type(options) and options.timeout or 10000
@@ -465,7 +465,7 @@ BCSocket =
o.Buffer = nil
return o
end,
--- Establishes a connection.
--
-- @return Status (true or false).
@@ -474,7 +474,7 @@ BCSocket =
self.Socket:set_timeout( self.timeout )
return self.Socket:connect( self.host, self.port )
end,
--- Closes an open connection.
--
-- @return Status (true or false).
@@ -482,7 +482,7 @@ BCSocket =
close = function( self )
return self.Socket:close()
end,
--- Opposed to the <code>socket:receive_bytes</code> function, that returns
-- at least x bytes, this function returns the amount of bytes requested.
--
@@ -492,9 +492,9 @@ BCSocket =
-- err containing error message if status is false
recv = function( self, count )
local status, data
self.Buffer = self.Buffer or ""
if ( #self.Buffer < count ) then
status, data = self.Socket:receive_bytes( count - #self.Buffer )
if ( not(status) or #data < count - #self.Buffer ) then
@@ -502,13 +502,13 @@ BCSocket =
end
self.Buffer = self.Buffer .. data
end
data = self.Buffer:sub( 1, count )
self.Buffer = self.Buffer:sub( count + 1)
return true, data
return true, data
end,
--- Sends data over the socket
--
-- @return Status (true or false).
@@ -520,15 +520,15 @@ BCSocket =
-- The Helper class used as a primary interface to scripts
Helper = {
-- Creates a new Helper instance
-- Creates a new Helper instance
-- @param host table as received by the action method
-- @param port table as received by the action method
-- @param options table containing additional options
-- <code>timeout</code> - the socket timeout in ms
-- @return instance of Helper
new = function(self, host, port, options)
local o = {
local o = {
host = host,
port = port,
options = options
@@ -544,7 +544,7 @@ Helper = {
connect = function(self)
self.socket = BCSocket:new(self.host, self.port, self.options)
local status, err = self.socket:connect()
if ( not(status) ) then
return false, err
end
@@ -560,63 +560,63 @@ Helper = {
if ( not(self.socket) ) then
return false
end
local req = Request.Version:new(
self.host, self.port, self.lhost, self.lport
)
local status, err = self.socket:send(tostring(req))
if ( not(status) ) then
return false, "Failed to send \"Version\" request to server"
end
local version
status, version = Response.recvPacket(self.socket)
if ( not(status) or not(version) or version.cmd ~= "version\0\0\0\0\0" ) then
return false, "Failed to read \"Version\" response from server"
end
if ( version.ver_raw > 29000 ) then
local status, verack = Response.recvPacket(self.socket)
end
local verack = Request.VerAck:new()
local status, err = self.socket:send(tostring(verack))
if ( not(status) ) then
return false, "Failed to send \"Version\" request to server"
end
self.version = version.ver_raw
return status, version
end,
getNodes = function(self)
local req = Request.GetAddr:new(
self.host, self.port, self.lhost, self.lport
)
local status, err = self.socket:send(tostring(req))
if ( not(status) ) then
return false, "Failed to send \"Version\" request to server"
end
local version
status, version = Response.recvPacket(self.socket)
if ( not(status) or not(version) or version.cmd ~= "version\0\0\0\0\0" ) then
return false, "Failed to read \"Version\" response from server"
end
if ( version.ver_raw > 29000 ) then
local status, verack = Response.recvPacket(self.socket)
end
local verack = Request.VerAck:new()
local status, err = self.socket:send(tostring(verack))
if ( not(status) ) then
return false, "Failed to send \"Version\" request to server"
end
self.version = version.ver_raw
return status, version
end,
getNodes = function(self)
local req = Request.GetAddr:new(
self.host, self.port, self.lhost, self.lport
)
local status, err = self.socket:send(tostring(req))
if ( not(status) ) then
return false, "Failed to send \"Version\" request to server"
end
-- take care of any alerts that may be incoming
local status, response = Response.recvPacket(self.socket, self.version)
while ( status and response and response.type == "Alert" ) do
status, response = Response.recvPacket(self.socket, self.version)
end
return status, response
end,
-- Reads a message from the server
-- @return status true on success, false on failure
-- @return response instance of response packet if status is true
-- err string containing the error message if status is false
readMessage = function(self)
assert(self.version, "Version handshake has not been performed")
return Response.recvPacket(self.socket, self.version)
return Response.recvPacket(self.socket, self.version)
end,
-- Closes the connection to the server
@@ -624,7 +624,7 @@ Helper = {
-- @return err code, if status is false
close = function(self)
return self.socket:close()
end
end
}
return _ENV;

View File

@@ -1,4 +1,4 @@
--- Bittorrent and DHT protocol library which enables users to read
--- Bittorrent and DHT protocol library which enables users to read
-- information from a torrent file, decode bencoded (bittorrent
-- encoded) buffers, find peers associated with a certain torrent and
-- retrieve nodes discovered during the search for peers.
@@ -79,7 +79,7 @@
-- the peers_dht_ping to be processed by the dht_ping thread and so on.
-- That enables the three threads to cooperate and pass on peers and
-- nodes between each other.
--
--
-- There is also a bdecode function which decodes Bittorrent encoded
-- buffers and organizes them into a structure I deemed fit for use.
-- There are two known bittorrent structures: the list and the
@@ -104,7 +104,7 @@ local url = require "url"
_ENV = stdnse.module("bittorrent", stdnse.seeall)
--- Given a buffer and a starting position in the buffer, this function decodes
-- a bencoded string there and returns it as a normal lua string, as well as
-- a bencoded string there and returns it as a normal lua string, as well as
-- the position after the string
local bdec_string = function(buf, pos)
local len = ""
@@ -126,16 +126,16 @@ local bdec_string = function(buf, pos)
end
--- Given a buffer and a starting position in the buffer, this function decodes
-- a bencoded number there and returns it as a normal lua number, as well as
-- a bencoded number there and returns it as a normal lua number, as well as
-- the position after the number
local bdec_number = function(buf, pos)
local s, n = string.match(buf, "^i(%-*)(%d+)e", pos)
if not n then return nil end
local num = tonumber(n)
-- 1 for the "i", 1 for the "e", 1 if there is a "-" plus the length of n
pos = pos + 2 + #n
if s == "-" then
num = -num
pos = pos + 1
@@ -144,7 +144,7 @@ local bdec_number = function(buf, pos)
return num, pos
end
--- Parses a bencoded buffer
--- Parses a bencoded buffer
-- @param buf, string with the bencoded buffer
-- @return bool indicating if parsing went ok
-- @return table containing the decoded structure, or error string
@@ -154,7 +154,7 @@ bdecode = function(buf)
-- the main table
local t = {}
local stack = {}
local pos = 1
local cur = {}
cur.type = "list"
@@ -175,7 +175,7 @@ bdecode = function(buf)
-- next element is a number
elseif "i" == string.char(buf:byte(pos)) then
local num
local num
num, pos = bdec_number(buf, pos)
if not num then return nil, "Error parsing number", pos end
table.insert(cur.ref, num)
@@ -185,7 +185,7 @@ bdecode = function(buf)
local new_list = {}
new_list.type="list"
table.insert(cur.ref, new_list)
cur = {}
cur.type = "list"
cur.ref = new_list
@@ -193,17 +193,17 @@ bdecode = function(buf)
pos = pos+1
--next element is a dict
elseif "d" == string.char(buf:byte(pos)) then
elseif "d" == string.char(buf:byte(pos)) then
local new_dict = {}
new_dict.type = "dict"
table.insert(cur.ref, new_dict)
cur = {}
cur.type = "dict"
cur.ref = new_dict
table.insert(stack, cur)
pos = pos+1
--escape from the list
elseif "e" == string.char(buf:byte(pos)) then
table.remove(stack, #stack)
@@ -213,16 +213,16 @@ bdecode = function(buf)
else
return nil, "Unknown type found.", pos
end
elseif cur.type == "dict" then
local item = {} -- {key = <string>, value = <.*>}
-- used to skip reading the value when escaping from a structure
local escape_flag = false
-- fill the key
if tonumber( string.char( buf:byte(pos) ) ) then
local str
local tmp_pos = pos
local tmp_pos = pos
str, pos = bdec_string(buf, pos)
if not str then return nil, "Error parsing string.", pos end
item.key = str
@@ -231,13 +231,13 @@ bdecode = function(buf)
cur = stack[#stack]
if not cur then return nil, "Problem with list closure:", pos end
pos = pos+1
escape_flag = true
else
return nil, "A dict key has to be a string or escape.", pos
end
if not escape_flag then
-- value
-- next element is a string
@@ -250,7 +250,7 @@ bdecode = function(buf)
--next element is a number
elseif "i" == string.char(buf:byte(pos)) then
local num
local num
num, pos = bdec_number(buf, pos)
if not num then return nil, "Error parsing number.", pos end
item.value = num
@@ -261,7 +261,7 @@ bdecode = function(buf)
item.value = {}
item.value.type = "list"
table.insert(cur.ref, item)
cur = {}
cur.type = "list"
cur.ref = item.value
@@ -296,8 +296,8 @@ bdecode = function(buf)
return false, "Invalid type of structure. Fix the code."
end
end -- while(true)
-- The code below is commented out because some responses from trackers are
-- The code below is commented out because some responses from trackers are
-- not according to standards
-- next(stack) is never gonna be nil because we're always in the main list
@@ -305,15 +305,15 @@ bdecode = function(buf)
-- if next(stack, next(stack)) then
-- return false, "Probably file incorrect format"
-- end
return true, t
end
--- This is the thread function which sends a DHT ping probe to every peer in
-- pnt.peers_dht_ping after which the peer is moved to the pnt.peers and
--- This is the thread function which sends a DHT ping probe to every peer in
-- pnt.peers_dht_ping after which the peer is moved to the pnt.peers and
-- removed from pnt.peers_dht_ping. Every peer which responds to the DHT ping
-- is actually a DHT node and is added to the pnt.nodes_find_node table in
-- order to be processed byt the find_node_thread(). This operation is done
-- is actually a DHT node and is added to the pnt.nodes_find_node table in
-- order to be processed byt the find_node_thread(). This operation is done
-- during the specified timeout which has a default value of about 30 seconds.
local dht_ping_thread = function(pnt, timeout)
local condvar = nmap.condvar(pnt)
@@ -331,34 +331,34 @@ local dht_ping_thread = function(pnt, timeout)
while next(pnt.peers_dht_ping) ~= nil and num_peers <= 100 and os.time() - start < timeout do
num_peers = num_peers +1
local peer_ip, peer_info = next(pnt.peers_dht_ping)
--transaction ids are 2 bytes long
local t_ID_hex = stdnse.tohex(transaction_id % 0xffff)
t_ID_hex = string.rep("0",4-#t_ID_hex)..t_ID_hex
peer_info.transaction_id = bin.pack("H",t_ID_hex)
-- mark it as received so we can distinguish from the others and
-- mark it as received so we can distinguish from the others and
-- successfully iterate while receiving
peer_info.received = false
pnt.peers[peer_ip] = peer_info
pnt.peers_dht_ping[peer_ip] = nil
-- bencoded ping query describing a dictionary with y = q (query), q = ping
-- {"t":<transaction_id>, "y":"q", "q":"ping", "a":{"id":<node_id>}}
local ping_query = "d1:ad2:id20:" .. pnt.node_id .. "e1:q4:ping1:t2:" ..
peer_info.transaction_id .. "1:y1:qe"
status, data = socket:sendto(peer_ip, peer_info.port, ping_query)
transaction_id = transaction_id +1
if transaction_id % 0xffff == 0 then
if transaction_id % 0xffff == 0 then
transaction_id = 0
end
end
-- receive responses up to a 100
for c = 1, 100 do
for c = 1, 100 do
if os.time() - start >= timeout then break end
status, data = socket:receive()
if not status then break end
@@ -381,19 +381,19 @@ local dht_ping_thread = function(pnt, timeout)
trans_id = i.value
end
end
if (not error_flag) and good_response and node_id and trans_id then
local peer_ip
for ip, info in pairs(pnt.peers) do
if info.transaction_id == trans_id then
info.received = nil
info.received = nil
peer_ip = ip
break
end
end
if peer_ip then
pnt.peers[peer_ip].node_id = node_id
if not (pnt.nodes_find_node[peer_ip] or pnt.nodes_get_peers[peer_ip] or
pnt.peers[peer_ip].node_id = node_id
if not (pnt.nodes_find_node[peer_ip] or pnt.nodes_get_peers[peer_ip] or
pnt.nodes[peer_ip]) then
pnt.nodes_find_node[peer_ip] = pnt.peers[peer_ip]
end
@@ -407,18 +407,18 @@ local dht_ping_thread = function(pnt, timeout)
end
--- This thread sends a DHT find_node query to every node in
--- This thread sends a DHT find_node query to every node in
-- pnt.nodes_find_node, after which every node is moved to pnt.nodes_get_peers
-- to be processed by the get_peers_thread() function. The responses to these
-- to be processed by the get_peers_thread() function. The responses to these
-- queries contain adresses of other DHT nodes (usually 8) which are added to
-- the pnt.nodes_find_node list. This action is done for a timeout with a
-- the pnt.nodes_find_node list. This action is done for a timeout with a
-- default value of 30 seconds.
local find_node_thread = function(pnt, timeout)
local condvar = nmap.condvar(pnt)
local socket = nmap.new_socket("udp")
socket:set_timeout(3000)
local status, data
local start = os.time()
while true do
if os.time() - start >= timeout then break end
@@ -429,15 +429,15 @@ local find_node_thread = function(pnt, timeout)
local node_ip, node_info = next(pnt.nodes_find_node)
-- standard bittorrent protocol specified find_node query with y = q (query),
-- q = "find_node" (type of query),
-- q = "find_node" (type of query),
-- find_node Query = {"t":<trainsaction_id>, "y":"q", "q":"find_node", "a": {"id":<node_id>, "target":<info_hash>}}
local find_node_query = "d1:ad2:id20:" .. pnt.node_id .. "6:target20:" ..
local find_node_query = "d1:ad2:id20:" .. pnt.node_id .. "6:target20:" ..
pnt.info_hash .. "e1:q9:find_node1:t2:" .. openssl.rand_bytes(2) .. "1:y1:qe"
-- add the traversed nodes to pnt.nodes_get_peers so they can be traversed by get_peers_thread
pnt.nodes_get_peers[node_ip] = node_info
pnt.nodes_find_node[node_ip] = nil
status, data = socket:sendto(node_ip, node_info.port, find_node_query)
end
@@ -448,7 +448,7 @@ local find_node_thread = function(pnt, timeout)
local s, r = bdecode(data)
if s then
local nodes = nil
local nodes = nil
if r[1] and r[1][1] and r[1][1].key == "r" and r[1][1].value then
for _, el in ipairs(r[1][1].value) do
if el.key == "nodes" then
@@ -456,9 +456,9 @@ local find_node_thread = function(pnt, timeout)
end
end
end
--parse the nodes an add them to pnt.nodes_find_node
if nodes then
if nodes then
for node_id, bin_node_ip, bin_node_port in nodes:gmatch("(....................)(....)(..)") do
local node_ip = string.format("%d.%d.%d.%d", bin_node_ip:byte(1), bin_node_ip:byte(2),
bin_node_ip:byte(3), bin_node_ip:byte(4))
@@ -466,25 +466,25 @@ local find_node_thread = function(pnt, timeout)
local node_info = {}
node_info.port = node_port
node_info.node_id = node_id
if not (pnt.nodes[node_ip] or pnt.nodes_get_peers[node_ip]
if not (pnt.nodes[node_ip] or pnt.nodes_get_peers[node_ip]
or pnt.nodes_find_node[node_ip]) then
pnt.nodes_find_node[node_ip] = node_info
end
end
end -- if nodes
end -- if s
end -- for c = 1, 100
end -- if s
end -- for c = 1, 100
end -- while true
socket:close()
condvar("signal")
end
--- This thread sends get_peers DHT queries to all the nodes in
-- pnt.nodes_get_peers, after which they are moved to pnt.nodes. There are two
-- kinds of responses to these kinds of queries. One response contains peers,
-- which would be added to the pnt.peers_dht_ping list, and the other kind of
--- This thread sends get_peers DHT queries to all the nodes in
-- pnt.nodes_get_peers, after which they are moved to pnt.nodes. There are two
-- kinds of responses to these kinds of queries. One response contains peers,
-- which would be added to the pnt.peers_dht_ping list, and the other kind of
-- response is sent when the queried node has no peers, and contains more nodes
-- which are added to the pnt.nodes_find_node list.
local get_peers_thread = function(pnt, timeout)
@@ -503,11 +503,11 @@ local get_peers_thread = function(pnt, timeout)
local node_ip, node_info = next(pnt.nodes_get_peers)
-- standard bittorrent protocol specified get_peers query with y ="q" (query)
-- and q = "get_peers" (type of query)
-- and q = "get_peers" (type of query)
-- {"t":<transaction_id>, "y":"q", "q":"get_peers", "a": {"id":<node_id>, "info_hash":<info_hash>}}
local get_peers_query = "d1:ad2:id20:" .. pnt.node_id .. "9:info_hash20:" ..
local get_peers_query = "d1:ad2:id20:" .. pnt.node_id .. "9:info_hash20:" ..
pnt.info_hash .. "e1:q9:get_peers1:t2:" .. openssl.rand_bytes(2) .. "1:y1:qe"
pnt.nodes[node_ip] = node_info
pnt.nodes_get_peers[node_ip] = nil
@@ -525,7 +525,7 @@ local get_peers_thread = function(pnt, timeout)
local nodes = nil
local peers = nil
for _,el in ipairs(r[1]) do
if el.key == "y" and el.value == "r" then
if el.key == "y" and el.value == "r" then
good_response = true
elseif el.key == "r" then
for _,i in ipairs(el.value) do
@@ -538,39 +538,39 @@ local get_peers_thread = function(pnt, timeout)
break
end
end
end
end
end
if not good_response then
if not good_response then
break
end
if nodes then
for node_id, bin_node_ip, bin_node_port in
for node_id, bin_node_ip, bin_node_port in
nodes:gmatch("(....................)(....)(..)") do
local node_ip = string.format("%d.%d.%d.%d", bin_node_ip:byte(1), bin_node_ip:byte(2),
bin_node_ip:byte(3), bin_node_ip:byte(4))
local node_port = bit.lshift(bin_node_port:byte(1),8) + bin_node_port:byte(2)
local node_info = {}
node_info.port = node_port
node_info.node_id = node_id
if not (pnt.nodes[node_ip] or pnt.nodes_get_peers[node_ip] or
if not (pnt.nodes[node_ip] or pnt.nodes_get_peers[node_ip] or
pnt.nodes_find_node[node_ip]) then
pnt.nodes_find_node[node_ip] = node_info
end
end
elseif peers then
for _, peer in ipairs(peers) do
local bin_ip, bin_port = peer:match("(....)(..)")
local ip = string.format("%d.%d.%d.%d", bin_ip:byte(1),
local ip = string.format("%d.%d.%d.%d", bin_ip:byte(1),
bin_ip:byte(2), bin_ip:byte(3), bin_ip:byte(4))
local port = bit.lshift(bin_port:byte(1),8)+bin_port:byte(2)
if not (pnt.peers[ip] or pnt.peers_dht_ping[ip]) then
pnt.peers_dht_ping[ip] = {}
pnt.peers_dht_ping[ip].port = port
@@ -587,36 +587,36 @@ end
Torrent =
Torrent =
{
new = function(self)
local o ={}
setmetatable(o, self)
self.__index = self
self.buffer = nil -- buffer to keep the torrent
self.buffer = nil -- buffer to keep the torrent
self.tor_struct = nil -- the decoded structure from the bencoded buffer
self.trackers = {} -- list of trackers {"tr1", "tr2", "tr3"...}
self.trackers = {} -- list of trackers {"tr1", "tr2", "tr3"...}
self.port = 6881 -- port on which our peer "listens" / it doesn't actually listen
self.size = nil -- size of the files in the torrent
self.info_buf = nil --buffer for info_hash
self.info_hash = nil --info_hash binary string
self.info_hash_url = nil --info_hash escaped
self.peers = {} -- peers = { [ip1] = {port1, id1}, [ip2] = {port2, id2}, ...}
self.nodes = {} -- nodes = { [ip1] = {port1, id1}, [ip2] = {port2, id2}, ...}
self.nodes = {} -- nodes = { [ip1] = {port1, id1}, [ip2] = {port2, id2}, ...}
return o
end,
--- Loads trackers and similar information for a torrent from a magnet link.
load_from_magnet = function(self, magnet)
local info_hash_hex = magnet:match("^magnet:%?xt=urn:btih:(%w+)&")
if not info_hash_hex then
if not info_hash_hex then
return false, "Erroneous magnet link"
end
self.info_hash = bin.pack("H",info_hash_hex)
self.info_hash = bin.pack("H",info_hash_hex)
local pos = #info_hash_hex + 21
local name = magnet:sub(pos,#magnet):match("^&dn=(.-)&")
@@ -631,7 +631,7 @@ Torrent =
self.size = 50
end,
--- Reads a torrent file, loads self.buffer and parses it using
--- Reads a torrent file, loads self.buffer and parses it using
-- self:parse_buffer(), then self:calc_info_hash()
--
-- @param filename, string containing filename of the torrent file
@@ -641,13 +641,13 @@ Torrent =
if not filename then return false, "No filename specified." end
local file = io.open(filename, "r")
if not file then return false, "Cannot open file: "..filename end
if not file then return false, "Cannot open file: "..filename end
self.buffer = file:read("*a")
local status, err = self:parse_buffer()
if not status then
return false, "Could not parse file: ".. err
return false, "Could not parse file: ".. err
end
status, err = self:calc_info_hash()
@@ -659,7 +659,7 @@ Torrent =
if not status then
return false, "Could not load trackers: " .. err
end
status, err = self:calc_torrent_size()
if not status then
if not err then err = "" end
@@ -669,20 +669,20 @@ Torrent =
file:close()
return true
end,
--- Gets peers available from the loaded trackers
trackers_peers = function(self)
for _, tracker in ipairs(self.trackers) do
local status, err
if tracker:match("^http://") then -- http tracker
status, err = self:http_tracker_peers(tracker)
if not status then
if not status then
stdnse.print_debug("Could not get peers from tracker %s, reason: %s",tracker, err)
end
elseif tracker:match("^udp://") then -- udp tracker
status, err = self:udp_tracker_peers(tracker)
if not status then
if not status then
stdnse.print_debug("Could not get peers from tracker %s, reason: %s",tracker, err)
end
else -- unknown tracker
@@ -693,20 +693,20 @@ Torrent =
return true
end,
--- Runs the three threads which do a DHT discovery of nodes and peers.
-- The default timeout for this discovery is 30 seconds but it can be
-- set through the timeout argument.
-- The default timeout for this discovery is 30 seconds but it can be
-- set through the timeout argument.
dht_peers = function(self, timeout)
stdnse.print_debug("bittorrent: Starting DHT peers discovery")
if next(self.peers) == nil then
stdnse.print_debug("bittorrent: No peers detected")
return
end
if not timeout or type(timeout)~="number" then timeout = 30 end
-- peer node table aka the condvar!
local pnt = {}
pnt.peers = {}
@@ -733,10 +733,10 @@ Torrent =
break
end
end
self.peers = pnt.peers
self.nodes = pnt.nodes
-- Add some residue nodes and peers
for peer_ip, peer_info in pairs(pnt.peers_dht_ping) do
if not self.peers[peer_ip] then
@@ -756,7 +756,7 @@ Torrent =
end,
--- Parses self.buffer, fills self.tor_struct, self.info_buf
-- This function is similar to the bdecode function but it has a few
-- This function is similar to the bdecode function but it has a few
-- additions for calculating torrent file specific fields
parse_buffer = function(self)
local buf = self.buffer
@@ -767,7 +767,7 @@ Torrent =
local t = {}
self.tor_struct = t
local stack = {}
local pos = 1
local cur = {}
cur.type = "list"
@@ -775,12 +775,12 @@ Torrent =
table.insert(stack, cur)
cur.ref.type="list"
-- starting and ending position of the info dict
-- starting and ending position of the info dict
local info_pos_start, info_pos_end, info_buf_count = nil, nil, 0
while true do
if pos == len or (len-pos)==-1 then break end
if cur.type == "list" then
-- next element is a string
if tonumber( string.char( buf:byte(pos) ) ) then
@@ -791,7 +791,7 @@ Torrent =
-- next element is a number
elseif "i" == string.char(buf:byte(pos)) then
local num
local num
num, pos = bdec_number(buf, pos)
if not num then return nil, "Error parsing number", pos end
table.insert(cur.ref, num)
@@ -801,11 +801,11 @@ Torrent =
if info_pos_start and (not info_pos_end) then
info_buf_count = info_buf_count +1
end
local new_list = {}
new_list.type="list"
table.insert(cur.ref, new_list)
cur = {}
cur.type = "list"
cur.ref = new_list
@@ -813,7 +813,7 @@ Torrent =
pos = pos+1
--next element is a dict
elseif "d" == string.char(buf:byte(pos)) then
elseif "d" == string.char(buf:byte(pos)) then
if info_pos_start and (not info_pos_end) then
info_buf_count = info_buf_count +1
end
@@ -821,13 +821,13 @@ Torrent =
local new_dict = {}
new_dict.type = "dict"
table.insert(cur.ref, new_dict)
cur = {}
cur.type = "dict"
cur.ref = new_dict
table.insert(stack, cur)
pos = pos+1
--escape from the list
elseif "e" == string.char(buf:byte(pos)) then
if info_buf_count == 0 then
@@ -844,13 +844,13 @@ Torrent =
else
return nil, "Unknown type found.", pos
end
elseif cur.type == "dict" then
local item = {} -- {key = <string>, value = <.*>}
-- key
if tonumber( string.char( buf:byte(pos) ) ) then
local str
local tmp_pos = pos
local tmp_pos = pos
str, pos = bdec_string(buf, pos)
if not str then return nil, "Error parsing string.", pos end
item.key = str
@@ -869,11 +869,11 @@ Torrent =
cur = stack[#stack]
if not cur then return nil, "Problem with list closure:", pos end
pos = pos+1
else
return nil, "A dict key has to be a string or escape.", pos
end
-- value
-- next element is a string
if tonumber( string.char( buf:byte(pos) ) ) then
@@ -885,7 +885,7 @@ Torrent =
--next element is a number
elseif "i" == string.char(buf:byte(pos)) then
local num
local num
num, pos = bdec_number(buf, pos)
if not num then return nil, "Error parsing number.", pos end
item.value = num
@@ -900,7 +900,7 @@ Torrent =
item.value = {}
item.value.type = "list"
table.insert(cur.ref, item)
cur = {}
cur.type = "list"
cur.ref = item.value
@@ -945,16 +945,16 @@ Torrent =
return false, "Invalid type of structure. Fix the code."
end
end -- while(true)
-- next(stack) is never gonna be nil because we're always in the main list
-- next(stack, next(stack)) should be nil if we're in the main list
if next(stack, next(stack)) then
return false, "Probably file incorrect format"
end
self.info_buf = buf:sub(info_pos_start, info_pos_end)
return true
return true
end,
--- Loads the list of trackers in self.trackers from self.tor_struct
@@ -964,9 +964,9 @@ Torrent =
self.trackers = trackers
-- load the announce tracker
if tor and tor[1] and tor[1][1] and tor[1][1].key and
if tor and tor[1] and tor[1][1] and tor[1][1].key and
tor[1][1].key == "announce" and tor[1][1].value then
if tor[1][1].value.type and tor[1][1].value.type == "list" then
for _, trac in ipairs(tor[1][1].value) do
table.insert(trackers, trac)
@@ -993,18 +993,18 @@ Torrent =
return true
end,
--- Calculates the size of the torrent in bytes
-- @param tor, decoded bencoded torrent file structure
calc_torrent_size = function(self)
local tor = self.tor_struct
local tor = self.tor_struct
local size = nil
if tor[1].type ~= "dict" then return nil end
for _, m in ipairs(tor[1]) do
if m.key == "info" then
if m.value.type ~= "dict" then return nil end
for _, n in ipairs(m.value) do
if n.key == "files" then
if n.key == "files" then
size = 0
for _, f in ipairs(n.value) do
for _, k in ipairs(f) do
@@ -1025,29 +1025,29 @@ Torrent =
self.size=size
if size == 0 then return false end
end,
--- Calculates the info hash using self.info_buf. The info_hash value
-- is used in many communication transactions for identifying the file
-- shared among the bittorrent peers
calc_info_hash = function(self)
local info_hash = openssl.sha1(self.info_buf)
local info_hash = openssl.sha1(self.info_buf)
self.info_hash_url = url.escape(info_hash)
self.info_hash = info_hash
self.info_buf = nil
return true
end,
--- Generates a peer_id similar to the ones generated by Ktorrent version 4.1.1
generate_peer_id = function(self)
-- let's fool trackers that we use ktorrent just in case they control
-- which client they give peers to
-- which client they give peers to
local fingerprint = "-KT4110-"
local chars = {}
local peer_id = fingerprint
-- the full length of a peer_id is 20 bytes but we already have 8 from the fingerprint
for i = 1,12 do
local n = math.random(1,3)
if n == 1 then
peer_id = peer_id .. string.char( math.random( string.byte("a") , string.byte("z") ) )
elseif n==2 then
@@ -1056,7 +1056,7 @@ Torrent =
peer_id = peer_id .. string.char( math.random( string.byte("0") , string.byte("9") ) )
end
end
return peer_id
end,
@@ -1068,20 +1068,20 @@ Torrent =
url, url_ext = tracker:match("^http://(.-)(/.*)")
trac_port = "80"
end
trac_port = tonumber(trac_port)
-- a http torrent tracker request specifying the info_hash of the torrent, our random
-- generated peer_id (with some mods), notifying the tracker that we are just starting
-- to download the torrent, with 0 downloaded and 0 uploaded bytes, an as many bytes
-- left to download as the size of the torrent, requesting 200 peers in a compact format
-- because some trackers refuse connection if they are not explicitly requested that way
local request = "?info_hash=" .. self.info_hash_url .. "&peer_id=" .. self:generate_peer_id() ..
local request = "?info_hash=" .. self.info_hash_url .. "&peer_id=" .. self:generate_peer_id() ..
"&port=" .. self.port .. "&uploaded=0&downloaded=0&left=" .. self.size ..
"&event=started&numwant=200&compact=1"
local response = http.get(url, trac_port, url_ext .. request, nil)
if not response then
if not response then
return false, "No response from tracker: " .. tracker
end
@@ -1090,12 +1090,12 @@ Torrent =
if not status then
return false, "Could not parse response:"..t
end
if not t[1] then
return nil, "No response from server."
end
for _, k in ipairs(t[1]) do
for _, k in ipairs(t[1]) do
if k.key == "peers" and type(k.value) == "string" then
-- binary peers
for bin_ip, bin_port in string.gmatch(k.value, "(....)(..)") do
@@ -1105,7 +1105,7 @@ Torrent =
local peer = {}
peer.ip = ip
peer.port = port
if not self.peers[peer.ip] then
self.peers[peer.ip] = {}
self.peers[peer.ip].port = peer.port
@@ -1144,18 +1144,18 @@ Torrent =
--- Gets the peers from udp trackers when supplied the URL of the tracker
-- First we establish a connection to the udp server and then we can request peers
-- for a good specification refer to:
-- for a good specification refer to:
-- http://www.rasterbar.com/products/libtorrent/udp_tracker_protocol.html
udp_tracker_peers = function(self, tracker)
local host, port = tracker:match("^udp://(.-):(.+)")
if (not host) or (not port) then
return false, "Could not parse tracker url"
end
local socket = nmap.new_socket("udp")
-- The initial connection parameters' variables have hello_ prefixed names
local hello_transaction_id = openssl.rand_bytes(4)
local hello_transaction_id = openssl.rand_bytes(4)
local hello_action = "00 00 00 00" -- 0 for a connection request
local hello_connection_id = "00 00 04 17 27 10 19 80" -- identification of the protocol
local hello_packet = bin.pack("HHA", hello_connection_id, hello_action, hello_transaction_id)
@@ -1166,36 +1166,36 @@ Torrent =
if not status then return false, "Could not connect to tracker:"..tracker.." reason:"..msg end
local _, r_action, r_transaction_id, r_connection_id =bin.unpack("H4A4A8",msg)
if not (r_transaction_id == hello_transaction_id) then
return false, "Received transaction ID not equivalent to sent transaction ID"
end
-- the action in the response has to be 0 too
if not r_action == "00000000" then
if not r_action == "00000000" then
return false, "Wrong action field, usualy caused by an erroneous request"
end
-- established a connection, and now for an announce message, to which a
-- established a connection, and now for an announce message, to which a
-- response holds the peers
-- the announce connection parameters' variables are prefixed with a_
local a_action = "00 00 00 01" -- 1 for announce
local a_transaction_id = openssl.rand_bytes(4)
local a_transaction_id = openssl.rand_bytes(4)
local a_info_hash = self.info_hash -- info_hash of the torrent
local a_peer_id = self:generate_peer_id()
local a_peer_id = self:generate_peer_id()
local a_downloaded = "00 00 00 00 00 00 00 00" -- 0 bytes downloaded
local a_left = stdnse.tohex(self.size) -- bytes left to download is the size of torrent
a_left = string.rep("0", 16-#a_left) .. a_left
local a_uploaded = "00 00 00 00 00 00 00 00" -- 0 bytes uploaded
local a_event = "00 00 00 02" -- value of 2 for started torrent
local a_ip = "00 00 00 00" -- not necessary to specify our ip since it's resolved
local a_ip = "00 00 00 00" -- not necessary to specify our ip since it's resolved
-- by tracker automatically
local a_key = openssl.rand_bytes(4)
local a_num_want = "FF FF FF FF" -- request for many many peers
local a_port = "1A E1" -- 6881 the port "we are listening on"
local a_port = "1A E1" -- 6881 the port "we are listening on"
local a_extensions = "00 00" -- client recognizes no extensions of the bittorrent proto
local announce_packet = bin.pack("AHAAAHHHHHAHHH", r_connection_id, a_action, a_transaction_id,
a_info_hash, a_peer_id, a_downloaded, a_left, a_uploaded, a_event, a_ip, a_key,
@@ -1211,7 +1211,7 @@ Torrent =
return false, "Didn't receive response to announce message, reason: "..msg
end
local pos, p_action, p_transaction_id, p_interval, p_leechers, p_seeders = bin.unpack("H4A4H4H4H4",msg)
-- the action field in the response has to be 1 (like the sent response)
if not (p_action == "00000001") then
return false, "Action in response to announce erroneous"
@@ -1219,9 +1219,9 @@ Torrent =
if not (p_transaction_id == a_transaction_id) then
return false, "Transaction ID in response to announce message not equal to original"
end
-- parse peers from msg:sub(pos, #msg)
for bin_ip, bin_port in msg:sub(pos,#msg):gmatch("(....)(..)") do
local ip = string.format("%d.%d.%d.%d",
bin_ip:byte(1), bin_ip:byte(2), bin_ip:byte(3), bin_ip:byte(4))

View File

@@ -22,7 +22,7 @@ BJNP = {
-- The common BJNP header
Header = {
new = function(self, o)
o = o or {}
o = {
@@ -42,15 +42,15 @@ BJNP = {
parse = function(data)
local hdr = BJNP.Header:new({ code = -1 })
local pos
pos, hdr.id, hdr.type, hdr.code,
hdr.seq, hdr.session, hdr.length = bin.unpack(">A4CCISI", data)
return hdr
end,
__tostring = function(self)
return bin.pack(">ACCISI",
self.id,
return bin.pack(">ACCISI",
self.id,
self.type,
self.code,
self.seq,
@@ -59,19 +59,19 @@ BJNP = {
)
end
},
-- Scanner related code
Scanner = {
Code = {
DISCOVER = 1,
IDENTITY = 48,
},
Request = {
Discover = {
new = function(self)
local o = { header = BJNP.Header:new( { type = 2, code = BJNP.Scanner.Code.DISCOVER }) }
setmetatable(o, self)
@@ -83,10 +83,10 @@ BJNP = {
return tostring(self.header)
end,
},
Identity = {
new = function(self)
local o = { header = BJNP.Header:new( { type = 2, code = BJNP.Scanner.Code.IDENTITY, length = 4 }), data = 0 }
setmetatable(o, self)
@@ -98,18 +98,18 @@ BJNP = {
return tostring(self.header) .. bin.pack(">I", self.data)
end,
}
},
Response = {
Identity = {
new = function(self)
local o = {}
setmetatable(o, self)
self.__index = self
return o
return o
end,
parse = function(data)
@@ -123,10 +123,10 @@ BJNP = {
return identity
end
end,
}
}
},
@@ -138,7 +138,7 @@ BJNP = {
DISCOVER = 1,
IDENTITY = 48,
},
Request = {
Discover = {
@@ -153,9 +153,9 @@ BJNP = {
return tostring(self.header)
end,
},
Identity = {
new = function(self)
local o = { header = BJNP.Header:new( { code = BJNP.Printer.Code.IDENTITY }) }
setmetatable(o, self)
@@ -167,11 +167,11 @@ BJNP = {
return tostring(self.header)
end,
}
},
Response = {
Identity = {
new = function(self)
@@ -184,7 +184,7 @@ BJNP = {
parse = function(data)
local identity = BJNP.Printer.Response.Identity:new()
identity.header = BJNP.Header.parse(data)
local pos = #tostring(identity.header) + 1
local pos, len = bin.unpack(">S", data, pos)
if ( len ) then
@@ -192,19 +192,19 @@ BJNP = {
return identity
end
end,
}
},
}
}
-- Helper class, the main script writer interface
Helper = {
-- Creates a new Helper instance
-- @param host table
-- @param port table
@@ -222,7 +222,7 @@ Helper = {
self.__index = self
return o
end,
-- Connects the socket to the device
-- This should always be called, regardless if the broadcast option is set
-- or not.
@@ -237,7 +237,7 @@ Helper = {
end
return true
end,
-- Discover network devices using either broadcast or unicast
-- @param packet discovery packet (printer or scanner)
-- @return status, true on success, false on failure
@@ -267,17 +267,17 @@ Helper = {
for host in pairs(tmp) do table.insert(devices, host) end
return true, ( self.options.bcast and devices or ( #devices > 0 and devices[1] ))
end,
-- Discover BJNP supporting scanners
discoverScanner = function(self)
return self:discoverDevice(BJNP.Scanner.Request.Discover:new())
end,
-- Discover BJNP supporting printers
discoverPrinter = function(self)
return self:discoverDevice(BJNP.Printer.Request.Discover:new())
end,
-- Gets a printer identity (additional information)
-- @param devtype string containing either the string printer or scanner
-- @return status, true on success, false on failure
@@ -285,13 +285,13 @@ Helper = {
-- errmsg string containing the error message when status is false
getDeviceIdentity = function(self, devtype)
-- Were currenlty only decoding this as I don't know what the other cruft is
local attrib_names = {
local attrib_names = {
["scanner"] = {
{ ['MFG'] = "Manufacturer" },
{ ['MDL'] = "Model" },
{ ['DES'] = "Description" },
{ ['CMD'] = "Command" },
},
},
["printer"] = {
{ ['MFG'] = "Manufacturer" },
{ ['MDL'] = "Model" },
@@ -314,7 +314,7 @@ Helper = {
if ( not(status) ) then
return false, "Failed to receive response from server"
end
local identity
if ( "printer" == devtype ) then
identity = BJNP.Printer.Response.Identity.parse(data)
@@ -337,27 +337,27 @@ Helper = {
table.insert(attrs, ("%s: %s"):format(long, kvps[short]))
end
end
return true, attrs
end,
-- Retrieves information related to the printer
getPrinterIdentity = function(self)
return self:getDeviceIdentity("printer")
end,
-- Retrieves information related to the scanner
getScannerIdentity = function(self)
return self:getDeviceIdentity("scanner")
end,
-- Closes the connection
-- @return status, true on success, false on failure
-- @return errmsg string containing the error message when status is false
close = function(self)
return self.socket:close()
end
}
return _ENV;

View File

@@ -1,6 +1,6 @@
---
-- The brute library is an attempt to create a common framework for performing
-- password guessing against remote services.
-- password guessing against remote services.
--
-- The library currently attempts to parallellize the guessing by starting
-- a number of working threads. The number of threads can be defined using
@@ -17,9 +17,9 @@
-- * <code>Options</code>
-- ** Stores any options that should be used during brute-forcing.
--
-- In order to make use of the framework a script needs to implement a Driver
-- class. The Driver class is then to be passed as a parameter to the Engine
-- constructor, which creates a new instance for each guess. The Driver class
-- In order to make use of the framework a script needs to implement a Driver
-- class. The Driver class is then to be passed as a parameter to the Engine
-- constructor, which creates a new instance for each guess. The Driver class
-- SHOULD implement the following four methods:
--
-- <code>
@@ -38,14 +38,14 @@
-- password guessing by calling the Error objects <code>setAbort</code> method.
--
-- The following example code demonstrates how the Error object can be used.
--
--
-- <code>
-- -- After a number of incorrect attempts VNC blocks us, so we abort
-- if ( not(status) and x:match("Too many authentication failures") ) then
-- local err = brute.Error:new( data )
-- -- signal the engine to abort
-- err:setAbort( true )
-- return false, err
-- return false, err
-- elseif ( not(status) ) then
-- local err = brute.Error:new( "VNC handshake failed" )
-- -- This might be temporary, signal the engine to retry
@@ -56,7 +56,7 @@
-- .
-- .
-- -- Return a simple error, no retry needed
-- return false, brute.Error:new( "Incorrect password" )
-- return false, brute.Error:new( "Incorrect password" )
-- </code>
--
-- The purpose of the <code>check</code> method is to be able to determine
@@ -64,11 +64,11 @@
-- brute force. It's the method where you should check, e.g., if the correct
-- database or repository URL was specified or not. On success, the
-- <code>check</code> method returns true, on failure it returns false and the
-- brute force engine aborts.
-- brute force engine aborts.
--
-- NOTE: The <code>check</code> method is deprecated and will be removed from
-- all scripts in the future. Scripts should do this check in the action
-- function instead.
-- function instead.
--
-- The <code>connect</code> method provides the framework with the ability to
-- ensure that the thread can run once it has been dispatched a set of
@@ -96,8 +96,8 @@
-- end,
-- disconnect = function( self )
-- return self.socket:close()
-- end,
-- check = function( self )
-- end,
-- check = function( self )
-- return true
-- end,
-- login = function( self, username, password )
@@ -127,7 +127,7 @@
-- end
-- </code>
--
-- For a complete example of a brute implementation consult the
-- For a complete example of a brute implementation consult the
-- <code>svn-brute.nse</code> or <code>vnc-brute.nse</code> scripts
--
-- @args brute.useraspass guess the username as password for each user
@@ -173,7 +173,7 @@
-- Revised 07/13/2010 - v0.2 - added connect, disconnect methods to Driver
-- <patrik@cqure.net>
-- Revised 07/21/2010 - v0.3 - documented missing argument brute.mode
-- Revised 07/23/2010 - v0.4 - fixed incorrect statistics and changed output to
-- Revised 07/23/2010 - v0.4 - fixed incorrect statistics and changed output to
-- include statistics, and to display "no accounts
-- found" message.
-- Revised 08/14/2010 - v0.5 - added some documentation and smaller changes per
@@ -185,7 +185,7 @@
-- iterator to use a file handle instead of table
-- Revised 07/21/2011 - v0.72- added code to allow script reporting invalid
-- (non existing) accounts using setInvalidAccount
-- Revised 11/12/2011 - v0.73- added support for max guesses per account to
-- Revised 11/12/2011 - v0.73- added support for max guesses per account to
-- prevent account lockouts.
-- bugfix: added support for guessing the username
-- as password per default, as suggested by the
@@ -224,7 +224,7 @@ _ENV = stdnse.module("brute", stdnse.seeall)
-- * emptypass - guesses an empty string as password (default: false)
--
Options = {
new = function(self)
local o = {}
setmetatable(o, self)
@@ -240,7 +240,7 @@ Options = {
return o
end,
--- Checks if a script argument is boolean true or false
--
-- @param arg string containing the name of the argument to check
@@ -250,7 +250,7 @@ Options = {
local val = stdnse.get_script_args(arg) or default
return (val == "true" or val==true or tonumber(val)==1)
end,
--- Sets the brute mode to either iterate over users or passwords
-- @see description for more information.
--
@@ -260,11 +260,11 @@ Options = {
setMode = function( self, mode )
local modes = { "password", "user", "creds" }
local supported = false
for _, m in ipairs(modes) do
if ( mode == m ) then supported = true end
end
if ( not(supported) ) then
stdnse.print_debug("ERROR: brute.options.setMode: mode %s not supported", mode)
return false, "Unsupported mode"
@@ -279,7 +279,7 @@ Options = {
-- @param param string containing the parameter name
-- @param value string containing the parameter value
setOption = function( self, param, value ) self[param] = value end,
--- Set an alternate title for the result output (default: Accounts)
--
-- @param title string containing the title value
@@ -303,7 +303,7 @@ Account =
self.__index = self
return o
end,
--- Converts an account object to a printable script
--
-- @return string representation of object
@@ -320,7 +320,7 @@ Account =
return ("%s"):format(c)
end
end,
}
-- The Error class, is currently only used to flag for retries
@@ -328,50 +328,50 @@ Account =
Error =
{
retry = false,
new = function(self, msg)
local o = { msg = msg, done = false }
setmetatable(o, self)
self.__index = self
return o
end,
--- Is the error recoverable?
--
-- @return status true if the error is recoverable, false if not
isRetry = function( self ) return self.retry end,
--- Set the error as recoverable
--
-- @param r boolean true if the engine should attempt to retry the
-- credentials, unset or false if not
setRetry = function( self, r ) self.retry = r end,
--- Set the error as abort all threads
--
-- @param b boolean true if the engine should abort guessing on all threads
setAbort = function( self, b ) self.abort = b end,
--- Was the error abortable
--
-- @return status true if the driver flagged the engine to abort
isAbort = function( self ) return self.abort end,
--- Get the error message reported
--
-- @return msg string containing the error message
getMessage = function( self ) return self.msg end,
--- Is the thread done?
--
-- @return status true if done, false if not
isDone = function( self ) return self.done end,
--- Signals the engine that the thread is done and should be terminated
--
-- @param b boolean true if done, unset or false if not
setDone = function( self, b ) self.done = b end,
-- Marks the username as invalid, aborting further guessing.
-- @param username
setInvalidAccount = function(self, username)
@@ -381,25 +381,25 @@ Error =
-- Checks if the error reported the account as invalid.
-- @return username string containing the invalid account
isInvalidAccount = function(self)
return self.invalid_account
return self.invalid_account
end,
}
-- The brute engine, doing all the nasty work
Engine =
{
STAT_INTERVAL = 20,
--- Creates a new Engine instance
--
-- @param driver, the driver class that should be instantiated
-- @param host table as passed to the action method of the script
-- @param port table as passed to the action method of the script
-- @param options table containing any script specific options
-- @return o new Engine instance
-- @return o new Engine instance
new = function(self, driver, host, port, options)
local o = {
local o = {
driver = driver,
host = host,
port = port,
@@ -422,25 +422,25 @@ Engine =
return o
end,
--- Sets the username iterator
--
--- Sets the username iterator
--
-- @param usernameIterator function to set as a username iterator
setUsernameIterator = function(self,usernameIterator)
self.usernames = usernameIterator
end,
--- Sets the password iterator
--
--- Sets the password iterator
--
-- @param passwordIterator function to set as a password iterator
setPasswordIterator = function(self,passwordIterator)
self.passwords = passwordIterator
end,
--- Limit the number of worker threads
--
-- @param max number containing the maximum number of allowed threads
setMaxThreads = function( self, max ) self.max_threads = max end,
--- Returns the number of non-dead threads
--
-- @return count number of non-dead threads
@@ -456,7 +456,7 @@ Engine =
end
return count
end,
--- Calculates the number of threads that are actually doing any work
--
-- @return count number of threads performing activity
@@ -465,9 +465,9 @@ Engine =
for thread, v in pairs(self.threads) do
if ( v.guesses ~= nil ) then count = count + 1 end
end
return count
return count
end,
--- Iterator wrapper used to iterate over all registered iterators
--
-- @return iterator function
@@ -486,7 +486,7 @@ Engine =
end
return coroutine.wrap( next_credential )
end,
--- Does the actual authentication request
--
-- @return true on success, false on failure
@@ -497,7 +497,7 @@ Engine =
local next_credential = self:get_next_credential()
local retries = self.options.max_retries
local username, password
repeat
local driver = self.driver:new( self.host, self.port, self.driver_options )
status = driver:connect()
@@ -510,22 +510,22 @@ Engine =
if ( not(username) and not(password) ) then
driver:disconnect()
self.threads[coroutine.running()].terminate = true
return false
return false
end
until ( ( not(self.found_accounts) or not(self.found_accounts[username]) ) and
( self.options.max_guesses == 0 or not(self.account_guesses[username]) or
( self.options.max_guesses == 0 or not(self.account_guesses[username]) or
self.options.max_guesses > self.account_guesses[username] ) )
-- increases the number of guesses for an account
self.account_guesses[username] = self.account_guesses[username] and self.account_guesses[username] + 1 or 1
end
-- make sure that all threads locked in connect stat terminate quickly
if ( Engine.terminate_all ) then
if ( Engine.terminate_all ) then
driver:disconnect()
return false
end
local c
-- Do we have a username or not?
if ( username and #username > 0 ) then
@@ -533,13 +533,13 @@ Engine =
else
c = ("%s"):format(#password > 0 and password or "<empty>")
end
local msg = ( retries ~= self.options.max_retries ) and "Re-trying" or "Trying"
stdnse.print_debug(2, "%s %s against %s:%d", msg, c, self.host.ip, self.port.number )
status, response = driver:login( username, password )
driver:disconnect()
driver = nil
driver = nil
end
retries = retries - 1
@@ -549,10 +549,10 @@ Engine =
-- * The response was not set to retry
-- * We've reached the maximum retry attempts
until( status or ( response and not( response:isRetry() ) ) or retries == 0)
-- Increase the amount of total guesses
self.counter = self.counter + 1
-- did we exhaust all retries, terminate and report?
if ( retries == 0 ) then
Engine.terminate_all = true
@@ -562,18 +562,18 @@ Engine =
end
return status, response
end,
login = function(self, cvar )
local condvar = nmap.condvar( cvar )
local condvar = nmap.condvar( cvar )
local thread_data = self.threads[coroutine.running()]
local interval_start = os.time()
while( true ) do
-- Should we terminate all threads?
if ( self.terminate_all or thread_data.terminate ) then break end
local status, response = self:doAuthenticate()
if ( status ) then
-- Prevent locked accounts from appearing several times
if ( not(self.found_accounts) or self.found_accounts[response.username] == nil ) then
@@ -583,7 +583,7 @@ Engine =
self.credstore = self.credstore or {}
table.insert(self.credstore, response:toString() )
end
stdnse.print_debug("Discovered account: %s", response:toString())
-- if we're running in passonly mode, and want to continue guessing
@@ -592,7 +592,7 @@ Engine =
if ( not(self.options.passonly) ) then
self.found_accounts[response.username] = true
end
-- Check if firstonly option was set, if so abort all threads
if ( self.options.firstonly ) then self.terminate_all = true end
end
@@ -607,9 +607,9 @@ Engine =
self.found_accounts[response:isInvalidAccount()] = true
end
end
local timediff = (os.time() - interval_start)
-- This thread made another guess
thread_data.guesses = ( thread_data.guesses and thread_data.guesses + 1 or 1 )
@@ -626,20 +626,20 @@ Engine =
end
condvar "signal"
end,
--- Starts the brute-force
--
-- @return status true on success, false on failure
-- @return err string containing error message on failure
start = function(self)
local cvar = {}
local condvar = nmap.condvar( cvar )
assert(self.options.script_name, "SCRIPT_NAME was not set in options.script_name")
assert(self.port.number and self.port.protocol, "Invalid port table detected")
self.port.service = self.port.service or "unknown"
-- Only run the check method if it exist. We should phase this out
-- in favor of a check in the action function of the script
if ( self.driver:new( self.host, self.port, self.driver_options ).check ) then
@@ -647,7 +647,7 @@ Engine =
local status, response = self.driver:new( self.host, self.port, self.driver_options ):check()
if( not(status) ) then return false, response end
end
local usernames = self.usernames
local passwords = self.passwords
@@ -659,7 +659,7 @@ Engine =
end
local mode = self.options.mode or stdnse.get_script_args("brute.mode")
-- if no mode was given, but a credfile is present, assume creds mode
if ( not(mode) and stdnse.get_script_args("brute.credfile") ) then
if ( stdnse.get_script_args("userdb") or
@@ -668,7 +668,7 @@ Engine =
end
mode = 'creds'
end
-- Are we guessing against a service that has no username (eg. VNC)
if ( self.options.passonly ) then
local function single_user_iter(next)
@@ -677,24 +677,24 @@ Engine =
end
-- only add this iterator if no other iterator was specified
if self.iterator == nil then
self.iterator = Iterators.user_pw_iterator( single_user_iter(), passwords )
self.iterator = Iterators.user_pw_iterator( single_user_iter(), passwords )
end
elseif ( mode == 'creds' ) then
local credfile = stdnse.get_script_args("brute.credfile")
if ( not(credfile) ) then
return false, "No credential file specified (see brute.credfile)"
end
local f = io.open( credfile, "r" )
if ( not(f) ) then
return false, ("Failed to open credfile (%s)"):format(credfile)
end
self.iterator = Iterators.credential_iterator( f )
self.iterator = Iterators.credential_iterator( f )
elseif ( mode and mode == 'user' ) then
self.iterator = self.iterator or Iterators.user_pw_iterator( usernames, passwords )
self.iterator = self.iterator or Iterators.user_pw_iterator( usernames, passwords )
elseif( mode and mode == 'pass' ) then
self.iterator = self.iterator or Iterators.pw_user_iterator( usernames, passwords )
self.iterator = self.iterator or Iterators.pw_user_iterator( usernames, passwords )
elseif ( mode ) then
return false, ("Unsupported mode: %s"):format(mode)
-- Default to the pw_user_iterator in case no iterator was specified
@@ -708,7 +708,7 @@ Engine =
self.iterator = unpwdb.concat_iterators(Iterators.pw_same_as_user_iterator(usernames, "lower"),self.iterator)
end
end
if ( ( not(mode) or mode == 'user' or mode == 'pass' ) and self.options.emptypass ) then
local function empty_pass_iter()
local function next_pass()
@@ -718,7 +718,7 @@ Engine =
end
self.iterator = Iterators.account_iterator(usernames, empty_pass_iter(), mode or "pass")
end
self.starttime = os.time()
@@ -731,15 +731,15 @@ Engine =
-- wait for all threads to finnish running
while self:threadCount()>0 do condvar "wait" end
local valid_accounts
if ( not(self.options.nostore) ) then
valid_accounts = creds.Credentials:new(self.options.script_name, self.host, self.port):getTable()
else
valid_accounts = self.credstore
end
local result = {}
-- Did we find any accounts, if so, do formatting
if ( valid_accounts and #valid_accounts > 0 ) then
@@ -748,7 +748,7 @@ Engine =
else
table.insert( result, {"No valid accounts found", name="Accounts"} )
end
-- calculate the average tps
local sum = 0
for _, v in ipairs( self.tps ) do sum = sum + v end
@@ -761,12 +761,12 @@ Engine =
table.insert(stats, ("Performed %d guesses in %d seconds, average tps: %d"):format( self.counter, time_diff, tps ) )
stats.name = "Statistics"
table.insert( result, stats )
if ( self.options.max_guesses > 0 ) then
-- we only display a warning if the guesses are equal to max_guesses
for user, guesses in pairs(self.account_guesses) do
if ( guesses == self.options.max_guesses ) then
table.insert( result, { name = "Information",
table.insert( result, { name = "Information",
("Guesses restricted to %d tries per account to avoid lockout"):format(self.options.max_guesses) } )
break
end
@@ -774,7 +774,7 @@ Engine =
end
result = ( #result ) and stdnse.format_output( true, result ) or ""
-- Did any error occure? If so add this to the result.
if ( self.error ) then
result = result .. (" \n ERROR: %s"):format( self.error )
@@ -782,10 +782,10 @@ Engine =
end
return true, result
end,
}
--- Default username iterator that uses unpwdb
--- Default username iterator that uses unpwdb
--
usernames_iterator = function()
local status, usernames = unpwdb.usernames()
@@ -793,8 +793,8 @@ usernames_iterator = function()
return usernames
end
--- Default password iterator that uses unpwdb
--
--- Default password iterator that uses unpwdb
--
passwords_iterator = function()
local status, passwords = unpwdb.passwords()
if ( not(status) ) then return "Failed to load passwords" end
@@ -810,7 +810,7 @@ Iterators = {
-- @param mode string, should be either 'user' or 'pass' and controls
-- whether the users or passwords are in the 'outer' loop
-- @return function iterator
account_iterator = function(users, pass, mode)
account_iterator = function(users, pass, mode)
local function next_credential ()
local outer, inner
if "table" == type(users) then
@@ -819,7 +819,7 @@ Iterators = {
if "table" == type(pass) then
pass = unpwdb.table_iterator(pass)
end
if ( mode == 'pass' ) then
outer, inner = pass, users
elseif ( mode == 'user' ) then
@@ -840,7 +840,7 @@ Iterators = {
end
while true do coroutine.yield(nil, nil) end
end
return coroutine.wrap( next_credential )
return coroutine.wrap( next_credential )
end,
@@ -868,7 +868,7 @@ Iterators = {
-- @param case string [optional] 'upper' or 'lower', specifies if user
-- and password pairs should be case converted.
-- @return function iterator
pw_same_as_user_iterator = function( users, case )
pw_same_as_user_iterator = function( users, case )
local function next_credential ()
for user in users do
if ( case == 'upper' ) then
@@ -901,7 +901,7 @@ Iterators = {
end
return coroutine.wrap( next_credential )
end,
--- Credential iterator (for default or known user/pass combinations)
--
-- @param f file handle to file containing credentials separated by '/'
@@ -911,7 +911,7 @@ Iterators = {
local c = {}
for line in f:lines() do
if ( not(line:match("^#!comment:")) ) then
local trim = function(s) return s:match('^()%s*$') and '' or s:match('^%s*(.*%S)') end
local trim = function(s) return s:match('^()%s*$') and '' or s:match('^%s*(.*%S)') end
line = trim(line)
local user, pass = line:match("^([^%/]*)%/(.*)$")
coroutine.yield( user, pass )
@@ -922,19 +922,19 @@ Iterators = {
end
return coroutine.wrap( next_credential )
end,
unpwdb_iterator = function( mode )
local status, users, passwords
status, users = unpwdb.usernames()
if ( not(status) ) then return end
status, passwords = unpwdb.passwords()
if ( not(status) ) then return end
return Iterators.account_iterator( users, passwords, mode )
end,
}
return _ENV;

View File

@@ -16,7 +16,7 @@ _ENV = stdnse.module("cassandra", stdnse.seeall)
--[[
Cassandra Thrift protocol implementation.
Cassandra Thrift protocol implementation.
For more information about Cassandra, see:
@@ -43,7 +43,7 @@ end
--@param username to put in format
--@param password to put in format
--@return str : string in cassandra format for login
function loginstr (username, password)
function loginstr (username, password)
local str = CASSANDRAREQ .. pack4str ("login")
str = str .. CASSLOGINMAGIC
str = str .. pack4str("username")
@@ -60,7 +60,7 @@ end
--@param cnt is protocol count
--@return status : true if ok; false if bad
--@return result : value if status ok, error msg if bad
function cmdstr (command,cnt)
function cmdstr (command,cnt)
local str = CASSANDRAREQ .. pack4str (command)
str = str .. bin.pack(">I",cnt)
str = str .. string.char (0x00) -- add null on the end
@@ -73,7 +73,7 @@ end
--@param cnt is protocol count
--@return status : true if ok; false if bad
--@return result : value if status ok, error msg if bad
function sendcmd (socket, command, cnt)
function sendcmd (socket, command, cnt)
local cmdstr = cmdstr (command,cnt)
local response
@@ -86,7 +86,7 @@ function sendcmd (socket, command, cnt)
if ( not(status) ) then
return false, "error sending packet payload"
end
status, response = socket:receive_bytes(4)
if ( not(status) ) then
return false, "error receiving length"
@@ -103,7 +103,7 @@ function sendcmd (socket, command, cnt)
end
-- magic response starts at 5th byte for 4 bytes, 4 byte for length + length of string commmand
if (string.sub(response,5,8+4+string.len(command)) ~= CASSANDRARESP..pack4str(command)) then
if (string.sub(response,5,8+4+string.len(command)) ~= CASSANDRARESP..pack4str(command)) then
return false, "protocol response error"
end
@@ -115,10 +115,10 @@ end
--@param cnt is protocol count
--@return status : true if ok; false if bad
--@return result : value if status ok, error msg if bad
function describe_cluster_name (socket,cnt)
function describe_cluster_name (socket,cnt)
local cname = "describe_cluster_name"
local status,resp = sendcmd(socket,cname,cnt)
if (not(status)) then
stdnse.print_debug(1, "sendcmd"..resp)
return false, "error in communication"
@@ -134,15 +134,15 @@ function describe_cluster_name (socket,cnt)
return true, value
end
--Return API version
--Return API version
--@param socket to connect to
--@param cnt is protocol count
--@return status : true if ok; false if bad
--@return result : value if status ok, error msg if bad
function describe_version (socket,cnt)
function describe_version (socket,cnt)
local cname = "describe_version"
local status,resp = sendcmd(socket,cname,cnt)
if (not(status)) then
stdnse.print_debug(1, "sendcmd"..resp)
return false, "error in communication"
@@ -158,7 +158,7 @@ function describe_version (socket,cnt)
return true, value
end
--Login to Cassandra
--Login to Cassandra
--@param socket to connect to
--@param username to connect to
--@param password to connect to
@@ -190,7 +190,7 @@ function login (socket,username,password)
local _, size = bin.unpack(">I", response, 1)
local loginresp = string.sub(response,5,17)
if (loginresp ~= CASSANDRARESP..pack4str("login")) then
if (loginresp ~= CASSANDRARESP..pack4str("login")) then
return false, "protocol error"
end
@@ -205,6 +205,6 @@ function login (socket,username,password)
else
return false, "Login failed."
end
end
end
return _ENV;

View File

@@ -1,7 +1,7 @@
---
-- This module was written by Patrik Karlsson and facilitates communication
-- with the Citrix XML Service. It is not feature complete and is missing several
-- functions and parameters.
-- with the Citrix XML Service. It is not feature complete and is missing several
-- functions and parameters.
--
-- The library makes little or no effort to verify that the parameters submitted
-- to each function are compliant with the DTD
@@ -12,7 +12,7 @@
-- Details regarding the requests/responses and their parameters can be found in
-- the NFuse.DTD included with Citrix MetaFrame/Xenapp
--
-- This code is based on the information available in:
-- This code is based on the information available in:
-- NFuse.DTD - Version 5.0 (draft 1) 24 January 2008
--
@@ -25,40 +25,40 @@ local table = require "table"
_ENV = stdnse.module("citrixxml", stdnse.seeall)
--- Decodes html-entities to chars eg. &#32; => <space>
--
--
-- @param xmldata string to convert
-- @return string an e
function decode_xml_document(xmldata)
local hexval
if not xmldata then
return ""
end
local newstr = xmldata
for m in xmldata:gmatch("(&#%d+;)") do
hexval = m:match("(%d+)")
if ( hexval ) then
newstr = xmldata:gsub(m, string.char(hexval))
end
end
return newstr
end
--- Sends the request to the server using the http lib
--
--
-- @param host string, the ip of the remote server
-- @param port number, the port of the remote server
-- @param xmldata string, the HTTP data part of the request as XML
--
-- @return string with the response body
--
function send_citrix_xml_request(host, port, xmldata)
function send_citrix_xml_request(host, port, xmldata)
local response = http.post( host, port, "/scripts/WPnBr.dll", { header={["Content-Type"]="text/xml"}}, nil, xmldata)
@@ -66,13 +66,13 @@ function send_citrix_xml_request(host, port, xmldata)
-- decoding should *probably* only be done on XML-values
-- this is *probably* defined in the standard, for anyone interested
return decode_xml_document(response.body)
end
--- Request information about the Citrix Server Farm
--
-- Consult the NFuse.DTD for a complete list of supported parameters
-- This function implements all the supported parameters described in:
-- This function implements all the supported parameters described in:
-- Version 5.0 (draft 1) 24 January 2008
--
-- @param host string, the ip of the remote server
@@ -86,7 +86,7 @@ function request_server_farm_data( host, port )
xmldata = xmldata .. "<NFuseProtocol version=\"1.1\">"
xmldata = xmldata .. "<RequestServerFarmData></RequestServerFarmData>"
xmldata = xmldata .. "</NFuseProtocol>\r\n"
return send_citrix_xml_request(host, port, xmldata)
end
@@ -97,14 +97,14 @@ end
function parse_server_farm_data_response( response )
local farms = {}
response = response:gsub("\r?\n","")
for farm in response:gmatch("<ServerFarmName.->([^<]+)</ServerFarmName>") do
table.insert(farms, farm)
end
return farms
end
--- Sends a request for application data to the Citrix XML service
@@ -137,20 +137,20 @@ function request_appdata(host, port, params)
if desired_details then
if type(desired_details) == "string" then
xmldata = xmldata .. "<DesiredDetails>" .. desired_details .. "</DesiredDetails>"
xmldata = xmldata .. "<DesiredDetails>" .. desired_details .. "</DesiredDetails>"
elseif type(desired_details) == "table" then
for _, v in ipairs(desired_details) do
xmldata = xmldata .. "<DesiredDetails>" .. v .. "</DesiredDetails>"
xmldata = xmldata .. "<DesiredDetails>" .. v .. "</DesiredDetails>"
end
else
assert(desired_details)
end
end
xmldata = xmldata .. "</RequestAppData>"
xmldata = xmldata .. "</NFuseProtocol>\r\n"
return send_citrix_xml_request(host, port, xmldata)
end
@@ -174,32 +174,32 @@ local function extract_appdata_acls(xmldata)
for user in acl:gmatch("<User>(.-)</User>") do
local user_name = user:match("<UserName.->(.-)</UserName>") or ""
local domain_name = user:match("<Domain.->(.-)</Domain>") or ""
if user_name:len() > 0 then
if domain_name:len() > 0 then
domain_name = domain_name .. "\\"
end
table.insert(users, domain_name .. user_name)
end
end
for group in acl:gmatch("<Group>(.-)</Group>") do
local group_name = group:match("<GroupName.->(.-)</GroupName>") or ""
local domain_name = group:match("<Domain.->(.-)</Domain>") or ""
local domain_name = group:match("<Domain.->(.-)</Domain>") or ""
if group_name:len() > 0 then
if domain_name:len() > 0 then
domain_name = domain_name .. "\\"
end
table.insert(groups, domain_name .. group_name)
table.insert(groups, domain_name .. group_name)
end
end
end
end
if #users> 0 then
acls['User'] = users
@@ -207,7 +207,7 @@ local function extract_appdata_acls(xmldata)
if #groups>0 then
acls['Group'] = groups
end
end
return acls
@@ -216,7 +216,7 @@ end
--- Extracts the settings section of the XML response
--
--
-- @param xmldata string containing results from the request app data request
-- @return table containing settings extracted from the settings section of the response
local function extract_appdata_settings(xmldata)
@@ -224,7 +224,7 @@ local function extract_appdata_settings(xmldata)
local settings = {}
settings['appisdisabled'] = xmldata:match("<Settings.-appisdisabled=\"(.-)\".->")
settings['appisdesktop'] = xmldata:match("<Settings.-appisdesktop=\"(.-)\".->")
settings['appisdesktop'] = xmldata:match("<Settings.-appisdesktop=\"(.-)\".->")
for s in xmldata:gmatch("<Settings.->(.-)</Settings>") do
settings['Encryption'] = s:match("<Encryption.->(.-)</Encryption>")
@@ -236,7 +236,7 @@ local function extract_appdata_settings(xmldata)
end
return settings
end
--- Parses the appdata XML response
@@ -247,21 +247,21 @@ function parse_appdata_response(xmldata)
local apps = {}
xmldata = xmldata:gsub("\r?\n",""):gsub(">%s+<", "><")
for AppData in xmldata:gmatch("<AppData>(.-)</AppData>") do
local app_name = AppData:match("<FName.->(.-)</FName>") or ""
local app_name = AppData:match("<FName.->(.-)</FName>") or ""
local app = {}
app['FName'] = app_name
app['AccessList'] = extract_appdata_acls(AppData)
app['Settings'] = extract_appdata_settings(AppData)
table.insert(apps, app)
end
return apps
return apps
end
--
@@ -278,13 +278,13 @@ function request_address(host, port, flags, appname)
if flags then
xmldata = xmldata .. "<Flags>" .. flags .. "</Flags>"
end
if appname then
xmldata = xmldata .. "<Name>"
xmldata = xmldata .. "<AppName>" .. appname .. "</AppName>"
xmldata = xmldata .. "</Name>"
end
xmldata = xmldata .. "</RequestAddress>"
xmldata = xmldata .. "</NFuseProtocol>\r\n"
@@ -294,7 +294,7 @@ end
--- Request information about the Citrix protocol
--
-- Consult the NFuse.DTD for a complete list of supported parameters
-- This function implements all the supported parameters described in:
-- This function implements all the supported parameters described in:
-- Version 5.0 (draft 1) 24 January 2008
--
-- @param host string the host which is to be queried
@@ -303,24 +303,24 @@ end
-- @return string HTTP response data
--
function request_server_data(host, port, params)
local params = params or {}
local server_type = params.ServerType or {"all"}
local client_type = params.ClientType or {"all"}
local xmldata = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\r\n"
xmldata = xmldata .. "<!DOCTYPE NFuseProtocol SYSTEM \"NFuse.dtd\">\r\n"
xmldata = xmldata .. "<NFuseProtocol version=\"1.1\">"
xmldata = xmldata .. "<RequestServerData>"
for _, srvtype in pairs(server_type) do
xmldata = xmldata .. "<ServerType>" .. srvtype .. "</ServerType>"
end
for _, clitype in pairs(client_type) do
xmldata = xmldata .. "<ClientType>" .. clitype .. "</ClientType>"
end
xmldata = xmldata .. "</RequestServerData>"
xmldata = xmldata .. "</NFuseProtocol>\r\n"
@@ -334,20 +334,20 @@ end
function parse_server_data_response(response)
local servers = {}
response = response:gsub("\r?\n","")
response = response:gsub("\r?\n","")
for s in response:gmatch("<ServerName>([^<]+)</ServerName>") do
table.insert(servers, s)
end
return servers
end
--- Request information about the Citrix protocol
--
-- Consult the NFuse.DTD for a complete list of supported parameters
-- This function implements all the supported parameters described in:
-- This function implements all the supported parameters described in:
-- Version 5.0 (draft 1) 24 January 2008
--
-- @param host string the host which is to be queried
@@ -363,7 +363,7 @@ function request_protocol_info( host, port, params )
xmldata = xmldata .. "<!DOCTYPE NFuseProtocol SYSTEM \"NFuse.dtd\">\r\n"
xmldata = xmldata .. "<NFuseProtocol version=\"1.1\">"
xmldata = xmldata .. "<RequestProtocolInfo>"
if params['ServerAddress'] then
xmldata = xmldata .. "<ServerAddress addresstype=\"" .. params['ServerAddress']['attr']['addresstype'] .. "\">"
xmldata = xmldata .. params['ServerAddress'] .. "</ServerAddress>"
@@ -371,14 +371,14 @@ function request_protocol_info( host, port, params )
xmldata = xmldata .. "</RequestProtocolInfo>"
xmldata = xmldata .. "</NFuseProtocol>\r\n"
return send_citrix_xml_request(host, port, xmldata)
end
--- Request capability information
--- Request capability information
--
-- Consult the NFuse.DTD for a complete list of supported parameters
-- This function implements all the supported parameters described in:
-- This function implements all the supported parameters described in:
-- Version 5.0 (draft 1) 24 January 2008
--
-- @param host string the host which is to be queried
@@ -393,7 +393,7 @@ function request_capabilities( host, port )
xmldata = xmldata .. "<RequestCapabilities>"
xmldata = xmldata .. "</RequestCapabilities>"
xmldata = xmldata .. "</NFuseProtocol>\r\n"
return send_citrix_xml_request(host, port, xmldata)
end
@@ -404,20 +404,20 @@ end
function parse_capabilities_response(response)
local servers = {}
response = response:gsub("\r?\n","")
response = response:gsub("\r?\n","")
for s in response:gmatch("<CapabilityId.->([^<]+)</CapabilityId>") do
table.insert(servers, s)
end
return servers
end
--- Tries to validate user credentials against the XML service
--
-- Consult the NFuse.DTD for a complete list of supported parameters
-- This function implements all the supported parameters described in:
-- This function implements all the supported parameters described in:
-- Version 5.0 (draft 1) 24 January 2008
--
--
@@ -436,7 +436,7 @@ function request_validate_credentials(host, port, params )
xmldata = xmldata .. "<NFuseProtocol version=\"5.0\">"
xmldata = xmldata .. "<RequestValidateCredentials>"
xmldata = xmldata .. "<Credentials>"
if credentials['UserName'] then
xmldata = xmldata .. "<UserName>" .. credentials['UserName'] .. "</UserName>"
end
@@ -444,17 +444,17 @@ function request_validate_credentials(host, port, params )
if credentials['Password'] then
xmldata = xmldata .. "<Password encoding=\"cleartext\">" .. credentials['Password'] .. "</Password>"
end
if credentials['Domain'] then
xmldata = xmldata .. "<Domain type=\"NT\">" .. credentials['Domain'] .. "</Domain>"
end
xmldata = xmldata .. "</Credentials>"
xmldata = xmldata .. "</RequestValidateCredentials>"
xmldata = xmldata .. "</NFuseProtocol>\r\n"
return send_citrix_xml_request(host, port, xmldata)
end
@@ -464,14 +464,14 @@ end
--
function parse_validate_credentials_response(response)
local tblResult = {}
response = response:gsub("\r?\n","")
response = response:gsub("\r?\n","")
tblResult['DaysUntilPasswordExpiry'] = response:match("<DaysUntilPasswordExpiry>(.+)</DaysUntilPasswordExpiry>")
tblResult['ShowPasswordExpiryWarning'] = response:match("<ShowPasswordExpiryWarning>(.+)</ShowPasswordExpiryWarning>")
tblResult['ErrorId'] = response:match("<ErrorId>(.+)</ErrorId>")
return tblResult
end
--- Sends a request to reconnect session data
@@ -487,7 +487,7 @@ function request_reconnect_session_data(host, port, params)
local params = params or {}
local Credentials = params.Credentials or {}
params.ServerType = params.ServerType or {}
params.ClientType = params.ClientType or {}
@@ -497,7 +497,7 @@ function request_reconnect_session_data(host, port, params)
xmldata = xmldata .. "<RequestReconnectSessionData>"
xmldata = xmldata .. "<Credentials>"
if Credentials.UserName then
xmldata = xmldata .. "<UserName>" .. Credentials.UserName .. "</UserName>"
end
@@ -505,11 +505,11 @@ function request_reconnect_session_data(host, port, params)
if Credentials.Password then
xmldata = xmldata .. "<Password encoding=\"cleartext\">" .. Credentials.Password .. "</Password>"
end
if Credentials.Domain then
xmldata = xmldata .. "<Domain type=\"NT\">" .. Credentials.Domain .. "</Domain>"
end
xmldata = xmldata .. "</Credentials>"
if params.ClientName then
@@ -519,21 +519,21 @@ function request_reconnect_session_data(host, port, params)
if params.DeviceId then
xmldata = xmldata .. "<DeviceId>" .. params.DeviceId .. "</DeviceId>"
end
for _, srvtype in pairs(params.ServerType) do
xmldata = xmldata .. "<ServerType>" .. srvtype .. "</ServerType>"
end
for _, clitype in pairs(params.ClientType) do
xmldata = xmldata .. "<ClientType>" .. clitype .. "</ClientType>"
end
xmldata = xmldata .. "</RequestReconnectSessionData>"
xmldata = xmldata .. "</NFuseProtocol>\r\n"
return send_citrix_xml_request(host, port, xmldata)
end
return _ENV;

View File

@@ -154,7 +154,7 @@ local function is_ssl(port_number)
return not not common_ssl_ports[port_number]
end
--- This function returns best protocol order for trying to open a
--- This function returns best protocol order for trying to open a
-- connection based on port and service information
--
-- The first value is the best option, the second is the worst
@@ -173,7 +173,7 @@ local function bestoption(port)
end
--- This function opens a connection, sends the first data payload and
-- check if a response is correctly received (what means that the
-- check if a response is correctly received (what means that the
-- protocol used is fine)
--
-- Possible options:
@@ -197,7 +197,7 @@ local function opencon(host, port, protocol, data, opts)
-- check for connect_timeout or timeout option
if opts and opts.connect_timeout then
if opts and opts.connect_timeout then
sd:set_timeout(opts.connect_timeout)
elseif opts and opts.timeout then
sd:set_timeout(opts.timeout)
@@ -206,9 +206,9 @@ local function opencon(host, port, protocol, data, opts)
end
local status = sd:connect(host, port, protocol)
if not status then
if not status then
sd:close()
return nil, nil, nil
return nil, nil, nil
end
-- check for request_timeout or timeout option
@@ -233,9 +233,9 @@ local function opencon(host, port, protocol, data, opts)
end
response = early_resp
end
if not status then
if not status then
sd:close()
return nil, response, early_resp
return nil, response, early_resp
end
return sd, response, early_resp
end

View File

@@ -51,7 +51,7 @@
-- --script-args creds.http='webadmin:password'
--
-- The service name at this point may be anything and the entry is created
-- dynamically without validating whether the service exists or not.
-- dynamically without validating whether the service exists or not.
--
-- The credential argument is not documented in this library using the <at>args
-- function as the argument would incorrectly show up in all scripts making use
@@ -71,9 +71,9 @@
--
-- Supported output formats are CSV, verbose and plain. In both verbose and plain
-- records are seperated by colons. The difference between the two is that verbose
-- includes the credential state. The file extension is automatically added to
-- includes the credential state. The file extension is automatically added to
-- the filename based on the type requested.
--
--
-- @author "Patrik Karlsson <patrik@cqure.net>"
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
@@ -147,7 +147,7 @@ RegStorage = {
o.filter = {}
return o
end,
--- Add credentials to storage
--
-- @param scriptname the name of the script adding the credentials
@@ -158,7 +158,7 @@ RegStorage = {
-- @param pass the password of the user
-- @param state of the account
add = function( self, scriptname, host, port, service, user, pass, state )
local cred = {
local cred = {
scriptname = scriptname,
host = host,
port = port,
@@ -170,7 +170,7 @@ RegStorage = {
nmap.registry.creds = nmap.registry.creds or {}
table.insert( nmap.registry.creds, cred )
end,
--- Sets the storage filter
--
-- @param host table containing the host
@@ -181,7 +181,7 @@ RegStorage = {
self.filter.port = port
self.filter.state = state
end,
--- Returns a credential iterator matching the selected filters
--
-- @return a credential iterator
@@ -190,23 +190,23 @@ RegStorage = {
local host, port = self.filter.host, self.filter.port
if ( not(nmap.registry.creds) ) then return end
for _, v in pairs(nmap.registry.creds) do
local h = ( v.host.ip or v.host )
if ( not(host) and not(port) ) then
if ( not(self.filter.state) or ( v.state == self.filter.state ) ) then
if ( not(self.filter.state) or ( v.state == self.filter.state ) ) then
coroutine.yield(v)
end
elseif ( not(host) and ( port == v.port ) ) then
if ( not(self.filter.state) or ( v.state == self.filter.state ) ) then
if ( not(self.filter.state) or ( v.state == self.filter.state ) ) then
coroutine.yield(v)
end
elseif ( ( host and ( h == host or h == host.ip ) ) and not(port) ) then
if ( not(self.filter.state) or ( v.state == self.filter.state ) ) then
if ( not(self.filter.state) or ( v.state == self.filter.state ) ) then
coroutine.yield(v)
end
elseif ( ( host and ( h == host or h == host.ip ) ) and port.number == v.port ) then
if ( not(self.filter.state) or ( v.state == bit.band(self.filter.state, v.state) ) ) then
if ( not(self.filter.state) or ( v.state == bit.band(self.filter.state, v.state) ) ) then
coroutine.yield(v)
end
end
@@ -214,12 +214,12 @@ RegStorage = {
end
return coroutine.wrap(get_next)
end,
}
-- The credentials class
Credentials = {
--- Creates a new instance of the Credentials class
-- @param scriptname string containing the name of the script
-- @param host table as received by the scripts action method
@@ -231,12 +231,12 @@ Credentials = {
o.storage = RegStorage:new()
o.storage:setFilter(host, port)
o.host = host
o.port = ( port and port.number ) and port.number
o.port = ( port and port.number ) and port.number
o.service = ( port and port.service ) and port.service
o.scriptname = scriptname
return o
end,
--- Add a discovered credential
--
-- @param user the name of the user
@@ -255,11 +255,11 @@ Credentials = {
self.storage:add( self.scriptname, self.host, self.port, self.service, user, pass, state )
end
end,
--- Returns a credential iterator
--
-- @param state mask containing values from the <Code>State</code> table
-- @return credential iterator, returning a credential each time it's
-- @return credential iterator, returning a credential each time it's
-- called. Unless filtered by the state mask all credentials
-- for the host, port match are iterated over.
-- The credential table has the following fields:
@@ -273,7 +273,7 @@ Credentials = {
-- script that added the credential
getCredentials = function(self, state)
local function next_credential()
if ( state ) then
if ( state ) then
self.storage:setFilter(self.host, { number=self.port, service = self.service }, state)
end
@@ -288,11 +288,11 @@ Credentials = {
local creds_global = stdnse.get_script_args('creds.global')
local creds_service
local creds_params
if ( self.service ) then
creds_service = stdnse.get_script_args('creds.' .. self.service )
end
if ( creds_service ) then creds_params = creds_service end
if ( creds_global and creds_service ) then
creds_params = creds_params .. ',' .. creds_global
@@ -311,9 +311,9 @@ Credentials = {
else
user = cred:match("^(.*)$")
end
coroutine.yield( { host = self.host,
coroutine.yield( { host = self.host,
port = self.port,
user = user,
user = user,
pass = pass,
state = State.PARAM,
service = self.service } )
@@ -322,10 +322,10 @@ Credentials = {
end
return coroutine.wrap( next_credential )
end,
--- Returns a table of credentials
--
-- @return tbl table containing the discovered credentials
-- @return tbl table containing the discovered credentials
getTable = function(self)
local result = {}
@@ -355,7 +355,7 @@ Credentials = {
table.insert( result[h][svc], c )
end
end
local output = {}
for hostname, host in pairs(result) do
local host_tbl = { name = hostname }
@@ -369,7 +369,7 @@ Credentials = {
table.insert( host_tbl, svc_tbl )
end
-- sort the services
table.sort( host_tbl,
table.sort( host_tbl,
function(a,b)
return tonumber(a.name:match("^(%d+)")) < tonumber(b.name:match("^(%d+)"))
end
@@ -388,27 +388,27 @@ Credentials = {
end
return (#output > 0 ) and output
end,
-- Saves credentials in the current object to file
-- @param filename string name of the file
-- @param fileformat string file format type, values = csv | verbose | plain (default)
-- @return status true on success, false on failure
-- @return err string containing the error if status is false
saveToFile = function(self, filename, fileformat)
if ( fileformat == 'csv' ) then
filename = filename .. '.csv'
else
filename = filename .. '.txt'
end
local f = io.open( filename, "w")
local output = nil
if ( not(f) ) then
return false, ("ERROR: Failed to open file (%s)"):format(filename)
end
for account in self:getCredentials() do
if ( fileformat == 'csv' ) then
output = "\"" .. account.user .. "\",\"" .. account.pass .. "\",\"" .. StateMsg[account.state] .. "\""
@@ -425,7 +425,7 @@ Credentials = {
f:close()
return true
end,
--- Get credentials with optional host and port filter
-- If no filters are supplied all records are returned
--
@@ -436,7 +436,7 @@ Credentials = {
local all = self:getTable()
if ( all ) then return stdnse.format_output(true, all) end
end,
}
return _ENV;

View File

@@ -24,7 +24,7 @@ Helper = {
self.__index = self
return o
end,
connect = function(self)
self.socket = nmap.new_socket()
return self.socket:connect(self.host, self.port)
@@ -35,23 +35,23 @@ Helper = {
assert(repo, "No repository was specified")
assert(user, "No user was specified")
assert(pass, "No pass was specified")
-- Add a leading slash if it's missing
if ( repo:sub(1,1) ~= "/" ) then repo = "/" .. repo end
table.insert(auth_tab, "BEGIN AUTH REQUEST")
table.insert(auth_tab, repo)
table.insert(auth_tab, user)
table.insert(auth_tab, Util.pwscramble(pass))
table.insert(auth_tab, "END AUTH REQUEST")
local data = stdnse.strjoin("\n", auth_tab) .. "\n"
local status = self.socket:send(data)
if ( not(status) ) then return false, "Failed to send login request" end
local status, response = self.socket:receive()
if ( not(status) ) then return false, "Failed to read login response" end
if ( response == "I LOVE YOU\n" ) then return true end
return false, response
end,
@@ -59,11 +59,11 @@ Helper = {
close = function(self)
return self.socket:close()
end
}
Util = {
--- Scrambles a password
--
-- @param password string containing the password to scramble
@@ -92,7 +92,7 @@ Util = {
end
return 'A' .. result
end
}
return _ENV;

View File

@@ -16,7 +16,7 @@ local url = require "url"
-- * <code>target_check</code> - Validation function of the target (optional)
-- * <code>login_check</code> - Login function of the target
--
-- TODO: Update the functionality of <code>target_check</code> to differentiate
-- TODO: Update the functionality of <code>target_check</code> to differentiate
-- between valid HTTP/200 and a custom error page.
---
@@ -52,7 +52,7 @@ end
---
local function try_http_post_login(host, port, path, target, failstr, params, follow_redirects)
local req = http.post(host, port, url.absolute(path, target), {no_cache=true}, nil, params)
if not req.status then return false end
local status = tonumber(req.status) or 0
if follow_redirects and ( status > 300 and status < 400 ) then
@@ -68,7 +68,7 @@ end
-- Returns authentication realm advertised in an HTTP response
-- @param response HTTP response object, such as a result from http.get()
-- @return realm found in response header WWW-Authenticate
-- (or nil if not present)
-- (or nil if not present)
---
local function http_auth_realm(response)
local auth = response.header["www-authenticate"] or ""

View File

@@ -12,7 +12,7 @@ local url = require "url"
-- * <code>name</code> - Descriptive name
-- * <code>rapidDetect</code> - Callback function that is called in the beginning
-- of detection process. It takes the host and port of the target website as
-- arguments.
-- arguments.
-- * <code>consumingDetect</code> - Callback function that is called for each
-- spidered page. It takes the body of the response (HTML source code) and the
-- requested path as arguments.
@@ -25,25 +25,25 @@ tools = { Django = { rapidDetect = function(host, port)
local response = http.get(host, port, "/admin/")
if response.body then
if string.find(response.body, "Log in | Django site admin") or
string.find(response.body, "this_is_the_login_form") or
if string.find(response.body, "Log in | Django site admin") or
string.find(response.body, "this_is_the_login_form") or
string.find(response.body, "csrfmiddlewaretoken") then
return "Django detected. Found Django admin login page on /admin/"
return "Django detected. Found Django admin login page on /admin/"
end
end
-- In Django, the cookie sessionid is being set when you log in
-- In Django, the cookie sessionid is being set when you log in
-- and forms will probably set a cookie called csrftoken.
if response.cookies then
for _, c in pairs(response.cookies) do
if c.name == "csrftoken" then
return "Django detected. Found sessionid cookie which means the contrib.auth package for authentication is enabled."
return "Django detected. Found sessionid cookie which means the contrib.auth package for authentication is enabled."
elseif c.name == "sessionid" then
return "Django detected. Found csrftoken cookie."
end
end
end
-- See if DEBUG mode still happens to be true.
response = http.get(host, port, "/random404page/")
@@ -54,7 +54,7 @@ tools = { Django = { rapidDetect = function(host, port)
end
end,
consumingDetect = function(page, path)
if page then
if string.find(page, "csrfmiddlewaretoken") then
@@ -64,7 +64,7 @@ tools = { Django = { rapidDetect = function(host, port)
return "Django detected. Found id_ preffix in id attribute name on " .. path
end
if string.find(page, "%-TOTAL%-FORMS") or string.find(page, "%-DELETE") then
return "Django detected. Found -TOTAL-FORMS and -DELETE hidden inputs, which means there is a Django formset on " .. path
return "Django detected. Found -TOTAL-FORMS and -DELETE hidden inputs, which means there is a Django formset on " .. path
end
end
end
@@ -94,7 +94,7 @@ tools = { Django = { rapidDetect = function(host, port)
end
end
-- Make up a bad path and match the error page
-- Make up a bad path and match the error page
response = http.get(host, port, "/random404page/")
if response.body then
@@ -104,7 +104,7 @@ tools = { Django = { rapidDetect = function(host, port)
end
end,
consumingDetect = function(page, path)
-- Check the source and look for csrf patterns.
@@ -113,7 +113,7 @@ tools = { Django = { rapidDetect = function(host, port)
return "RoR detected. Found csrf field on" .. path
end
end
end
},
@@ -133,16 +133,16 @@ tools = { Django = { rapidDetect = function(host, port)
if response.cookies then
for _, c in pairs(response.cookies) do
if c.name == "aspnetsessionid" then
return "ASP.NET detected. Found aspnetsessionid cookie."
return "ASP.NET detected. Found aspnetsessionid cookie."
end
end
end
end,
consumingDetect = function(page, path)
-- Check the source and look for common traces.
if page then
if string.find(page, " __VIEWSTATE") or
if string.find(page, " __VIEWSTATE") or
string.find(page, "__EVENT") or
string.find(page, "__doPostBack") or
string.find(page, "aspnetForm") or
@@ -166,7 +166,7 @@ tools = { Django = { rapidDetect = function(host, port)
end
end,
consumingDetect = function(page, path)
return
end
@@ -186,7 +186,7 @@ tools = { Django = { rapidDetect = function(host, port)
end
end,
consumingDetect = function(page, path)
return
end
@@ -203,9 +203,9 @@ tools = { Django = { rapidDetect = function(host, port)
return "Symfony detected. Found related header."
end
end
end,
consumingDetect = function(page, path)
return
end
@@ -217,7 +217,7 @@ tools = { Django = { rapidDetect = function(host, port)
local response = http.get(host, port, "/")
if response.body then
if string.find(response.body, "content=[\"']WordPress") or
if string.find(response.body, "content=[\"']WordPress") or
string.find(response.body, "wp%-content") then
return "Wordpress detected. Found common traces on /"
end
@@ -233,7 +233,7 @@ tools = { Django = { rapidDetect = function(host, port)
consumingDetect = function(page, path)
if page then
if string.find(page, "content=[\"']WordPress") or
if string.find(page, "content=[\"']WordPress") or
string.find(page, "wp%-content") then
return "Wordpress detected. Found common traces on " .. page
end
@@ -249,7 +249,7 @@ tools = { Django = { rapidDetect = function(host, port)
if response.body then
if string.find(response.body, "content=[\"']Joomla!") then
return "Joomla detected. Found common traces on /"
return "Joomla detected. Found common traces on /"
end
end
@@ -264,7 +264,7 @@ tools = { Django = { rapidDetect = function(host, port)
consumingDetect = function(page, path)
if page and string.find(page, "content=[\"']Joomla!") then
return "Joomla detected. Found common traces on " .. page
return "Joomla detected. Found common traces on " .. page
end
end
},
@@ -283,7 +283,7 @@ tools = { Django = { rapidDetect = function(host, port)
consumingDetect = function(page, path)
if page and string.find(page, "content=[\"']Drupal") then
return "Drupal detected. Found common traces on " .. page
return "Drupal detected. Found common traces on " .. page
end
end
},
@@ -294,7 +294,7 @@ tools = { Django = { rapidDetect = function(host, port)
local response = http.get(host, port, "/")
if response.body then
if string.find(response.body, "content=[\"']MediaWiki") or
if string.find(response.body, "content=[\"']MediaWiki") or
string.find(response.body, "/mediawiki/") then
return "MediaWiki detected. Found common traces on /"
end
@@ -304,7 +304,7 @@ tools = { Django = { rapidDetect = function(host, port)
consumingDetect = function(page, path)
if page and string.find(page, "content=[\"']MediaWiki") or
string.find(page, "/mediawiki/") then
return "MediaWiki detected. Found common traces on " .. page
return "MediaWiki detected. Found common traces on " .. page
end
end
},
@@ -316,7 +316,7 @@ tools = { Django = { rapidDetect = function(host, port)
if response.cookies then
for _, c in pairs(response.cookies) do
if c.name == "cfid" or c.name == "cftoken" then
return "ColdFusion detected. Found " .. c.name .. " cookie."
return "ColdFusion detected. Found " .. c.name .. " cookie."
end
end
end
@@ -334,7 +334,7 @@ tools = { Django = { rapidDetect = function(host, port)
if response.cookies then
for _, c in pairs(response.cookies) do
if string.find(c.name, "bv_") then
return "Broadvision detected. Found " .. c.name .. " cookie."
return "Broadvision detected. Found " .. c.name .. " cookie."
end
end
end
@@ -352,7 +352,7 @@ tools = { Django = { rapidDetect = function(host, port)
if response.cookies then
for _, c in pairs(response.cookies) do
if string.find(c.name, "wc_") then
return "WebSphere Commerce detected. Found " .. c.name .. " cookie."
return "WebSphere Commerce detected. Found " .. c.name .. " cookie."
end
end
end

View File

@@ -14,17 +14,17 @@ local table = require "table"
-- This file is released under the Nmap license; see:
-- http://nmap.org/book/man-legal.html
--
-- @args http-fingerprints.nikto-db-path Looks at the given path for nikto database.
-- It then converts the records in nikto's database into our Lua table format
-- and adds them to our current fingerprints if they don't exist already.
-- @args http-fingerprints.nikto-db-path Looks at the given path for nikto database.
-- It then converts the records in nikto's database into our Lua table format
-- and adds them to our current fingerprints if they don't exist already.
-- Unfortunately, our current implementation has some limitations:
-- * It doesn't support records with more than one 'dontmatch' patterns for
-- a probe.
-- * It doesn't support logical AND for the 'match' patterns.
-- * It doesn't support sending additional headers for a probe.
-- That means, if a nikto fingerprint needs one of the above features, it
-- won't be loaded. At the time of writing this, 6546 out of the 6573 Nikto
-- fingerprints are being loaded successfully. This runtime Nikto fingerprint integration was suggested by Nikto co-author Chris Sullo as described at http://seclists.org/nmap-dev/2013/q4/292
-- That means, if a nikto fingerprint needs one of the above features, it
-- won't be loaded. At the time of writing this, 6546 out of the 6573 Nikto
-- fingerprints are being loaded successfully. This runtime Nikto fingerprint integration was suggested by Nikto co-author Chris Sullo as described at http://seclists.org/nmap-dev/2013/q4/292
--
-- Although this format was originally modeled after the Nikto format, that ended
-- up being too restrictive. The current format is a simple Lua table. There are many
@@ -11804,7 +11804,7 @@ table.insert(fingerprints, {
method = 'HEAD'
},
{
path = '/sitecore/admin/unlock_admin.aspx', -- disabled per default in 6.2.0 (rev.100507)
path = '/sitecore/admin/unlock_admin.aspx', -- disabled per default in 6.2.0 (rev.100507)
method = 'HEAD'
},
{
@@ -11862,12 +11862,12 @@ if f then
if not string.match(l, "^#.*") then
record = {}
for field in string.gmatch(l, "\"(.-)\",") do
-- Grab every attribute and create a record.
if field then
string.gsub(field, '%%', '%%%%')
string.gsub(field, '%%', '%%%%')
table.insert(record, field)
end
end
@@ -11892,7 +11892,7 @@ if f then
-- record[2]: OSVDB-ID
-- record[3]: Server Type
-- record[4]: URI
-- record[5]: HTTP Method
-- record[5]: HTTP Method
-- record[6]: Match 1
-- record[7]: Match 1 (Or)
-- record[8]: Match1 (And)
@@ -11903,11 +11903,11 @@ if f then
-- record[13]: Headers
-- Is this a valid record? Atm, with our current format we need
-- to skip some nikto records. See NSEDoc for more info.
if not exists
-- to skip some nikto records. See NSEDoc for more info.
if not exists
and record[4]
and record[8] == "" and record[10] == "" and record[12] == ""
and record[8] == "" and record[10] == "" and record[12] == ""
and (tonumber(record[4]) == nil or (tonumber(record[4]) and record[4] == "200")) then
-- Our current format does not support HTTP code matching.
@@ -11930,11 +11930,11 @@ if f then
}
-- If there is a second match, add it.
if record[7] and record[7] ~= "" then
if record[7] and record[7] ~= "" then
table.insert(nikto_fingerprint.matches, { match = record[7], output = record[11] })
end
table.insert(fingerprints, nikto_fingerprint)
table.insert(fingerprints, nikto_fingerprint)
end
end

View File

@@ -147,7 +147,7 @@ table.insert(fingerprints, {
fingerprint = '^f4ed19e0c114eb516faaac0ee37daf2807b4381f000000010000138d........00000000........'
});
-- Catch all Checkpoint
-- Catch all Checkpoint
table.insert(fingerprints, {
category = 'vendor',
vendor = 'Checkpoint VPN-1 / Firewall-1',
@@ -161,7 +161,7 @@ table.insert(fingerprints, {
--------------------------------------------------------------------------------
-- Cisco
-- Cisco
--------------------------------------------------------------------------------
table.insert(fingerprints, {
category = 'vendor',
@@ -226,7 +226,7 @@ table.insert(fingerprints, {
--------------------------------------------------------------------------------
-- Fortinet
-- Fortinet
--------------------------------------------------------------------------------
table.insert(fingerprints, {
category = 'vendor',
@@ -241,7 +241,7 @@ table.insert(fingerprints, {
--------------------------------------------------------------------------------
-- FreeS/WAN
-- FreeS/WAN
--------------------------------------------------------------------------------
table.insert(fingerprints, {
category = 'vendor',
@@ -521,7 +521,7 @@ table.insert(fingerprints, {
version = nil,
ostype = nil,
devicetype = nil,
cpe = nil,
cpe = nil,
fingerprint = '^7003cbc1097dbe9c2600ba6983bc8b35'
});
@@ -553,7 +553,7 @@ table.insert(fingerprints, {
--------------------------------------------------------------------------------
-- Microsoft
-- Microsoft
-- http://msdn.microsoft.com/en-us/library/cc233476.aspx
--------------------------------------------------------------------------------
table.insert(fingerprints, {
@@ -659,7 +659,7 @@ table.insert(fingerprints, {
--------------------------------------------------------------------------------
-- Nortel Contivity / Nortel VPN router
-- Nortel Contivity / Nortel VPN router
-- The last byte might be a version ?
-- From ike-scan:
--- 00000004, 00000005, 00000007, 00000009, 0000000a
@@ -692,7 +692,7 @@ table.insert(fingerprints, {
--------------------------------------------------------------------------------
-- Openswan
-- Openswan
--------------------------------------------------------------------------------
table.insert(fingerprints, {
category = 'vendor',
@@ -791,7 +791,7 @@ table.insert(fingerprints, {
ostype = nil,
devicetype = nil,
cpe = nil,
fingerprint = '^5b362bc820f60007' -- (Maybe NSA?, SonicOS Enhanced 4.2?)
fingerprint = '^5b362bc820f60007' -- (Maybe NSA?, SonicOS Enhanced 4.2?)
});
table.insert(fingerprints, {
@@ -1879,7 +1879,7 @@ table.insert(fingerprints, {
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Attribute: Misc fingerprints
-- not directly usable for fingerprinting
-- not directly usable for fingerprinting
-- but can be used for guessing
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
@@ -2348,7 +2348,7 @@ table.insert(fingerprints, {
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- vid_order:
-- vid_order:
-- By examining the ordering of the VIDs, some assumptions can be made
-- Currently only has support for Cisco
@@ -2419,7 +2419,7 @@ table.insert(fingerprints, {
-- Cisco Unity, XAUTH, IKE Fragmentation, Cisco VPN Concentrator
});
--[[ Probably too
--[[ Probably too
table.insert(fingerprints, {
category = 'vid_ordering',
vendor = 'Cisco',
@@ -2436,11 +2436,11 @@ table.insert(fingerprints, {
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- header_ordering:
-- header_ordering:
-- For possible future use
--- Cisco
-- 1: SA, VID, VID, VID, VID, KeyExchange, ID, Nonce, Hash
-- 1: SA, VID, VID, VID, VID, KeyExchange, ID, Nonce, Hash
-- 2: SA, KeyExchange, Nonce, ID, Hash, VID, VID, VID, VID, VID, VID
-- 3: SA, KeyExchange, Nonce, ID, Hash, VID, VID, VID, VID, VID

View File

@@ -1,7 +1,7 @@
---This config file is designed for adding a backdoor to the system. It has a few
-- options by default, only one enabled by default. I suggest
-- options by default, only one enabled by default. I suggest
--
-- Note that none of these modules are included with Nmap by default.
-- Note that none of these modules are included with Nmap by default.
-- Any variable in the 'config' table in smb-psexec.nse can be overriden in the
-- 'overrides' table. Most of them are not really recommended, such as the host,
@@ -17,7 +17,7 @@ local mod
-- a response
mod = {}
mod.upload = false
mod.name = "Adding a user account: $username/$password"
mod.name = "Adding a user account: $username/$password"
mod.program = "net"
mod.args = "user $username $password /add"
mod.maxtime = 2

View File

@@ -1,10 +1,10 @@
---This is the default configuration file. It simply runs some built-in Window
-- programs to gather information about the remote system. It's intended to be
-- simple, demonstrate some of the concepts, and not break/alte anything.
-- programs to gather information about the remote system. It's intended to be
-- simple, demonstrate some of the concepts, and not break/alte anything.
-- Any variable in the 'config' table in smb-psexec.nse can be overriden in the
-- 'overrides' table. Most of them are not really recommended, such as the host,
-- Any variable in the 'config' table in smb-psexec.nse can be overriden in the
-- 'overrides' table. Most of them are not really recommended, such as the host,
-- key, etc.
overrides = {}
--overrides.timeout = 40
@@ -13,7 +13,7 @@ modules = {}
local mod
-- Get the Windows version. For some reason we can't run this directly, but it works ok
-- if we run it through cmd.exe.
-- if we run it through cmd.exe.
mod = {}
mod.upload = false
mod.name = "Windows version"
@@ -24,7 +24,7 @@ mod.noblank = true
table.insert(modules, mod)
-- Grab the ip and mac address(es) from ipconfig. The output requires quite a bit of cleanup
-- to end up being usable and pretty.
-- to end up being usable and pretty.
mod = {}
mod.upload = false
mod.name = "IP Address and MAC Address from 'ipconfig.exe'"
@@ -47,7 +47,7 @@ mod.remove = {"User accounts for", "The command completed", "%-%-%-%-%
mod.noblank = true
table.insert(modules, mod)
-- Get the list of accounts in the 'administrators' group.
-- Get the list of accounts in the 'administrators' group.
mod = {}
mod.upload = false
mod.name = "Membership of 'administrators' from 'net localgroup administrators'"
@@ -58,9 +58,9 @@ mod.remove = {"The command completed", "%-%-%-%-%-%-%-%-%-%-%-", "Memb
mod.noblank = true
table.insert(modules, mod)
-- Try and ping back to our host. This helps check if there's a firewall in the way for connecting backwards.
-- Try and ping back to our host. This helps check if there's a firewall in the way for connecting backwards.
-- Interestingly, in my tests against Windows 2003, ping gives weird output (but still, more or less, worked)
-- when the SystemRoot environmental variable wasn't set.
-- when the SystemRoot environmental variable wasn't set.
mod = {}
mod.upload = false
mod.name = "Can the host ping our address?"
@@ -69,10 +69,10 @@ mod.args = "-n 1 $lhost"
mod.maxtime = 5
mod.remove = {"statistics", "Packet", "Approximate", "Minimum"}
mod.noblank = true
mod.env = "SystemRoot=c:\\WINDOWS"
mod.env = "SystemRoot=c:\\WINDOWS"
table.insert(modules, mod)
-- Try a traceroute back to our host. I limited it to the first 5 hops in the interest of saving time.
-- Try a traceroute back to our host. I limited it to the first 5 hops in the interest of saving time.
-- Like ping, if the SystemRoot variable isn't set, the output is a bit strange (but still works)
mod = {}
mod.upload = false
@@ -85,7 +85,7 @@ mod.noblank = true
mod.env = "SystemRoot=c:\\WINDOWS"
table.insert(modules, mod)
-- Dump the arp cache of the system.
-- Dump the arp cache of the system.
mod = {}
mod.name = "ARP Cache from arp.exe"
mod.program = 'arp.exe'
@@ -105,12 +105,12 @@ mod.maxtime = 1
mod.remove = {"Active"}
mod.noblank = true
mod.env = "SystemRoot=c:\\WINDOWS"
table.insert(modules, mod)
table.insert(modules, mod)
-- Get the routing table.
-- Get the routing table.
--
-- Like 'ver', this has to be run through cmd.exe. This also requires the 'PATH' variable to be
-- set properly, so it isn't going to work against systems with odd paths.
-- Like 'ver', this has to be run through cmd.exe. This also requires the 'PATH' variable to be
-- set properly, so it isn't going to work against systems with odd paths.
mod = {}
mod.upload = false
mod.name = "Full routing table from 'netstat -nr'"
@@ -131,7 +131,7 @@ mod.maxtime = 5
table.insert(modules, mod)
-- Get the drive configuration. For same (insane?) reason, it uses NULL characters instead of spaces
-- for the response, so we have to do a replaceent.
-- for the response, so we have to do a replaceent.
mod = {}
mod.upload = false
mod.name = "Drive list (for more info, try adding --script-args=config=drives,drive=C:)"

View File

@@ -1,7 +1,7 @@
---This configuration file pulls info about a given harddrive
-- Any variable in the 'config' table in smb-psexec.nse can be overriden in the
-- 'overrides' table. Most of them are not really recommended, such as the host,
-- Any variable in the 'config' table in smb-psexec.nse can be overriden in the
-- 'overrides' table. Most of them are not really recommended, such as the host,
-- key, etc.
overrides = {}
--overrides.timeout = 40

View File

@@ -1,7 +1,7 @@
---This configuration file contains the examples given in smb-psexec.nse.
---This configuration file contains the examples given in smb-psexec.nse.
-- Any variable in the 'config' table in smb-psexec.nse can be overriden in the
-- 'overrides' table. Most of them are not really recommended, such as the host,
-- Any variable in the 'config' table in smb-psexec.nse can be overriden in the
-- 'overrides' table. Most of them are not really recommended, such as the host,
-- key, etc.
overrides = {}
overrides.timeout = 40
@@ -42,7 +42,7 @@ mod.program = "ping.exe"
mod.args = "$lhost"
mod.remove = {"statistics", "Packet", "Approximate", "Minimum"}
mod.noblank = true
mod.env = "SystemRoot=c:\\WINDOWS"
mod.env = "SystemRoot=c:\\WINDOWS"
table.insert(modules, mod)
mod = {}
@@ -52,7 +52,7 @@ mod.program = "ping.exe"
mod.args = "$host"
mod.remove = {"statistics", "Packet", "Approximate", "Minimum"}
mod.noblank = true
mod.env = "SystemRoot=c:\\WINDOWS"
mod.env = "SystemRoot=c:\\WINDOWS"
mod.req_args = {'host'}
table.insert(modules, mod)

View File

@@ -1,9 +1,9 @@
---This is the configuration file for modules that aren't quite ready for prime
-- time yet.
-- time yet.
-- Any variable in the 'config' table in smb-psexec.nse can be overriden in the
-- 'overrides' table. Most of them are not really recommended, such as the host,
-- Any variable in the 'config' table in smb-psexec.nse can be overriden in the
-- 'overrides' table. Most of them are not really recommended, such as the host,
-- key, etc.
overrides = {}
--overrides.timeout = 40

View File

@@ -1,7 +1,7 @@
---More verbose network scripts
-- Any variable in the 'config' table in smb-psexec.nse can be overriden in the
-- 'overrides' table. Most of them are not really recommended, such as the host,
-- Any variable in the 'config' table in smb-psexec.nse can be overriden in the
-- 'overrides' table. Most of them are not really recommended, such as the host,
-- key, etc.
overrides = {}
--overrides.timeout = 40
@@ -10,7 +10,7 @@ modules = {}
local mod
-- Grab the ip and mac address(es) from ipconfig. The output requires quite a bit of cleanup
-- to end up being usable and pretty.
-- to end up being usable and pretty.
mod = {}
mod.upload = false
mod.name = "IP Address and MAC Address from 'ipconfig.exe'"
@@ -21,7 +21,7 @@ mod.find = {"IP Address", "Physical Address", "Ethernet adapter"}
mod.replace = {{"%. ", ""}, {"-", ":"}, {"Physical Address", "MAC Address"}}
table.insert(modules, mod)
-- Dump the arp cache of the system.
-- Dump the arp cache of the system.
mod = {}
mod.name = "ARP Cache from arp.exe"
mod.program = 'arp.exe'
@@ -41,12 +41,12 @@ mod.maxtime = 1
mod.remove = {"Active"}
mod.noblank = true
mod.env = "SystemRoot=c:\\WINDOWS"
table.insert(modules, mod)
table.insert(modules, mod)
-- Get the routing table.
-- Get the routing table.
--
-- Like 'ver', this has to be run through cmd.exe. This also requires the 'PATH' variable to be
-- set properly, so it isn't going to work against systems with odd paths.
-- Like 'ver', this has to be run through cmd.exe. This also requires the 'PATH' variable to be
-- set properly, so it isn't going to work against systems with odd paths.
mod = {}
mod.upload = false
mod.name = "Full routing table from 'netstat -nr'"
@@ -57,9 +57,9 @@ mod.maxtime = 1
mod.noblank = true
table.insert(modules, mod)
-- Try and ping back to our host. This helps check if there's a firewall in the way for connecting backwards.
-- Try and ping back to our host. This helps check if there's a firewall in the way for connecting backwards.
-- Interestingly, in my tests against Windows 2003, ping gives weird output (but still, more or less, worked)
-- when the SystemRoot environmental variable wasn't set.
-- when the SystemRoot environmental variable wasn't set.
mod = {}
mod.upload = false
mod.name = "Can the host ping our address?"
@@ -68,10 +68,10 @@ mod.args = "-n 1 $lhost"
mod.maxtime = 5
mod.remove = {"statistics", "Packet", "Approximate", "Minimum"}
mod.noblank = true
mod.env = "SystemRoot=c:\\WINDOWS"
mod.env = "SystemRoot=c:\\WINDOWS"
table.insert(modules, mod)
-- Try a traceroute back to our host. I limited it to the first 5 hops in the interest of saving time.
-- Try a traceroute back to our host. I limited it to the first 5 hops in the interest of saving time.
-- Like ping, if the SystemRoot variable isn't set, the output is a bit strange (but still works)
mod = {}
mod.upload = false
@@ -94,7 +94,7 @@ mod.req_args = {'address'}
mod.maxtime = 5
mod.remove = {"statistics", "Packet", "Approximate", "Minimum"}
mod.noblank = true
mod.env = "SystemRoot=c:\\WINDOWS"
mod.env = "SystemRoot=c:\\WINDOWS"
table.insert(modules, mod)
-- Try a traceroute to an address given by the user

View File

@@ -1,7 +1,7 @@
---This config file is designed for running password-dumping scripts. So far,
---This config file is designed for running password-dumping scripts. So far,
-- it supports pwdump6 2.0.0 and fgdump.
--
-- Note that none of these modules are included with Nmap by default.
-- Note that none of these modules are included with Nmap by default.
-- Any variable in the 'config' table in smb-psexec.nse can be overriden in the
-- 'overrides' table. Most of them are not really recommended, such as the host,
@@ -22,7 +22,7 @@ local mod
--mod.url = "http://www.foofus.net/fizzgig/pwdump/"
--table.insert(modules, mod)
---Uncomment if you'd like to use PwDump6 1.7.2 (considered obsolete, but still works).
---Uncomment if you'd like to use PwDump6 1.7.2 (considered obsolete, but still works).
-- Note that for some reason, this and 'fgdump' don't get along (fgdump only produces a blank
-- file if these are run together)
--mod = {}
@@ -36,8 +36,8 @@ local mod
--mod.url = "http://www.foofus.net/fizzgig/pwdump/"
--table.insert(modules, mod)
-- Warning: the danger of using fgdump is that it always write the output to the harddrive unencrypted;
-- this makes it more obvious that an attack has occurred.
-- Warning: the danger of using fgdump is that it always write the output to the harddrive unencrypted;
-- this makes it more obvious that an attack has occurred.
mod = {}
mod.upload = true
mod.name = "FgDump"

View File

@@ -1,6 +1,6 @@
---
-- Read and parse some of Nmap's data files: <code>nmap-protocols</code>,
-- <code>nmap-rpc</code>, <code>nmap-services</code>, and
-- <code>nmap-rpc</code>, <code>nmap-services</code>, and
-- <code>nmap-mac-prefixes</code>.
--
-- The functions in this module return values appropriate for use with exception

View File

@@ -1,9 +1,9 @@
---Implement a Dynamic Host Configuration Protocol (DHCP) client.
---Implement a Dynamic Host Configuration Protocol (DHCP) client.
--
-- DHCP, defined in rfc2132 and rfc2131, is a protocol for hosts to automatically
-- DHCP, defined in rfc2132 and rfc2131, is a protocol for hosts to automatically
-- configure themselves on a network (that is, obtain an ip address). This library,
-- which have a trivial one-function interface, can send out DHCP packets of many
-- types and parse the responses.
-- types and parse the responses.
--
-- @author "Ron Bowes"
@@ -24,7 +24,7 @@ local table = require "table"
_ENV = stdnse.module("dhcp", stdnse.seeall)
request_types =
request_types =
{
DHCPDISCOVER = 1,
DHCPOFFER = 2,
@@ -46,19 +46,19 @@ request_types_str[6] = "DHCPNAK"
request_types_str[7] = "DHCPRELEASE"
request_types_str[8] = "DHCPINFORM"
---Read an IP address or a list of IP addresses. Print an error if the length isn't a multiple of 4.
---Read an IP address or a list of IP addresses. Print an error if the length isn't a multiple of 4.
--
--@param data The packet.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@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)
if(length ~= 4) then
if((length % 4) ~= 0) then
stdnse.print_debug(1, "dhcp-discover: Invalid length for an ip address (%d)", length)
pos = pos + length
return pos, nil
else
local results = {}
@@ -78,24 +78,24 @@ local function read_ip(data, pos, length)
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.
--
--@param data The packet.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@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)
return bin.unpack(string.format("A%d", length), data, pos)
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.
--
--@param data The packet.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@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)
if(length ~= 1) then
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be %d)", length, 1)
@@ -106,13 +106,13 @@ local function read_1_byte(data, pos, length)
end
---Read a message type. This is a single-byte value that's looked up in the <code>request_types_str</code>
-- table. Print an error if the length isn't 1.
-- table. Print an error if the length isn't 1.
--
--@param data The packet.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@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 value
@@ -125,14 +125,14 @@ local function read_message_type(data, pos, length)
return pos, request_types_str[value]
end
---Read a single byte, and return 'false' if it's 0, or 'true' if it's non-zero. Print an error if the
-- length isn't 1.
---Read a single byte, and return 'false' if it's 0, or 'true' if it's non-zero. Print an error if the
-- length isn't 1.
--
--@param data The packet.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@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 result
pos, result = read_1_byte(data, pos, length)
@@ -147,13 +147,13 @@ local function read_boolean(data, pos, length)
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.
--
--@param data The packet.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@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)
if(length ~= 2) then
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be %d)", length, 2)
@@ -165,13 +165,13 @@ end
---Read a list of 2-byte unsigned little endian values. Print an error if the length isn't a multiple
-- of 2.
-- of 2.
--
--@param data The packet.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@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)
if((length % 2) ~= 0) then
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be multiple of %d)", length, 2)
@@ -191,13 +191,13 @@ local function read_2_bytes_list(data, pos, length)
end
---Read a 4-byte unsigned little endian value. Print an error if the length isn't 4.
---Read a 4-byte unsigned little endian value. Print an error if the length isn't 4.
--
--@param data The packet.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@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)
if(length ~= 4) then
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be %d)", length, 4)
@@ -207,14 +207,14 @@ local function read_4_bytes(data, pos, length)
return bin.unpack(">I", data, pos)
end
---Read a 4-byte unsigned little endian value, and interpret it as a time offset value. Print an
-- error if the length isn't 4.
---Read a 4-byte unsigned little endian value, and interpret it as a time offset value. Print an
-- error if the length isn't 4.
--
--@param data The packet.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@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 result
if(length ~= 4) then
@@ -244,14 +244,14 @@ local function read_time(data, pos, length)
return pos, string.format("%d %s, %d:%02d:%02d", days, dayLabel, hours, minutes, seconds)
end
---Read a list of static routes. Each of them are a pair of IP addresses, a destination and a
-- router. Print an error if the length isn't a multiple of 8.
---Read a list of static routes. Each of them are a pair of IP addresses, a destination and a
-- router. Print an error if the length isn't a multiple of 8.
--
--@param data The packet.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@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)
if((length % 8) ~= 0) then
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be multiple of %d)", length, 8)
@@ -271,14 +271,14 @@ local function read_static_route(data, pos, length)
end
end
---Read a list of policy filters. Each of them are a pair of IP addresses, an address and a
-- mask. Print an error if the length isn't a multiple of 8.
---Read a list of policy filters. Each of them are a pair of IP addresses, an address and a
-- mask. Print an error if the length isn't a multiple of 8.
--
--@param data The packet.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@param pos The position in the packet.
--@param length The length that the server claims the field is.
--@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)
if((length % 8) ~= 0) then
stdnse.print_debug(1, "dhcp-discover: Invalid length for data (%d; should be multiple of %d)", length, 8)
@@ -299,7 +299,7 @@ local function read_policy_filter(data, pos, length)
end
---These are the different fields for DHCP. These have to come after the read_* function
-- definitions.
-- definitions.
local actions = {}
actions[1] = {name="Subnet Mask", func=read_ip, default=true}
actions[2] = {name="Time Offset", func=read_4_bytes, default=false}
@@ -364,14 +364,14 @@ actions[60] = {name="Class Identifier", func=read_string,
actions[61] = {name="Client Identifier (client)", func=read_string, default=false}
actions[252]= {name="WPAD", func=read_string, default=false}
--- 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)
-- Send out the packet
return socket:sendto(host, { number=67, protocol="udp" }, packet)
end
local function dhcp_receive(socket, transaction_id)
local status, data = socket:receive()
if ( not(status) ) then
socket:close()
@@ -382,7 +382,7 @@ local function dhcp_receive(socket, transaction_id)
-- generated and different for every instance of a script (to prevent collisions)
while status and data:sub(5, 8) ~= transaction_id do
status, data = socket:receive()
end
end
return status, data
end
@@ -390,32 +390,32 @@ end
--- Builds a DHCP packet
--
--@param request_type The type of request as an integer (use the <code>request_types</code> table at the
-- top of this file).
--@param ip_address Your ip address (as a dotted-decimal string). This tells the DHCP server where to
-- top of this file).
--@param ip_address Your ip address (as a dotted-decimal string). This tells the DHCP server where to
-- send the response. Setting it to "255.255.255.255" or "0.0.0.0" is generally acceptable (if not,
-- host.ip_src can work).
-- host.ip_src can work).
--@param mac_address Your mac address (as a string up to 16 bytes) where the server will send the response. Like
-- <code>ip_address</code>, setting to the broadcast address (FF:FF:FF:FF:FF:FF) is
-- common (host.mac_addr_src works).
-- <code>ip_address</code>, setting to the broadcast address (FF:FF:FF:FF:FF:FF) is
-- common (host.mac_addr_src works).
--@param options [optional] A table of additional request options where each option is a table containing the
-- following fields:
-- * <code>number</code> - The option number
-- * <code>type</code> - The option type ("string" or "ip")
-- * <code>value</code> - The option value
--@param request_options [optional] The options to request from the server, as an array of integers. For the
--@param request_options [optional] The options to request from the server, as an array of integers. For the
-- acceptable options, see the <code>actions</code> table above or have a look at rfc2132.
-- Some DHCP servers (such as my Linksys WRT54g) will ignore this list and send whichever
-- information it wants. Default: all options marked as 'default' in the <code>actions</code>
-- table above are requested (the typical interesting ones) if no verbosity is given.
-- If any level of verbosity is on, get all types.
-- table above are requested (the typical interesting ones) if no verbosity is given.
-- If any level of verbosity is on, get all types.
--@param overrides [optional] A table of overrides. If a field in the table matches a field in the DHCP
-- packet (see rfc2131 section 2 for a list of possible fields), the value in the table
-- will be sent instead of the default value.
--@param lease_time [optional] The lease time used when requestint an IP. Default: 1 second.
-- will be sent instead of the default value.
--@param lease_time [optional] The lease time used when requestint an IP. Default: 1 second.
--@param transaction_id The identity of the transaction.
--
--@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)
local packet = ''
@@ -472,13 +472,13 @@ function dhcp_build(request_type, ip_address, mac_address, options, request_opti
end
---Parse a DHCP packet (either a request or a response) and return the results as a table. The
-- table at the top of this function (<code>actions</code>) defines the name of each field, as
-- laid out in rfc2132, and the function that parses it.
-- table at the top of this function (<code>actions</code>) defines the name of each field, as
-- laid out in rfc2132, and the function that parses it.
--
-- In theory, this should be able to parse any valid DHCP packet.
-- In theory, this should be able to parse any valid DHCP packet.
--
--@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).
--@param data The DHCP packet data. Any padding at the end of the packet will be ignored (by default,
-- DHCP packets are padded with \x00 bytes).
function dhcp_parse(data, transaction_id)
local pos = 1
local result = {}
@@ -555,7 +555,7 @@ function dhcp_parse(data, transaction_id)
end
-- Handle the 'Option Overload' option specially -- if it's set, it tells us to use the file and/or sname values after we
-- run out of data.
-- run out of data.
if(option == 52) then
if(value == 1) then
data = data .. result['file']
@@ -573,7 +573,7 @@ function dhcp_parse(data, transaction_id)
end
---Build and send any kind of DHCP packet, and parse the response. This is the only interface
-- to the DHCP library, and should be the only one necessary.
-- to the DHCP library, and should be the only one necessary.
--
-- All DHCP packet have the same structure, but different fields. It is therefore easy to build
-- any of the possible request types:
@@ -591,30 +591,30 @@ end
-- type. If you're going to build some DHCP code on your own, I recommend reading rfc2131.
--
--@param request_type The type of request as an integer (use the <code>request_types</code> table at the
-- top of this file).
--@param ip_address Your ip address (as a dotted-decimal string). This tells the DHCP server where to
-- top of this file).
--@param ip_address Your ip address (as a dotted-decimal string). This tells the DHCP server where to
-- send the response. Setting it to "255.255.255.255" or "0.0.0.0" is generally acceptable (if not,
-- host.ip_src can work).
-- host.ip_src can work).
--@param mac_address Your mac address (as a string up to 16 bytes) where the server will send the response. Like
-- <code>ip_address</code>, setting to the broadcast address (FF:FF:FF:FF:FF:FF) is
-- common (host.mac_addr_src works).
-- <code>ip_address</code>, setting to the broadcast address (FF:FF:FF:FF:FF:FF) is
-- common (host.mac_addr_src works).
--@param options [optional] A table of additional request options where each option is a table containing the
-- following fields:
-- * <code>number</code> - The option number
-- * <code>type</code> - The option type ("string" or "ip")
-- * <code>value</code> - The option value
--@param request_options [optional] The options to request from the server, as an array of integers. For the
--@param request_options [optional] The options to request from the server, as an array of integers. For the
-- acceptable options, see the <code>actions</code> table above or have a look at rfc2132.
-- Some DHCP servers (such as my Linksys WRT54g) will ignore this list and send whichever
-- information it wants. Default: all options marked as 'default' in the <code>actions</code>
-- table above are requested (the typical interesting ones) if no verbosity is given.
-- If any level of verbosity is on, get all types.
-- table above are requested (the typical interesting ones) if no verbosity is given.
-- If any level of verbosity is on, get all types.
--@param overrides [optional] A table of overrides. If a field in the table matches a field in the DHCP
-- packet (see rfc2131 section 2 for a list of possible fields), the value in the table
-- will be sent instead of the default value.
--@param lease_time [optional] The lease time used when requestint an IP. Default: 1 second.
-- will be sent instead of the default value.
--@param lease_time [optional] The lease time used when requestint an IP. Default: 1 second.
--@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)
-- 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))
@@ -643,7 +643,7 @@ function make_request(target, request_type, ip_address, mac_address, options, re
if ( not(status) ) then
stdnse.print_debug(1, "dhcp: Couldn't receive packet: " .. response)
return false, "Couldn't receive packet: " .. response
end
end
-- Parse the response
local status, parsed = dhcp_parse(response, transaction_id)

View File

@@ -64,9 +64,9 @@ DHCP6.OptionTypes = {
-- DHCP6 options
DHCP6.Option = {
[DHCP6.OptionTypes.OPTION_ELAPSED_TIME] = {
-- Create a new class instance
-- @param time in ms since last request
-- @return o new instance of class
@@ -82,7 +82,7 @@ DHCP6.Option = {
self.__index = self
return o
end,
-- Converts option to a string
-- @return str string containing the class instance as string
__tostring = function(self)
@@ -94,11 +94,11 @@ DHCP6.Option = {
end
return bin.pack(">SP", self.type, data)
end,
},
[DHCP6.OptionTypes.OPTION_CLIENTID] = {
-- Create a new class instance
-- @param mac string containing the mac address
-- @param duid number the duid of the client
@@ -117,7 +117,7 @@ DHCP6.Option = {
self.__index = self
return o
end,
-- Parse the data string and create an instance of the class
-- @param data string containing the data as received over the socket
-- @return opt new instance of option
@@ -133,15 +133,15 @@ DHCP6.Option = {
opt.time = opt.time + os.time({year=2000, day=1, month=1, hour=0, min=0, sec=0})
return opt
end,
-- Converts option to a string
-- @return str string containing the class instance as string
__tostring = function(self)
local data = bin.pack(">SSIA", self.duid, self.hwtype, self.time, self.mac)
return bin.pack(">SP", self.type, data)
end,
end,
},
[DHCP6.OptionTypes.OPTION_SERVERID] = {
-- Create a new class instance
-- @param mac string containing the mac address
@@ -150,7 +150,7 @@ DHCP6.Option = {
-- @param time number time since 2000-01-01 00:00:00
-- @return o new instance of class
new = function(...) return DHCP6.Option[DHCP6.OptionTypes.OPTION_CLIENTID].new(...) end,
-- Parse the data string and create an instance of the class
-- @param data string containing the data as received over the socket
-- @return opt new instance of option
@@ -160,9 +160,9 @@ DHCP6.Option = {
-- @return str string containing the class instance as string
__tostring = function(...) return DHCP6.Option[DHCP6.OptionTypes.OPTION_CLIENTID].__tostring(...) end,
},
[DHCP6.OptionTypes.OPTION_STATUS_CODE] = {
-- Create a new class instance
-- @param code number containing the error code
-- @param msg string containing the error message
@@ -184,15 +184,15 @@ DHCP6.Option = {
parse = function(data)
local opt = DHCP6.Option[DHCP6.OptionTypes.OPTION_STATUS_CODE]:new()
local pos
pos, opt.code, opt.msg = bin.unpack(">SA" .. (#data - 2), data)
return opt
end,
},
[DHCP6.OptionTypes.OPTION_DNS_SERVERS] = {
-- Create a new class instance
-- @param servers table containing DNS servers
-- @return o new instance of class
@@ -212,7 +212,7 @@ DHCP6.Option = {
parse = function(data)
local opt = DHCP6.Option[DHCP6.OptionTypes.OPTION_DNS_SERVERS]:new()
local pos, count = 1, #data/16
for i=1,count do
local srv
pos, srv = bin.unpack(">B16", data, pos)
@@ -220,7 +220,7 @@ DHCP6.Option = {
end
return opt
end,
-- Converts option to a string
-- @return str string containing the class instance as string
__tostring = function(self)
@@ -232,9 +232,9 @@ DHCP6.Option = {
return data
end
},
[DHCP6.OptionTypes.OPTION_DOMAIN_LIST] = {
-- Create a new class instance
-- @param domain table containing the search domains
-- @return o new instance of class
@@ -254,7 +254,7 @@ DHCP6.Option = {
parse = function(data)
local opt = DHCP6.Option[DHCP6.OptionTypes.OPTION_DOMAIN_LIST]:new()
local pos = 1
repeat
local domain = {}
repeat
@@ -269,11 +269,11 @@ DHCP6.Option = {
return opt
end,
},
[DHCP6.OptionTypes.OPTION_IA_PD] = {
-- Create a new class instance
-- @param iad number containing iad
-- @param t1 number containing t1
@@ -292,18 +292,18 @@ DHCP6.Option = {
self.__index = self
return o
end,
-- Converts option to a string
-- @return str string containing the class instance as string
__tostring = function(self)
local data = bin.pack(">IIIA", self.iaid, self.t1, self.t2, self.options)
return bin.pack(">SP", self.type, data)
end,
},
[DHCP6.OptionTypes.OPTION_IA_NA] = {
-- Create a new class instance
-- @param iad number containing iad
-- @param t1 number containing t1
@@ -322,21 +322,21 @@ DHCP6.Option = {
self.__index = self
return o
end,
-- Parse the data string and create an instance of the class
-- @param data string containing the data as received over the socket
-- @return opt new instance of option
parse = function(data)
local opt = DHCP6.Option[DHCP6.OptionTypes.OPTION_IA_NA]:new()
local pos
pos, opt.iaid, opt.t1, opt.t2 = bin.unpack(">III", data)
-- do we have any options
while ( pos < #data ) do
local typ, len, ipv6, pref_lt, valid_lt, options
pos, typ, len = bin.unpack(">SS", data, pos)
if ( 5 == DHCP6.OptionTypes.OPTION_IAADDR ) then
local addr = { type = DHCP6.OptionTypes.OPTION_IAADDR }
pos, addr.ipv6, addr.pref_lt, addr.valid_lt = bin.unpack(">A16II", data, pos)
@@ -344,10 +344,10 @@ DHCP6.Option = {
else
pos = pos + len
end
end
end
return opt
end,
-- Converts option to a string
-- @return str string containing the class instance as string
__tostring = function(self)
@@ -355,9 +355,9 @@ DHCP6.Option = {
-- TODO: we don't cover self.options here, we should probably add that
return bin.pack(">SP", self.type, data)
end,
end,
},
[DHCP6.OptionTypes.OPTION_SNTP_SERVERS] = {
-- Create a new class instance
@@ -372,7 +372,7 @@ DHCP6.Option = {
self.__index = self
return o
end,
-- Parse the data string and create an instance of the class
-- @param data string containing the data as received over the socket
-- @return opt new instance of option
@@ -387,7 +387,7 @@ DHCP6.Option = {
return opt
end,
},
[DHCP6.OptionTypes.OPTION_CLIENT_FQDN] = {
-- Create a new class instance
@@ -402,7 +402,7 @@ DHCP6.Option = {
self.__index = self
return o
end,
-- Parse the data string and create an instance of the class
-- @param data string containing the data as received over the socket
-- @return opt new instance of option
@@ -410,7 +410,7 @@ DHCP6.Option = {
local opt = DHCP6.Option[DHCP6.OptionTypes.OPTION_CLIENT_FQDN]:new()
local pos = 2
local pieces = {}
repeat
local tmp
pos, tmp = bin.unpack("p", data, pos)
@@ -419,14 +419,14 @@ DHCP6.Option = {
opt.fqdn = stdnse.strjoin(".", pieces)
return opt
end,
}
}
DHCP6.Request = {
-- Create a new class instance
-- @param msgtype number containing the message type
-- @param xid number containing the transaction id
@@ -442,13 +442,13 @@ DHCP6.Request = {
self.__index = self
return o
end,
-- Adds a new DHCP6 option to the request
-- @param opt instance of object to add to the request
addOption = function(self, opt)
table.insert(self.opts, opt)
end,
-- Converts option to a string
-- @return str string containing the class instance as string
__tostring = function(self)
@@ -465,7 +465,7 @@ DHCP6.Request = {
-- The Response class handles responses from the server
DHCP6.Response = {
-- Creates a new instance of the response class
-- @param msgtype number containing the type of DHCP6 message
-- @param xid number containing the transaction ID
@@ -479,7 +479,7 @@ DHCP6.Response = {
self.__index = self
return o
end,
-- Parse the data string and create an instance of the class
-- @param data string containing the data as received over the socket
-- @return opt new instance of option
@@ -488,7 +488,7 @@ DHCP6.Response = {
local pos, tmp = bin.unpack(">I", data)
resp.msgtype = bit.band(tmp, 0xFF000000)
resp.msgtype = bit.rshift(resp.msgtype, 24)
resp.msgtype = bit.rshift(resp.msgtype, 24)
resp.xid = bit.band(tmp, 0x00FFFFFF)
while( pos < #data ) do
local opt = {}
@@ -507,7 +507,7 @@ DHCP6.Response = {
end
return resp
end
}
-- Table of option to string converters
@@ -517,7 +517,7 @@ DHCP6.Response = {
-- TODO: These functions could eventually be moved to a method in it's
-- respective class.
OptionToString = {
[DHCP6.OptionTypes.OPTION_CLIENTID] = function(opt)
local HWTYPE_ETHER = 1
if ( HWTYPE_ETHER == opt.hwtype ) then
@@ -527,12 +527,12 @@ OptionToString = {
return "Client identifier", ("MAC: %s; Time: %s"):format(mac, tm)
end
end,
[DHCP6.OptionTypes.OPTION_SERVERID] = function(opt)
local topic, str = OptionToString[DHCP6.OptionTypes.OPTION_CLIENTID](opt)
return "Server identifier", str
end,
[DHCP6.OptionTypes.OPTION_IA_NA] = function(opt)
if ( opt.options and 1 == #opt.options ) then
local ipv6 = opt.options[1].ipv6
@@ -541,7 +541,7 @@ OptionToString = {
return "Non-temporary Address", ipv6
end
end,
[DHCP6.OptionTypes.OPTION_DNS_SERVERS] = function(opt)
local servers = {}
for _, srv in ipairs(opt.servers) do
@@ -550,15 +550,15 @@ OptionToString = {
end
return "DNS Servers", stdnse.strjoin(",", servers)
end,
[DHCP6.OptionTypes.OPTION_DOMAIN_LIST] = function(opt)
return "Domain Search", stdnse.strjoin(", ", opt.domains)
end,
[DHCP6.OptionTypes.OPTION_STATUS_CODE] = function(opt)
return "Error", ("Code: %d; Message: %s"):format(opt.code, opt.msg)
end,
[DHCP6.OptionTypes.OPTION_SNTP_SERVERS] = function(opt)
return "NTP Servers", stdnse.strjoin(", ", opt.servers)
end,
@@ -566,7 +566,7 @@ OptionToString = {
-- The Helper class serves as the main interface to scripts
Helper = {
-- Creates a new Helper class instance
-- @param iface string containing the interface name
-- @param options table containing any options, currently
@@ -579,7 +579,7 @@ Helper = {
}
setmetatable(o, self)
self.__index = self
local info, err = nmap.get_interface_info(iface)
-- if we faile to get interface info, don't return a helper
-- this is true on OS X for interfaces like: p2p0 and vboxnet0
@@ -592,17 +592,17 @@ Helper = {
o.socket:set_timeout(o.options.timeout or 5000)
return o
end,
-- Sends a DHCP6 Solicit message to the server, essentiall requesting a new
-- IPv6 non-temporary address
-- @return table of results suitable for use with
-- @return table of results suitable for use with
-- <code>stdnse.format_output</code>
solicit = function(self)
local req = DHCP6.Request:new( DHCP6.Type.SOLICIT )
local option = DHCP6.Option
req:addOption(option[DHCP6.OptionTypes.OPTION_ELAPSED_TIME]:new())
req:addOption(option[DHCP6.OptionTypes.OPTION_CLIENTID]:new(self.mac))
local iaid = select(2, bin.unpack(">I", self.mac:sub(3)))
req:addOption(option[DHCP6.OptionTypes.OPTION_IA_NA]:new(iaid, 3600, 5400))
@@ -624,7 +624,7 @@ Helper = {
return false, "Failed to receive DHCP6 request from server"
end
resp = DHCP6.Response.parse(data)
resp = DHCP6.Response.parse(data)
if ( not(resp) ) then
return false, "Failed to decode DHCP6 response from server"
end
@@ -636,7 +636,7 @@ Helper = {
local result, result_options = {}, { name = "Options" }
local resptype = DHCP6.TypeStr[resp.msgtype] or ("Unknown (%d)"):format(resp.msgtype)
table.insert(result, ("Message type: %s"):format(resptype))
table.insert(result, ("Transaction id: %d"):format(resp.xid))
@@ -652,7 +652,7 @@ Helper = {
end
table.insert(result, result_options)
return true, result
end,
end,
}

View File

@@ -257,7 +257,7 @@ end
-- * <code>subnet</code>: table, if set perform a edns-client-subnet lookup. The table should contain the fields:
-- <code>family</code> - string can be either inet or inet6
-- <code>address</code> - string containing the originating subnet IP address
-- <code>mask</code> - number containing the number of subnet bits
-- <code>mask</code> - number containing the number of subnet bits
-- @return <code>true</code> if a dns response was received and contained an answer of the requested type,
-- or the decoded dns response was requested (retPkt) and is being returned - or <code>false</code> otherwise.
-- @return String answer of the requested type, table of answers or a String error message of one of the following:
@@ -1055,10 +1055,10 @@ decoder[types.NSEC3] = function (entry, data, pos)
entry.NSEC3.dname = entry.dname
entry.NSEC3.salt, entry.NSEC3.hash = {}, {}
np, entry.NSEC3.hash.alg,flags,entry.NSEC3.iterations = bin.unpack(">CBS", data, np)
np, entry.NSEC3.hash.alg,flags,entry.NSEC3.iterations = bin.unpack(">CBS", data, np)
-- do we even need to decode these do we care about opt out?
-- entry.NSEC3.flags = decodeFlagsNSEC3(flags)
np, entry.NSEC3.salt.bin = bin.unpack(">p", data, np)
_, entry.NSEC3.salt.hex = bin.unpack("H" .. #entry.NSEC3.salt.bin, entry.NSEC3.salt.bin)
@@ -1156,7 +1156,7 @@ decoder[types.TXT] =
-- @param entry RR in packet.
-- @param data Complete encoded DNS packet.
-- @param pos Position in packet after RR.
decoder[types.OPT] =
decoder[types.OPT] =
function(entry, data, pos)
local np = pos - #entry.data - 6
local opt = { bufsize = entry.class }
@@ -1367,14 +1367,14 @@ end
-- @param client_subnet table containing the following fields
-- <code>family</code> - 1 IPv4, 2 - IPv6
-- <code>mask</code> - byte containing the length of the subnet mask
-- <code>address</code> - string containing the IP address
-- <code>address</code> - string containing the IP address
function addClientSubnet(pkt,Z,subnet)
local udp_payload_size = 4096
local code = 20730 -- temporary option-code http://comments.gmane.org/gmane.ietf.dnsext/19776
local scope_mask = 0 -- In requests, it MUST be set to 0 see draft
local data = bin.pack(">SCCA",subnet.family or 1,subnet.mask,scope_mask,ipOps.ip_to_str(subnet.address))
local opt = bin.pack(">SS",code, #data) .. data
addOPT(pkt,Z,opt)
addOPT(pkt,Z,opt)
end
---
@@ -1384,7 +1384,7 @@ end
function addNSID (pkt,Z)
local udp_payload_size = 4096
local opt = bin.pack(">SS",3, 0) -- nsid data
addOPT(pkt,Z,opt)
addOPT(pkt,Z,opt)
end
---

View File

@@ -49,7 +49,7 @@ _ENV = stdnse.module("dnsbl", stdnse.seeall)
-- the TXT record, this argument and check can be omitted.
-- When the short mode is used, the function should return a table containing
-- the <code>state</code> field, or nil if the IP wasn't listed. When long
-- mode is used, the function should return additional information using the
-- mode is used, the function should return additional information using the
-- <code>details</code> field. Eg:
-- return { state = "SPAM" } -- short mode
-- return { state = "PROXY", details = {
@@ -69,11 +69,11 @@ _ENV = stdnse.module("dnsbl", stdnse.seeall)
-- and description of the arguments that provide the configuration/options.
-- If this function isn't specified, the library will assume the service
-- doesn't require configuration.
--
--
SERVICES = {
SPAM = {
["dnsbl.inps.de"] = {
-- This service supports both long and short <code>mode</code>
ns_type = {
@@ -114,7 +114,7 @@ SERVICES = {
end,
},
["spam.dnsbl.sorbs.net"] = {
["spam.dnsbl.sorbs.net"] = {
ns_type = {
["short"] = "A"
},
@@ -144,7 +144,7 @@ SERVICES = {
return ( r[1] and responses[r[1]] ) and { state = responses[r[1]] }
end,
},
["all.spamrats.com"] = {
new = function(self, ip, mode, config)
local o = { ip = ip, mode = mode, config = config }
@@ -160,7 +160,7 @@ SERVICES = {
return ( r[1] and responses[r[1]] ) and { state = responses[r[1]] }
end,
},
["list.quorum.to"] = {
new = function(self, ip, mode, config)
local o = { ip = ip, mode = mode, config = config }
@@ -172,11 +172,11 @@ SERVICES = {
-- this service appears to return 127.0.0.0 when the service is
-- "blocked because it has never been seen to send mail".
-- This would essentially return every host as SPAM and we
-- don't want that.
return ( ( r[1] and r[1] ~= "127.0.0.0" ) and { state = "SPAM" } )
-- don't want that.
return ( ( r[1] and r[1] ~= "127.0.0.0" ) and { state = "SPAM" } )
end
},
["sbl.spamhaus.org"] = {
new = function(self, ip, mode, config)
local o = { ip = ip, mode = mode, config = config }
@@ -190,9 +190,9 @@ SERVICES = {
["127.0.0.3"] = "SPAM",
}
return ( r[1] and responses[r[1]] ) and { state = responses[r[1]] }
end,
end,
},
["bl.spamcop.net"] = {
new = function(self, ip, mode, config)
local o = { ip = ip, mode = mode, config = config }
@@ -207,7 +207,7 @@ SERVICES = {
return ( r[1] and responses[r[1]] ) and { state = responses[r[1]] }
end,
},
["dnsbl.ahbl.org"] = {
new = function(self, ip, mode, config)
local o = { ip = ip, mode = mode, config = config }
@@ -226,7 +226,7 @@ SERVICES = {
return ( r[1] and responses[r[1]] ) and { state = responses[r[1]] }
end,
},
["l2.apews.org"] = {
new = function(self, ip, mode, config)
local o = { ip = ip, mode = mode, config = config }
@@ -241,11 +241,11 @@ SERVICES = {
return ( r[1] and responses[r[1]] ) and { state = responses[r[1]] }
end,
},
},
PROXY = {
["dnsbl.tornevall.org"] = {
new = function(self, ip, mode, config)
local o = { ip = ip, mode = mode, config = config }
@@ -275,12 +275,12 @@ SERVICES = {
if ( bit.band( code, k ) == k ) then
table.insert(result, v)
end
end
end
return { state = "PROXY", details = result }
end
end
end,
},
["ip-port.exitlist.torproject.org"] = {
configuration = {
["port"] = "the port to which the target can relay to",
@@ -364,7 +364,7 @@ SERVICES = {
end
end,
},
["dnsbl.ahbl.org"] = {
new = function(self, ip, mode, config)
local o = { ip = ip, mode = mode, config = config }
@@ -379,7 +379,7 @@ SERVICES = {
return ( r[1] and responses[r[1]] ) and { state = responses[r[1]] }
end,
},
["http.dnsbl.sorbs.net"] = {
new = function(self, ip, mode, config)
local o = { ip = ip, mode = mode, config = config }
@@ -394,7 +394,7 @@ SERVICES = {
return ( r[1] and responses[r[1]] ) and { state = responses[r[1]] }
end,
},
["socks.dnsbl.sorbs.net"] = {
new = function(self, ip, mode, config)
local o = { ip = ip, mode = mode, config = config }
@@ -409,7 +409,7 @@ SERVICES = {
return ( r[1] and responses[r[1]] ) and { state = responses[r[1]] }
end,
},
["misc.dnsbl.sorbs.net"] = {
new = function(self, ip, mode, config)
local o = { ip = ip, mode = mode, config = config }
@@ -424,7 +424,7 @@ SERVICES = {
return ( r[1] and responses[r[1]] ) and { state = responses[r[1]] }
end,
}
},
ATTACK = {
@@ -485,7 +485,7 @@ SERVICES = {
}
local result = {}
-- Search engines are a special case.
if ( octet4 == 0 ) then
table.insert(result, ("Search engine: %s"):format(
@@ -495,7 +495,7 @@ SERVICES = {
octet2))
table.insert(result, ("Threat score: %i"):format(
octet3))
local activity = {}
activity['name'] = "Activity"
-- Suspicious activity
@@ -512,7 +512,7 @@ SERVICES = {
if ( bit.band(octet4, 4) == 4) then
table.insert(activity, "Comment spammer")
end
table.insert(result, activity)
end
@@ -558,13 +558,13 @@ SERVICES = {
end,
}
},
}
Helper = {
-- Creates a new Helper instance
-- @param category string containing a valid DNSBL service category
-- @param mode string (short|long) specifying whether short or long
@@ -577,7 +577,7 @@ Helper = {
self.__index = self
return o
end,
-- Lists all DNSBL services for the category
-- @return services table of service names
listServices = function(self)
@@ -597,19 +597,19 @@ Helper = {
table.insert(services, name)
end
end
return services
return services
end,
-- Validates the filter set by setFilter to make sure it contains only
-- valid service names.
-- @return status boolean, true on success false on failure
-- @return err string containing an error message on failure
validateFilter = function(self)
if ( not(self.filterstr) ) then
return true
end
local all = SERVICES[self.category]
self.filter = {}
for _, f in pairs(stdnse.strsplit(",%s*", self.filterstr)) do
@@ -621,19 +621,19 @@ Helper = {
end
return true
end,
-- Sets a new service filter to choose only a limited subset of services
-- within a category.
-- @param filter string containing a comma separated list of service names
setFilter = function(self, filter) self.filterstr = filter end,
-- Gets a list of filtered services, or all services if no filter is in use
-- @return services table containing a list of services
getServices = function(self)
if ( not(self:validateFilter()) ) then
return nil
end
if ( self.filter ) then
local filtered = {}
for name, svc in pairs(SERVICES[self.category]) do
@@ -646,7 +646,7 @@ Helper = {
return SERVICES[self.category]
end
end,
doQuery = function(self, ip, name, svc, answers)
local condvar = nmap.condvar(answers)
@@ -676,10 +676,10 @@ Helper = {
else
stdnse.print_debug("Query function returned nothing, skipping '%s'", name)
end
condvar "signal"
end,
-- Runs the DNS blacklist check for the given IP against all non-filtered
-- services in the given category.
-- @param ip string containing the IP address to check
@@ -687,7 +687,7 @@ Helper = {
checkBL = function(self, ip)
local result, answers, threads = {}, {}, {}
local condvar = nmap.condvar(answers)
for name, svc in pairs(self:getServices()) do
local co = stdnse.new_thread(self.doQuery, self, ip, name, svc, answers)
threads[co] = true
@@ -701,7 +701,7 @@ Helper = {
condvar "wait"
end
until( next(threads) == nil )
for name, answer in pairs(answers) do
local status, answer, svc = answer.status, answer.answer, answer.svc
if ( status ) then
@@ -710,7 +710,7 @@ Helper = {
local resp = ( #answer > 0 and ("UNKNOWN (%s)"):format(answer[1]) or "UNKNOWN" )
stdnse.print_debug(2, ("%s received %s"):format(name, resp))
end
if ( svc_result ) then
table.insert(result, { name = name, result = svc_result })
end

View File

@@ -21,7 +21,7 @@
-- helper:setMulticast(true)
-- return stdnse.format_output(helper:queryServices())
-- </code>
--
--
-- This next snipplet queries a specific host for the same information:
-- <code>
-- local helper = dnssd.Helper:new( host, port )
@@ -57,7 +57,7 @@ Util = {
ipCompare = function(a, b)
return ipOps.compare_ip(a, "lt", b)
end,
--- Function used to compare discovered DNS services so they can be sorted
--
-- @param a table containing first item
@@ -74,8 +74,8 @@ Util = {
end
return false
end,
--- Creates a service host table
--- Creates a service host table
--
-- ['_ftp._tcp.local'] = {10.10.10.10,20.20.20.20}
-- ['_http._tcp.local'] = {30.30.30.30,40.40.40.40}
@@ -96,7 +96,7 @@ Util = {
return services
end,
--- Creates a unique list of services
--
-- @param response containing a single or multiple responses from
@@ -104,7 +104,7 @@ Util = {
-- @return array of strings containing service names
getUniqueServices = function( response )
local services = {}
for _, r in ipairs(response) do
if ( r.output ) then
for _, svc in ipairs(r.output) do services[svc] = true end
@@ -112,10 +112,10 @@ Util = {
services[r] = true
end
end
return services
end,
--- Returns the amount of currenlty active threads
--
-- @param threads table containing the list of threads
@@ -132,7 +132,7 @@ Util = {
end
return count
end
}
Comm = {
@@ -189,7 +189,7 @@ Comm = {
queryService = function( host, port, svc, multiple, svcresponse )
local condvar = nmap.condvar(svcresponse)
local status, response = dns.query( svc, { port = port, host = host, dtype="PTR", retPkt=true, retAll=true, multiple=multiple, sendCount=1, timeout=2000} )
if not status then
if not status then
stdnse.print_debug("Failed to query service: %s; Error: %s", svc, response)
return
end
@@ -266,7 +266,7 @@ Comm = {
table.insert( result, service )
end
end,
--- Query the mDNS resolvers for a list of their services
--
-- @param host table as received by the action function
@@ -286,7 +286,7 @@ Comm = {
end
return dns.query( "_services._dns-sd._udp.local", { port = port, host = ( host.ip or host ), dtype="PTR", retAll=true, multiple=multiple, sendCount=sendCount, timeout=timeout } )
end,
}
Helper = {
@@ -305,8 +305,8 @@ Helper = {
o.mcast = false
return o
end,
--- Instructs the helper to use unconnected sockets supporting multicast
--
-- @param mcast boolean true if multicast is to be used, false otherwise
@@ -314,12 +314,12 @@ Helper = {
assert( type(mcast)=="boolean", "mcast has to be either true or false")
self.mcast = mcast
end,
--- Performs a DNS-SD query against a host
--
-- @param host table as received by the action function
-- @param port number specifying the port to connect to
-- @param service string or table with the service(s) to query eg.
-- @param service string or table with the service(s) to query eg.
-- _ssh._tcp.local, _afpovertcp._tcp.local
-- if nil defaults to _services._dns-sd._udp.local (all)
-- @param mcast boolean true if a multicast query is to be done
@@ -333,7 +333,7 @@ Helper = {
local family = nmap.address_family()
local host = mcast and (family=="inet6" and "ff02::fb" or "224.0.0.251") or self.host
local service = service or stdnse.get_script_args('dnssd.services')
if ( not(service) ) then
status, response = Comm.queryAllServices( host, port, mcast )
if ( not(status) ) then return status, response end
@@ -346,12 +346,12 @@ Helper = {
end
response = Util.getUniqueServices(response)
local svcresponse = {}
local condvar = nmap.condvar( svcresponse )
local threads = {}
for svc in pairs(response) do
for svc in pairs(response) do
local co = stdnse.new_thread( Comm.queryService, (host.ip or host), port, svc, mcast, svcresponse )
threads[co] = true
end
@@ -374,7 +374,7 @@ Helper = {
Comm.decodeRecords( response, result )
end
end
if ( mcast ) then
-- Restructure and build our output table
for ip, svctbl in pairs( ipsvctbl ) do
@@ -387,10 +387,10 @@ Helper = {
else
-- sort the tables per port
table.sort( result, Util.serviceCompare )
end
end
return true, result
end,
}
return _ENV;

View File

@@ -39,7 +39,7 @@
-- </code>
--
-- The implementation is based on packet dumps and the excellent decoding
-- provided by Wireshark.
-- provided by Wireshark.
--
-- There is some documentation at
-- http://publib.boulder.ibm.com/infocenter/dzichelp/v2r2/topic/com.ibm.db29.doc.drda/db2z_drda.htm.
@@ -119,7 +119,7 @@ SecMec =
}
DRDAPacket = {
new = function(self, drda_array)
local o = {
drda_array = drda_array,
@@ -137,11 +137,11 @@ DRDAPacket = {
end
end
end,
getDRDA = function( self, n )
return ( #self.drda_array >= n ) and self.drda_array[n] or nil
end,
__tostring = function( self )
local data = ""
-- do some DDM fixup in here
@@ -156,12 +156,12 @@ DRDAPacket = {
end
return data
end
}
-- Distributed Relational Database Architecture (DRDA) Class
DRDA = {
new = function(self, ddm)
local o = {
Parameters = {},
@@ -171,8 +171,8 @@ DRDA = {
self.__index = self
return o
end,
--- Sets the DDM
--- Sets the DDM
--
-- @param ddm DDM to assign to the DRDA
-- @return status boolean true on success, false on failure
@@ -183,7 +183,7 @@ DRDA = {
self.DDM = ddm
return true
end,
--- Adds a DRDA parameter to the table
--
-- @param param DRDAParam containing the parameter to add to the table
@@ -198,16 +198,16 @@ DRDA = {
stdnse.print_debug("drda.DRDA.addParameter: Param cannot be nil")
return false, "Param cannot be nil"
end
table.insert(self.Parameters, param)
-- update the DDM length fields
self.DDM.Length = self.DDM.Length + param.Length
self.DDM.Length2 = self.DDM.Length2 + param.Length
return true
end,
--- Gets a parameter from the DRDA parameter table
--
-- @param codepoint number containing the parameter type ro retrieve
@@ -217,26 +217,26 @@ DRDA = {
if ( v.CodePoint == codepoint ) then
return v
end
end
end
return
end,
--- Converts the DRDA class to a string
--
-- @return data containing the object instance
-- @return data containing the object instance
__tostring = function(self)
if ( not(self.DDM) ) then
stdnse.print_debug("drda.DRDA.toString: DDM cannot be nil")
return nil
end
local data = bin.pack(">SCCSSS", self.DDM.Length, self.DDM.Magic, self.DDM.Format, self.DDM.CorelId, self.DDM.Length2, self.DDM.CodePoint )
for k,v in ipairs(self.Parameters) do
data = data .. tostring(v)
end
return data
end,
--- Sends the DRDA over the db2socket
--
-- @param db2socket DB2Socket over which to send the data
@@ -245,27 +245,27 @@ DRDA = {
send = function( self, db2socket )
return db2socket:send( tostring(self) )
end,
--- Receives data from the db2socket and builds a DRDA object
--
-- @param db2socket from which to read data
-- @return Status (true or false).
-- @return Data (if status is true) or error string (if status is false).
-- @return Data (if status is true) or error string (if status is false).
receive = function( self, db2socket )
local DDM_SIZE = 10
local pos = 1
-- first read atleast enough so that we can populate the DDM
local status, data = db2socket:receive_buf( match.numbytes(DDM_SIZE), true )
if ( not(status) ) then
stdnse.print_debug("drda.DRDA.receive: %s", data)
return false, ("Failed to read at least %d bytes from socket"):format(DDM_SIZE)
end
local ddm = DDM:new()
ddm:fromString( data )
self:setDDM( ddm )
status, data = db2socket:receive_buf( match.numbytes(ddm.Length - 10), true )
if ( not(status) ) then
return false, ("Failed to read the remaining %d bytes of the DRDA message")
@@ -277,7 +277,7 @@ DRDA = {
pos = param:fromString( data, pos )
self:addParameter( param )
until ( #data <= pos )
return true
end,
@@ -285,12 +285,12 @@ DRDA = {
-- The DRDAParameter class implements the DRDA parameters
DRDAParameter = {
--- DRDA Parameter constructor
--
-- @param codepoint number containing the codepoint value
-- @param data string containing the data portion of the DRDA parameter
-- @return o DRDAParameter object
-- @return o DRDAParameter object
new = function(self, codepoint, data)
local o = {
CodePoint = codepoint,
@@ -306,13 +306,13 @@ DRDAParameter = {
--
-- @return data string containing the DRDA Parameter
__tostring = function( self )
local data = bin.pack(">SS", self.Length, self.CodePoint )
local data = bin.pack(">SS", self.Length, self.CodePoint )
if ( self.Data ) then
data = data .. bin.pack("A", self.Data)
end
return data
end,
--- Builds a DRDA Parameter from a string
--
-- @param data string from which to build the DRDA Parameter
@@ -332,14 +332,14 @@ DRDAParameter = {
end
return pos
end,
--- Returns the data portion of the parameter as an ASCII string
--
-- @return str containing the data portion of the DRDA parameter as ASCII
getDataAsASCII = function( self )
return StringUtil.toASCII( self.Data )
end,
--- Returns the data in EBCDIC format
--
-- @return str containing the data portion of the DRDA parameter in EBCDIC
@@ -351,7 +351,7 @@ DRDAParameter = {
-- Distributed data management (DDM)
DDM = {
Formats =
{
RESERVED = 0x80,
@@ -359,7 +359,7 @@ DDM = {
CONTINUE = 0x20,
SAME_CORRELATION = 0x10,
},
Length = 10,
Magic = 0xD0,
Format = 0x41,
@@ -388,32 +388,32 @@ DDM = {
__tostring = function( self )
return bin.pack(">SCCSSS", self.Length, self.Magic, self.Format, self.CorelId, self.Length2, self.CodePoint)
end,
--- Constructs a DDM object from a string
--
-- @param str containing the data from which to construct the object
fromString = function( self, str )
local DDM_SIZE = 10
local pos = 1
if ( #str < DDM_SIZE ) then
return -1, ("drda.DDM.fromString: str was less than DDM_SIZE (%d)"):format( DDM_SIZE )
end
pos, self.Length, self.Magic, self.Format, self.CorelId, self.Length2, self.CodePoint = bin.unpack( ">SCCSSS", str )
return pos
end,
--- Verifiers if there are additional DRDA's following
--
-- @return true if the DRDA is to be chained, false if it's the last one
-- @return true if the DRDA is to be chained, false if it's the last one
isChained = function( self )
if ( bit.band( self.Format, DDM.Formats.CHAINED ) == DDM.Formats.CHAINED ) then
return true
end
return false
end,
--- Set the DRDA as chained (more following)
--
-- @param chained boolean true if more DRDA's are following
@@ -424,11 +424,11 @@ DDM = {
self.Format = bit.bor( self.Format, self.Formats.CHAINED )
end
end,
}
-- static DRDA packet construction class
Command =
Command =
{
--- Builds an EXCSAT DRDA packet
--
@@ -440,7 +440,7 @@ Command =
-- @return drda DRDA instance
EXCSAT = function( extname, srvname, rellev, mgrlvlls, srvclass )
local drda = DRDA:new( DDM:new( CodePoint.EXCSAT ) )
drda:addParameter( DRDAParameter:new( CodePoint.EXTNAM, StringUtil.toEBCDIC( extname ) ) )
drda:addParameter( DRDAParameter:new( CodePoint.SRVNAM, StringUtil.toEBCDIC( srvname ) ) )
drda:addParameter( DRDAParameter:new( CodePoint.SRVRLSLV, StringUtil.toEBCDIC( rellev ) ) )
@@ -449,7 +449,7 @@ Command =
return drda
end,
--- Builds an ACCSEC DRDA packet
--
-- @param secmec number containing the security mechanism ID
@@ -459,7 +459,7 @@ Command =
local drda = DRDA:new( DDM:new( CodePoint.ACCSEC ) )
drda:addParameter( DRDAParameter:new( CodePoint.SECMEC, secmec ))
drda:addParameter( DRDAParameter:new( CodePoint.RDBNAM, StringUtil.toEBCDIC(StringUtil.padWithChar(database,' ', 18)) ))
return drda
end,
@@ -469,17 +469,17 @@ Command =
-- @param database string containing the database name
-- @param username string
-- @param password string
-- @return drda DRDA instance
-- @return drda DRDA instance
SECCHK = function( secmec, database, username, password )
local drda = DRDA:new( DDM:new( CodePoint.SECCHK ) )
drda:addParameter( DRDAParameter:new( CodePoint.SECMEC, secmec ))
drda:addParameter( DRDAParameter:new( CodePoint.RDBNAM, StringUtil.toEBCDIC(StringUtil.padWithChar(database,' ', 18)) ))
drda:addParameter( DRDAParameter:new( CodePoint.USRID, StringUtil.toEBCDIC(username) ) )
drda:addParameter( DRDAParameter:new( CodePoint.PASSWORD, StringUtil.toEBCDIC(password) ) )
return drda
end,
--- Builds an ACCRDB DRDA packet
--
-- @param database string containing the database name
@@ -487,7 +487,7 @@ Command =
-- @param prdid string containing the product id
-- @param typdefnam string containing the data type definition name
-- @param typdefovr string containing the data type definition override
-- @return drda DRDA instance
-- @return drda DRDA instance
ACCRDB = function( database, rdbaccl, prdid, prddata, typdefnam, crrtkn, typdefovr )
local drda = DRDA:new( DDM:new( CodePoint.ACCRDB ) )
drda:addParameter( DRDAParameter:new( CodePoint.RDBNAM, StringUtil.toEBCDIC(StringUtil.padWithChar(database,' ', 18)) ) )
@@ -510,10 +510,10 @@ Command =
if( typdefovr ) then
drda:addParameter( DRDAParameter:new( CodePoint.TYPDEFOVR, typdefovr ) )
end
return drda
end
}
@@ -526,13 +526,13 @@ Helper = {
self.__index = self
return o
end,
--- Connect to the DB2 host
--
-- @param host table
-- @param port table
-- @return Status (true or false).
-- @return Error code (if status is false).
-- @return Error code (if status is false).
connect = function( self, host, port )
self.comm = Comm:new( host, port )
return self.comm:connect()
@@ -541,23 +541,23 @@ Helper = {
--- Closes an open connection.
--
-- @return Status (true or false).
-- @return Error code (if status is false).
-- @return Error code (if status is false).
close = function( self )
self.comm:close()
end,
--- Returns Server Information (name, platform, version)
--
-- @return table containing <code>extname</code>, <code>srvclass</code>,
-- @return table containing <code>extname</code>, <code>srvclass</code>,
-- <code>srvname</code> and <code>prodrel</code>
getServerInfo = function( self )
local mgrlvlls = bin.pack("H", "1403000724070008240f00081440000814740008")
local drda_excsat = Command.EXCSAT( "", "", "", mgrlvlls, "" )
local response, param, err
local status, packet = self.comm:exchDRDAPacket( DRDAPacket:new( { drda_excsat } ) )
if ( not(status) ) then return false, err end
local drda = packet:getDRDAByCodePoint( CodePoint.EXCSATRD )
if ( drda ) then
response = {}
@@ -578,12 +578,12 @@ Helper = {
response.prodrel = param:getDataAsASCII()
end
else
return false, "The response contained no EXCSATRD"
return false, "The response contained no EXCSATRD"
end
return true, response
return true, response
end,
--- Login to DB2 database server
--
-- @param database containing the name of the database
@@ -596,37 +596,37 @@ Helper = {
local secmec, prdid = "\00\03", "JCC03010"
local tdovr = bin.pack("H", "0006119c04b80006119d04b00006119e04b8")
local crrtkn= bin.pack("H", "d5c6f0f0f0f0f0f14bc3c6f4c4012a11168414")
local drda_excsat = Command.EXCSAT( "", "", "", mgrlvlls, "" )
local drda_accsec = Command.ACCSEC( secmec, database )
local drda_secchk = Command.SECCHK( secmec, database, username, password )
local drda_accrdb = Command.ACCRDB( database, string.char(0x24,0x07), "DNC10060", nil, "QTDSQLASC", crrtkn, tdovr)
local status, packet = self.comm:exchDRDAPacket( DRDAPacket:new( { drda_excsat, drda_accsec } ) )
if( not(status) ) then return false, packet end
if ( packet:getDRDAByCodePoint( CodePoint.RDBNFNRM ) or
packet:getDRDAByCodePoint( CodePoint.RDBAFLRM ) ) then
stdnse.print_debug("drda.Helper.login: ERROR: RDB not found")
return false, "ERROR: Database not found"
end
local drda = packet:getDRDAByCodePoint( CodePoint.ACCSECRD )
if ( not(drda) ) then
return false, "ERROR: Response did not contain any valid security mechanisms"
end
local param = drda:getParameter( CodePoint.SECMEC )
if ( not(param) ) then
stdnse.print_debug("drda.Helper.login: ERROR: Response did not contain any valid security mechanisms")
return false, "ERROR: Response did not contain any valid security mechanisms"
end
if ( select(2, bin.unpack(">S", param:getData())) ~= SecMec.USER_PASSWORD ) then
stdnse.print_debug("drda.Helper.login: ERROR: Securite Mechanism not supported")
return false, "ERROR: Security mechanism not supported"
end
status, packet = self.comm:exchDRDAPacket( DRDAPacket:new( { drda_secchk, drda_accrdb } ) )
if( not(status) ) then return false, "ERROR: Login failed" end
@@ -657,12 +657,12 @@ Helper = {
end
return false, "ERROR: Login failed"
end,
}
-- The communication class
Comm = {
new = function(self, host, port)
local o = {
host = host,
@@ -673,18 +673,18 @@ Comm = {
self.__index = self
return o
end,
connect = function(self)
return self.socket:connect(self.host, self.port)
end,
close = function(self)
return self.socket:close()
end,
recvDRDA = function( self )
local drda_tbl = {}
repeat
local drda = DRDA:new()
local status, err = drda:receive( self.socket )
@@ -695,7 +695,7 @@ Comm = {
until ( not(drda.DDM:isChained()) )
return true, drda_tbl
end,
--- Sends a packet to the server and receives the response
--
-- @param DRDAPacket
@@ -704,12 +704,12 @@ Comm = {
exchDRDAPacket = function( self, packet )
local drda, err
local status, err = self.socket:send( tostring(packet) )
if ( not(status) ) then
stdnse.print_debug("drda.Helper.login: ERROR: DB2Socket error: %s", err )
return false, ("ERROR: DB2Socket error: %s"):format( err )
end
status, drda = self:recvDRDA()
if( not(status) ) then
stdnse.print_debug("drda.Helper.login: ERROR: DB2Socket error: %s", drda )
@@ -717,7 +717,7 @@ Comm = {
end
return true, DRDAPacket:new( drda )
end
}
-- EBCDIC/ASCII Conversion tables
@@ -766,7 +766,7 @@ StringUtil =
-- @return string containing ASCII value
toASCII = function( ebcdic )
local ret = ""
for i=1, #ebcdic do
local val = ebcdic.byte(ebcdic,i) + 1
ret = ret .. e2a_tbl:sub(val, val)

View File

@@ -1,4 +1,4 @@
---
---
-- EAP (Extensible Authentication Protocol) library supporting a
-- limited subset of features.
--
@@ -16,8 +16,8 @@
-- <code>
-- pcap:pcap_open(iface.device, 512, true, "ether proto 0x888e")
-- ...
-- local _, _, l2_data, l3_data, _ = pcap:pcap_receive()
-- local packet = eap.parse(l2_data .. l3_data3)
-- local _, _, l2_data, l3_data, _ = pcap:pcap_receive()
-- local packet = eap.parse(l2_data .. l3_data3)
-- if packet then
-- if packet.eap.type == eap.eap_t.IDENTITY and packet.eap.code == eap.code_t.REQUEST then
-- eap.send_identity_response(iface, packet.eap.id, "anonymous")
@@ -74,7 +74,7 @@ code_t = {
}
code_str = {
[1] = "Request",
[1] = "Request",
[2] = "Response",
[3] = "Success",
[4] = "Failure",
@@ -155,13 +155,13 @@ eap_str = {
local make_eapol = function (arg)
if not arg.type then arg.type = eapol_t.PACKET end
if not arg.version then arg.version = 1 end
if not arg.payload then arg.payload = "" end
if not arg.payload then arg.payload = "" end
if not arg.src then return nil end
local p = packet.Frame:new()
p.mac_src = arg.src
p.mac_dst = packet.mactobin(ETHER_BROADCAST)
p.ether_type = ETHER_TYPE_EAPOL
p.ether_type = ETHER_TYPE_EAPOL
local bin_payload = bin.pack(">A",arg.payload)
p.buf = bin.pack("C",arg.version) .. bin.pack("C",arg.type) .. bin.pack(">S",bin_payload:len()).. bin_payload
@@ -179,14 +179,14 @@ local make_eap = function (arg)
local bin_payload = bin.pack(">A",arg.payload)
arg.header.payload = bin.pack("C",arg.code) .. bin.pack("C",arg.id) .. bin.pack(">S",bin_payload:len() + EAP_HEADER_SIZE).. bin.pack("C",arg.type) .. bin_payload
local v = make_eapol(arg.header)
stdnse.print_debug(2, "make eapol %s", arg.header.src)
return v
end
parse = function (packet)
parse = function (packet)
local tb = {}
local _
@@ -199,14 +199,14 @@ parse = function (packet)
-- parsing eapol header
_, tb.version, tb.type, tb.length = bin.unpack(">CCS", packet, ETHER_HEADER_SIZE + 1)
stdnse.print_debug(1, "mac_src: %s, mac_dest: %s, ether_type: 0x%X",
stdnse.print_debug(1, "mac_src: %s, mac_dest: %s, ether_type: 0x%X",
tb.mac_src_str, tb.mac_dst_str, tb.ether_type)
if tb.ether_type ~= ETHER_TYPE_EAPOL_N then return nil, "not an eapol packet" end
if tb.ether_type ~= ETHER_TYPE_EAPOL_N then return nil, "not an eapol packet" end
stdnse.print_debug(2, "version: %X, type: %s, length: 0x%X",
stdnse.print_debug(2, "version: %X, type: %s, length: 0x%X",
tb.version, eapol_str[tb.type] or "unknown",
tb.length)
tb.length)
tb.eap = {}
@@ -214,7 +214,7 @@ parse = function (packet)
-- parsing body
_, tb.eap.code, tb.eap.id, tb.eap.length, tb.eap.type = bin.unpack(">CCSC", packet,
ETHER_HEADER_SIZE + EAPOL_HEADER_SIZE + 1)
ETHER_HEADER_SIZE + EAPOL_HEADER_SIZE + 1)
stdnse.print_debug(2, "code: %s, id: 0x%X, length: 0x%X, type: %s",
code_str[tb.eap.code] or "unknown",
tb.eap.id, tb.eap.length, eap_str[tb.eap.type] or "unknown" )
@@ -233,7 +233,7 @@ parse = function (packet)
end
if tb.length > 5 and tb.eap.type == eap_t.MD5 then
_, tb.eap.body.challenge = bin.unpack("p", packet, ETHER_HEADER_SIZE + EAPOL_HEADER_SIZE + EAP_HEADER_SIZE + 1)
_, tb.eap.body.challenge = bin.unpack("p", packet, ETHER_HEADER_SIZE + EAPOL_HEADER_SIZE + EAP_HEADER_SIZE + 1)
end
return tb
@@ -244,9 +244,9 @@ send_identity_response = function (iface, id, identity)
if not iface then
stdnse.print_debug(1, "no interface given")
return
end
end
local dnet = nmap.new_dnet()
local dnet = nmap.new_dnet()
local tb = {src = iface.mac, type = eapol_t.PACKET}
local response = make_eap{header = tb, code = code_t.RESPONSE, type = eap_t.IDENTITY, id = id, payload = identity}
@@ -260,9 +260,9 @@ send_nak_response = function (iface, id, auth)
if not iface then
stdnse.print_debug(1, "no interface given")
return
end
end
local dnet = nmap.new_dnet()
local dnet = nmap.new_dnet()
local tb = {src = iface.mac, type = eapol_t.PACKET}
local response = make_eap{header = tb, code = code_t.RESPONSE, type = eap_t.NAK, id = id, payload = bin.pack("C",auth)}
@@ -273,19 +273,19 @@ end
send_start = function (iface)
if not iface then
stdnse.print_debug(1, "no interface given")
return
end
local dnet = nmap.new_dnet()
local start = make_eapol{type = eapol_t.START, src = iface.mac}
local start = make_eapol{type = eapol_t.START, src = iface.mac}
dnet:ethernet_open(iface.device)
dnet:ethernet_send(start)
dnet:ethernet_close()
end
return _ENV;

View File

@@ -70,7 +70,7 @@ EIGRP = {
-- @param Checksum integer EIGRP packet checksum. Calculated automatically
-- if not manually set.
-- @param Table TLVs table.
-- @return o Instance of EIGRP
-- @return o Instance of EIGRP
new = function(self, opcode, as, routerid, flags, seq, ack, checksum, tlvs)
local o = {
ver = 2,
@@ -253,7 +253,7 @@ EIGRP = {
-- @return status true if tlvtype is a routing information tlv.
isRoutingTLV = function(tlvtype)
if tlvtype == 0x101 or tlvtype == 0x102
or tlvtype == 0x103 or tlvtype == 0x104
or tlvtype == 0x103 or tlvtype == 0x104
or tlvtype == 0x402 or tlvtype == 0x403
or tlvtype == 0x404 then
return true
@@ -273,7 +273,7 @@ EIGRP = {
--- Sets the EIGRP packet checksum
-- @param integer checksum Checksum to set.
setChecksum = function(self, checksum)
self.checksum = checksum
self.checksum = checksum
end,
--- Sets the EIGRP packet flags field.
-- @param flags Flags integer value.
@@ -288,19 +288,19 @@ EIGRP = {
--- Sets the EIGRP Packet acknowledge field.
-- @param ack EIGRP acknowledge.
setAcknowledge = function(self, ack)
self.ack = ack
self.ack = ack
end,
--- Sets the EIGRP Packet Virtual Router ID.
--- Sets the EIGRP Packet Virtual Router ID.
-- @param routerid EIGRP Virtual Router ID.
setRouterID = function(self, routerid)
self.routerid = routerid
self.routerid = routerid
end,
--- Sets the EIGRP Packet Autonomous System.
-- @param as EIGRP A.S.
setAS = function(self, as)
self.as = as
end,
--- Sets the EIGRP Packet tlvs
--- Sets the EIGRP Packet tlvs
-- @param tlvs table of EIGRP tlvs.
setTlvs = function(self, tlvs)
self.tlvs = tlvs
@@ -314,7 +314,7 @@ EIGRP = {
-- If checksum not manually.
-- set to 0, then calculate it later
if self.checksum then
data = data .. bin.pack(">S", self.checksum)
data = data .. bin.pack(">S", self.checksum)
else
data = data .. bin.pack(">S", 0x0000) -- Calculated later.
end
@@ -322,7 +322,7 @@ EIGRP = {
data = data .. bin.pack(">I", self.seq) -- Sequence 0
data = data .. bin.pack(">I", self.ack) -- Acknowledge 0
data = data .. bin.pack(">S", self.routerid) -- Virtual Router ID 0
data = data .. bin.pack(">S", self.as) -- Autonomous system
data = data .. bin.pack(">S", self.as) -- Autonomous system
for _, tlv in pairs(self.tlvs) do
if tlv.type == TLV.PARAM then
data = data .. bin.pack(">S", TLV.PARAM)

View File

@@ -2,15 +2,15 @@
-- Formula functions for various calculations.
--
-- The library lets scripts to use common mathematical functions to compute percentages,
-- averages, entropy, randomness and other calculations. Scripts that generate statistics
-- averages, entropy, randomness and other calculations. Scripts that generate statistics
-- and metrics can also make use of this library.
--
-- Functions included:
--
-- <code>calcPwdEntropy</code> - Calculate the entropy of a password. A random
-- password's information entropy, H, is given by the formula: H = L * (logN) / (log2),
-- where N is the number of possible symbols and L is the number of symbols in the
-- password. Based on https://en.wikipedia.org/wiki/Password_strength
-- password's information entropy, H, is given by the formula: H = L * (logN) / (log2),
-- where N is the number of possible symbols and L is the number of symbols in the
-- password. Based on https://en.wikipedia.org/wiki/Password_strength
--
-- <code>looksRandom</code> - Returns true if the value looks random.
--

View File

@@ -24,7 +24,7 @@
-- - A helper class that provides easy access to the rest of the library
--
-- o Socket
-- - This is a copy of the DB2Socket class which provides fundamental
-- - This is a copy of the DB2Socket class which provides fundamental
-- buffering
--
--
@@ -66,24 +66,24 @@ _ENV = stdnse.module("giop", stdnse.seeall)
-- A bunch of constants
Constants = {
SyncScope = {
WITH_TARGET = 3,
},
ServiceContext = {
CODESETS = 1,
SENDING_CONTEXT_RUNTIME = 6,
NEO_FIRST_SERVICE_CONTEXT = 1313165056,
},
ReplyStatus = {
SYSTEM_EXCEPTION = 2,
},
VERSION_1_0 = 1,
VERSION_1_2 = 0x0201,
NAMESERVICE = "NameService\0",
}
@@ -91,7 +91,7 @@ Constants = {
Packet = {}
Packet.GIOP = {
magic = "GIOP",
version = 0x0001,
byte_order = 0,
@@ -110,19 +110,19 @@ Packet.GIOP = {
o.size = data and #data or 0
return o
end,
--- Converts the class to a string suitable to send over the socket
--
-- @return string containing the instance data
-- @return string containing the instance data
__tostring = function( self )
return bin.pack("<ASCC>IA", self.magic, self.version, self.byte_order, self.type, self.size, self.data )
end,
--- Sets the packet version
--
-- @param version number containing the version to use
setVersion = function( self, version ) self.version = version end,
--- Receives the packet over the socket
--
-- @param socket containing the already connected socket
@@ -131,14 +131,14 @@ Packet.GIOP = {
recv = function( self, socket )
local status, data = socket:recv( 12 )
local pos
if ( not(status) ) then return false, "Failed to read Packet.GIOP" end
pos, self.magic, self.version, self.byte_order,
pos, self.magic, self.version, self.byte_order,
self.type = bin.unpack("<A4SCC", data )
pos, self.size = bin.unpack( ( self.byte_order == 0 and ">" or "<") .. "I", data, pos )
status, data = socket:recv( self.size )
if ( not(status) ) then return false, "Failed to read Packet.GIOP" end
@@ -164,10 +164,10 @@ ServiceContext = {
o.pad = pad
return o
end,
--- Converts the class to a string suitable to send over the socket
--
-- @return string containing the instance data
-- @return string containing the instance data
__tostring = function( self )
if ( self.pad ) then
return bin.pack(">IIAS", self.id, #self.data, self.data, self.pad)
@@ -178,7 +178,7 @@ ServiceContext = {
}
--- Creates a SendingContextRuntime
SendingContextRuntime =
SendingContextRuntime =
{
--- Creates a SendingContextRuntime
--
@@ -188,12 +188,12 @@ SendingContextRuntime =
local o = {}
setmetatable(o, self)
self.__index = self
o.data = bin.pack(">HIAH",
[[
o.data = bin.pack(">HIAH",
[[
000000000000002849444c3a6f6d672e6f72672f53656e64696e67436f6e746
578742f436f6465426173653a312e300000000001000000000000006e000102
00
]], #lhost + 1, lhost .. "\0",
]], #lhost + 1, lhost .. "\0",
[[
00ec5100000019afabcb000000000249765d6900000008000000000000000014
0000000000000200000001000000200000000000010001000000020501000100
@@ -201,15 +201,15 @@ SendingContextRuntime =
]] )
return o
end,
--- Converts the class to a string suitable to send over the socket
--
-- @return string containing the instance data
-- @return string containing the instance data
__tostring = function( self ) return self.data end,
}
Packet.GIOP.reply = {
--- Creates a new Packet.GIOP.reply instance
--
-- @return obj a new Packet.GIOP.get instance
@@ -221,7 +221,7 @@ Packet.GIOP.reply = {
self.GIOP = Packet.GIOP:new()
return o
end,
--- Receives a Packet.GIOP.reply from the socket
--
-- @param socket already connected to the server
@@ -231,7 +231,7 @@ Packet.GIOP.reply = {
local status, err = self.GIOP:recv( socket )
local pos, tmp
local bo = ( self.GIOP.byte_order == 0 and ">" or "<")
if( not(status) ) then return false, err end
if ( self.GIOP.version == Constants.VERSION_1_2 ) then
@@ -248,24 +248,24 @@ Packet.GIOP.reply = {
if ( i ~= tmp ) then pos = pos + 2 end
table.insert( self.sc, ServiceContext:new( ctx_id, ctx_data ) )
end
if ( self.GIOP.version == Constants.VERSION_1_0 ) then
pos, self.request_id, self.reply_status, self.stub_data = bin.unpack( bo .. "IIA" .. ( #self.GIOP.data - pos - 8 ), self.GIOP.data, pos )
elseif ( pos < #self.GIOP.data ) then
pos, self.data = bin.unpack("A" .. (#self.GIOP.data - pos), self.GIOP.data, pos )
end
return true
end,
}
Packet.GIOP.get = {
resp_expected = 1,
key_length = 4,
princ_len = 0,
--- Creates a new Packet.GIOP._is_a instance
--
-- @param id the packet identifier
@@ -283,21 +283,21 @@ Packet.GIOP.get = {
o.sc = {}
return o
end,
--- Creates and adds a service context to the packet
--
-- @param id number containing the context id
-- @param data the service context data
-- @param pad [optional] number used to pad after the service context
addServiceContext = function( self, id, data, pad ) table.insert( self.sc, ServiceContext:new(id, data, pad) ) end,
--- Converts the class to a string suitable to send over the socket
--
-- @return string containing the packet data
-- @return string containing the packet data
__tostring = function( self )
local data = bin.pack(">I", #self.sc)
local pad = 0
for i=1, #self.sc do
local tmp = tostring( self.sc[i])
data = data .. bin.pack("A", tmp )
@@ -308,12 +308,12 @@ Packet.GIOP.get = {
return tostring( Packet.GIOP:new( 0, data ) )
end,
}
Packet.GIOP._is_a =
{
--- Creates a new Packet.GIOP._is_a instance
--
-- @param id the packet identifier
@@ -326,46 +326,46 @@ Packet.GIOP._is_a =
self.__index = self
o.op = "_is_a\0"
o.id = id
o.target_addr = 0 -- KeyAddr
o.target_addr = 0 -- KeyAddr
o.key_addr = key_addr
o.flags = flags or Constants.SyncScope.WITH_TARGET -- SyncScope WITH_TARGET
o.sc = {}
return o
end,
--- Creates and adds a service context to the packet
--
-- @param id number containing the context id
-- @param data the service context data
-- @param pad [optional] number used to pad after the service context
addServiceContext = function( self, id, data, pad ) table.insert( self.sc, ServiceContext:new(id, data, pad) ) end,
--- Converts the class to a string suitable to send over the socket
--
-- @return string containing the packet data
-- @return string containing the packet data
__tostring = function( self )
local TYPE_ID = "IDL:omg.org/CosNaming/NamingContextExt:1.0\0"
local RESERVED = 0
local UNKNOWN, UNKNOWN2, UNKNOWN3 = 2, 1, 0
local data = bin.pack(">ICCCCSSIAIASI", self.id, self.flags, RESERVED, RESERVED, RESERVED, self.target_addr,
UNKNOWN, #self.key_addr, self.key_addr, #self.op, self.op, UNKNOWN2, #self.sc )
for i=1, #self.sc do
local tmp = tostring( self.sc[i])
data = data .. bin.pack("A", tmp )
end
data = data .. bin.pack(">IA", #TYPE_ID, TYPE_ID)
local packet = Packet.GIOP:new( 0, data )
packet:setVersion( Constants.VERSION_1_2 )
return tostring( packet )
return tostring( packet )
end,
}
Packet.GIOP.list =
Packet.GIOP.list =
{
--- Creates a new Packet.GIOP.list instance
--
@@ -387,7 +387,7 @@ Packet.GIOP.list =
o.sc = {}
return o
end,
--- Creates and adds a service context to the packet
--
-- @param id number containing the context id
@@ -397,33 +397,33 @@ Packet.GIOP.list =
--- Converts the class to a string suitable to send over the socket
--
-- @return string containing the packet data
-- @return string containing the packet data
__tostring = function( self )
local RESERVED = 0
local UNKNOWN, UNKNOWN2, UNKNOWN3 = 2, 1, 6
local data = bin.pack(">ICCCCSSIAIACCCI", self.id, self.flags, RESERVED, RESERVED,
RESERVED, self.target_addr, UNKNOWN, #self.key_addr, self.key_addr,
RESERVED, self.target_addr, UNKNOWN, #self.key_addr, self.key_addr,
#self.op, self.op, RESERVED, RESERVED, UNKNOWN2, #self.sc )
for i=1, #self.sc do
local tmp = tostring( self.sc[i])
data = data .. bin.pack("A", tmp )
end
data = data .. bin.pack(">II", UNKNOWN3, self.how_many )
local packet = Packet.GIOP:new( 0, data )
packet:setVersion( Constants.VERSION_1_2 )
return tostring( packet )
end,
}
-- A socket implementation that provides fundamental buffering and allows for
-- reading of an exact number of bytes, instead of atleast ...
Socket =
{
{
new = function(self, socket)
local o = {}
setmetatable(o, self)
@@ -438,7 +438,7 @@ Socket =
if (not(status)) then return false, "Error failed to get socket information" end
return true, lhost
end,
--- Establishes a connection.
--
-- @param hostid Hostname or IP address.
@@ -450,7 +450,7 @@ Socket =
local status = self.Socket:set_timeout(10000)
return self.Socket:connect( hostid, port, protocol )
end,
--- Closes an open connection.
--
-- @return Status (true or false).
@@ -458,7 +458,7 @@ Socket =
close = function( self )
return self.Socket:close()
end,
--- Opposed to the <code>socket:receive_bytes</code> function, that returns
-- at least x bytes, this function returns the amount of bytes requested.
--
@@ -468,9 +468,9 @@ Socket =
-- err containing error message if status is false
recv = function( self, count )
local status, data
self.Buffer = self.Buffer or ""
if ( #self.Buffer < count ) then
status, data = self.Socket:receive_bytes( count - #self.Buffer )
if ( not(status) or #data < count - #self.Buffer ) then
@@ -478,13 +478,13 @@ Socket =
end
self.Buffer = self.Buffer .. data
end
data = self.Buffer:sub( 1, count )
self.Buffer = self.Buffer:sub( count + 1)
return true, data
return true, data
end,
--- Sends data over the socket
--
-- @return Status (true or false).
@@ -496,10 +496,10 @@ Socket =
-- Static class containing various message decoders
MessageDecoder = {
--- Decodes a get response
--
-- @param packet the GIOP packet as recieved by the comm
-- @param packet the GIOP packet as recieved by the comm
-- <code>exchGIOPPacket</code> function
-- @return status true on success, false on failure
-- @return table containing <code>ip</code> and <code>ctx</code>
@@ -507,7 +507,7 @@ MessageDecoder = {
local bo = ( packet.GIOP.byte_order == 0 and ">" or "<")
local pos, len = bin.unpack(bo .. "I", packet.stub_data)
local ip, ctx
pos = pos + len + 16
pos, len = bin.unpack(bo .. "I", packet.stub_data, pos)
@@ -516,13 +516,13 @@ MessageDecoder = {
pos = pos + 3
pos, len = bin.unpack(bo .. "I", packet.stub_data, pos)
pos, ctx = bin.unpack( bo .. "A" .. len, packet.stub_data, pos)
return true, { ip = ip, ctx = ctx}
end,
--- Decodes a _is_a response (not implemented)
--
-- @param packet the GIOP packet as recieved by the comm
-- @param packet the GIOP packet as recieved by the comm
-- <code>exchGIOPPacket</code> function
-- @return status, always true
["_is_a"] = function( packet )
@@ -531,7 +531,7 @@ MessageDecoder = {
--- Decodes a list response
--
-- @param packet the GIOP packet as recieved by the comm
-- @param packet the GIOP packet as recieved by the comm
-- <code>exchGIOPPacket</code> function
-- @return status true on success, false on failure
-- @return table containing <code>id</code>, <code>kind</code> and
@@ -540,40 +540,40 @@ MessageDecoder = {
local bo = ( packet.GIOP.byte_order == 0 and ">" or "<")
local pos, seq_len = bin.unpack( bo .. "I", packet.data, 7)
local objs = {}
for i=1, seq_len do
local seq_len_of_bind_name
local len, name
local obj = {}
pos, seq_len_of_bind_name = bin.unpack( bo .. "I", packet.data, pos)
if ( seq_len_of_bind_name ~= 1 ) then return false, "Sequence length of Binding_binding_name was greater than 1" end
pos, len = bin.unpack( bo .. "I", packet.data, pos )
pos, obj.id = bin.unpack( "A" .. len - 1, packet.data, pos )
-- Account for terminating zero
pos = pos + 1
-- Account for undecoded data
pos = pos + ( ( len % 4 > 0 ) and ( 4 - ( len % 4 ) ) or 0 )
pos = pos + 3
pos, obj.kind = bin.unpack("C", packet.data, pos)
-- Account for undecoded data
pos = pos + 4
pos, obj.enum = bin.unpack( bo .. "I", packet.data, pos )
table.insert( objs, obj )
end
return true, objs
end,
}
Comm = {
--- Creates a new Comm instance
--
-- @param socket containing a buffered socket connected to the server
@@ -585,7 +585,7 @@ Comm = {
o.socket = socket
return o
end,
--- Sends and recieves a GIOP packet
--
-- @param packet containing a Packet.* object, the object must
@@ -597,7 +597,7 @@ Comm = {
local status, err = self.socket:send( tostring(packet) )
local op = packet.op:sub(1, -2)
local data
if( not(status) ) then return false, err end
packet = Packet.GIOP.reply:new()
@@ -609,15 +609,15 @@ Comm = {
else
return false, ("No message decoder for op (%s)"):format(op)
end
return status, data
end,
}
Helper = {
new = function(self, host, port )
local o = {}
setmetatable(o, self)
@@ -627,48 +627,48 @@ Helper = {
o.socket = Socket:new()
return o
end,
GetNamingContext = function( self )
local packet = Packet.GIOP.get:new( 5, 0x494e4954, bin.pack(">IA", #Constants.NAMESERVICE, Constants.NAMESERVICE) )
local status, ctx, lhost, pos, len, bo, tmp
packet:addServiceContext( 17, string.char(0x00, 0x02), 0)
packet:addServiceContext( Constants.ServiceContext.NEO_FIRST_SERVICE_CONTEXT, string.char(0x00, 0x14), 0)
packet:addServiceContext( Constants.ServiceContext.SENDING_CONTEXT_RUNTIME, tostring(SendingContextRuntime:new( self.lhost )), 0 )
status, packet = self.comm:exchGIOPPacket( packet )
if( not(status) ) then return status, packet end
return true, packet.ctx
end,
ListObjects = function( self, keyaddr )
-- SyncScope WITH_TARGET
local packet = Packet.GIOP._is_a:new( 5, Constants.SyncScope.WITH_TARGET, keyaddr )
local status, err, lhost
status, err = self:Reconnect()
if( not(status) ) then return false, err end
packet:addServiceContext( 17, "\0\2", 0x000d)
packet:addServiceContext( Constants.ServiceContext.CODESETS, "\0\0\0\0\0\1\0\1\0\1\1\9" )
packet:addServiceContext( Constants.ServiceContext.NEO_FIRST_SERVICE_CONTEXT, string.char(0x00, 0x14), 0x5d69)
packet:addServiceContext( Constants.ServiceContext.SENDING_CONTEXT_RUNTIME, tostring(SendingContextRuntime:new( self.lhost )), 0 )
status, packet = self.comm:exchGIOPPacket( packet )
if( not(status) ) then return status, packet end
packet = Packet.GIOP.list:new( Constants.ServiceContext.SENDING_CONTEXT_RUNTIME, Constants.SyncScope.WITH_TARGET, keyaddr, 1000 )
packet:addServiceContext( 17, "\0\2", 0x000d)
packet:addServiceContext( Constants.ServiceContext.CODESETS, "\0\0\0\0\0\1\0\1\0\1\1\9" )
packet:addServiceContext( Constants.ServiceContext.NEO_FIRST_SERVICE_CONTEXT, string.char(0x00, 0x14), 0x9c9b)
status, packet = self.comm:exchGIOPPacket( packet )
if( not(status) ) then return status, packet end
return true, packet
end,
--- Connects and performs protocol negotiation with the Oracle server
--
-- @return true on success, false on failure
@@ -679,22 +679,22 @@ Helper = {
self.comm = Comm:new( self.socket )
status, self.lhost = self.socket:getSrcIp()
if ( not(status) ) then
if ( not(status) ) then
self.socket:close()
return false, self.lhost
return false, self.lhost
end
return true
end,
Close = function( self )
return self.socket:close()
end,
Reconnect = function( self )
local status = self:Close()
if( not(status) ) then return false, "Failed to close socket" end
status = self:Connect()
if( not(status) ) then return false, "Failed to re-connect socket" end

View File

@@ -13,27 +13,27 @@ _ENV = stdnse.module("gps", stdnse.seeall)
--
--
NMEA = {
NMEA = {
-- Parser for the RMC sentence
RMC = {
parse = function(str)
local time, status, latitude, ns_indicator, longitude,
ew_indicator, speed, course, date, variation,
ew_variation, checksum = str:match("^%$GPRMC,([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^%*]*)(.*)$")
if ( not(latitude) or not(longitude) ) then
return
end
local deg, min = latitude:match("^(..)(.*)$")
if ( not(deg) or not(min) ) then
return
end
latitude = tonumber(deg) + (tonumber(min)/60)
deg, min = longitude:match("^(..)(.*)$")
if ( not(deg) or not(min) ) then
return
@@ -46,15 +46,15 @@ NMEA = {
if ( ns_indicator == 'S' ) then
latitude = -latitude
end
return { time = time, status = status, latitude = latitude,
longitude = longitude, speed = speed, course = course,
date = date, variation = variation,
date = date, variation = variation,
ew_variation = ew_variation }
end,
},
-- Calculates an verifies the message checksum
--
-- @param str containing the GPS sentence
@@ -65,7 +65,7 @@ NMEA = {
for c in str:sub(2,-4):gmatch(".") do
val = bit.bxor(val, string.byte(c))
end
if ( str:sub(-2):upper() ~= stdnse.tohex(string.char(val)):upper() ) then
return false, ("Failed to verify checksum (got: %s; expected: %s)"):format(stdnse.tohex(string.char(val)), str:sub(-2))
end
@@ -75,16 +75,16 @@ NMEA = {
-- Parses a GPS sentence using the apropriate parser
--
-- @param str containing the GPS sentence
-- @return entry table containing the parsed response or
-- @return entry table containing the parsed response or
-- err string if status is false
-- @return status true on success, false on failure
parse = function(str)
local status, err = NMEA.checksum(str)
if ( not(status) ) then
return false, err
end
local prefix = str:match("^%$GP([^,]*)")
if ( not(prefix) ) then
return false, "Not a NMEA sentence"
@@ -101,9 +101,9 @@ NMEA = {
stdnse.print_debug(2, err)
return false, err
end
end
}
Util = {
@@ -111,7 +111,7 @@ Util = {
convertTime = function(date, time)
local d = {}
d.hour, d.min, d.sec = time:match("(..)(..)(..)")
d.day, d.month, d.year = date:match("(..)(..)(..)")
d.day, d.month, d.year = date:match("(..)(..)(..)")
d.year = d.year + 2000
return os.time(d)
end

View File

@@ -16,7 +16,7 @@
--
-- * <code>Crawler</code>
-- ** This class is responsible for the actual crawling.
--
--
-- The following sample code shows how the spider could be used:
-- <code>
-- local crawler = httpspider.Crawler:new( host, port, '/', { scriptname = SCRIPT_NAME } )
@@ -38,9 +38,9 @@
-- return result
-- </code>
--
-- For advanced use, the library currently supports a number of closures (withinhost,
-- withindomain, doscraping). Please note, that withinhost and withindomain options also
-- support boolean values. You will want to override them only for advanced use. You can
-- For advanced use, the library currently supports a number of closures (withinhost,
-- withindomain, doscraping). Please note, that withinhost and withindomain options also
-- support boolean values. You will want to override them only for advanced use. You can
-- define them using the following ultities:
--
-- * <code>iswithinhost</code>
@@ -51,18 +51,18 @@
--
-- * <code>isresource</code>
-- ** You can use this ultity to check the type of the resource (for example "js").
-- ** A third option may hold a number of signs that may exist after the extension
-- ** of the resource. By default, these are [#, ?]. For example, if we want to return
-- only php resources, the function will also return example.php?query=foo or
-- ** A third option may hold a number of signs that may exist after the extension
-- ** of the resource. By default, these are [#, ?]. For example, if we want to return
-- only php resources, the function will also return example.php?query=foo or
-- example.php#foo.
--
-- The following sample code shows an example usage. We override the default
-- withinhost method and we allow spidering only on resources within the host
-- The following sample code shows an example usage. We override the default
-- withinhost method and we allow spidering only on resources within the host
-- that they are not "js" or "css".
-- <code>
-- crawler.options.withinhost = function(url)
-- if crawler:iswithinhost(url)
-- and not crawler:isresource(url, "js")
-- if crawler:iswithinhost(url)
-- and not crawler:isresource(url, "js")
-- and not crawler:isresource(url, "css") then
-- return true
-- end
@@ -70,7 +70,7 @@
-- </code>
--
-- @author Patrik Karlsson <patrik@cqure.net>
--
--
-- @args httpspider.maxdepth the maximum amount of directories beneath
-- the initial url to spider. A negative value disables the limit.
-- (default: 3)
@@ -78,24 +78,24 @@
-- A negative value disables the limit (default: 20)
-- @args httpspider.url the url to start spidering. This is a URL
-- relative to the scanned host eg. /default.html (default: /)
-- @args httpspider.withinhost Closure that overrides the default withinhost
-- function that only spiders URLs within the same host. If this is
-- set to false the crawler will spider URLs both inside and outside
-- the host. See the closure section above to override the default
-- @args httpspider.withinhost Closure that overrides the default withinhost
-- function that only spiders URLs within the same host. If this is
-- set to false the crawler will spider URLs both inside and outside
-- the host. See the closure section above to override the default
-- behaviour. (default: true)
-- @args httpspider.withindomain Closure that overrides the default
-- @args httpspider.withindomain Closure that overrides the default
-- withindomain function that only spiders URLs within the same
-- domain. This widens the scope from <code>withinhost</code> and can
-- not be used in combination. See the closure section above to
-- not be used in combination. See the closure section above to
-- override the default behaviour. (default: false)
-- @args httpspider.noblacklist if set, doesn't load the default blacklist
-- @args httpspider.useheadfornonwebfiles if set, the crawler would use
-- HEAD instead of GET for files that do not have extensions indicating
-- that they are webpages (the list of webpage extensions is located in
-- nselib/data/http-web-files-extensions.lst)
-- @args httpspider.doscraping Closure that overrides the default doscraping
-- function used to check if the resource should be scraped (in terms
-- of extracting any links within it). See the closure section above to
-- @args httpspider.doscraping Closure that overrides the default doscraping
-- function used to check if the resource should be scraped (in terms
-- of extracting any links within it). See the closure section above to
-- override the default behaviour.
---
@@ -114,10 +114,10 @@ local PREFETCH_SIZE = 5
-- The Options class, handling all spidering options
Options = {
new = function(self, options)
local o = { }
-- copy all options as class members
for k, v in pairs(options) do o[k] = v end
@@ -126,12 +126,12 @@ Options = {
o.whitelist = o.whitelist or {}
o.blacklist = o.blacklist or {}
local removewww = function(url) return string.gsub(url, "^www%.", "") end
-- set up the appropriate matching functions
if ( o.withinhost ) then
o.withinhost = function(u)
local parsed_u = url.parse(tostring(u))
if ( o.base_url:getPort() ~= 80 and o.base_url:getPort() ~= 443 ) then
if ( tonumber(parsed_u.port) ~= tonumber(o.base_url:getPort()) ) then
return false
@@ -147,7 +147,7 @@ Options = {
end
if ( o.withindomain ) then
o.withindomain = function(u)
local parsed_u = url.parse(tostring(u))
local parsed_u = url.parse(tostring(u))
if ( o.base_url:getPort() ~= 80 and o.base_url:getPort() ~= 443 ) then
if ( tonumber(parsed_u.port) ~= tonumber(o.base_url:getPort()) ) then
return false
@@ -162,7 +162,7 @@ Options = {
end
if (not o.doscraping) then
o.doscraping = function(u)
return true
end
@@ -172,7 +172,7 @@ Options = {
self.__index = self
return o
end,
addWhitelist = function(self, func) table.insert(self.whitelist, func) end,
addBlacklist = function(self, func) table.insert(self.blacklist, func) end,
@@ -180,11 +180,11 @@ Options = {
-- Placeholder for form extraction code
FormExtractor = {
}
LinkExtractor = {
-- Creates a new instance of LinkExtractor
-- @return o instance of LinkExtractor
new = function(self, url, html, options)
@@ -200,7 +200,7 @@ LinkExtractor = {
return o
end,
-- is the link absolute or not?
isAbsolute = function(url)
-- at this point we don't care about the protocol
@@ -208,7 +208,7 @@ LinkExtractor = {
-- feed:http://example.com/rss.xml
return ( url:match('^%w*:') ~= nil )
end,
-- Creates an absolute link from a relative one based on the base_url
-- The functionality is very simple and does not take any ../../ in
-- consideration.
@@ -235,7 +235,7 @@ LinkExtractor = {
if ( ( base_url:getProto() == 'https' and base_url:getPort() == 443 ) or
( base_url:getProto() == 'http' and base_url:getPort() == 80 ) ) then
if ( leading_slash ) then
return ("%s://%s/%s"):format(base_url:getProto(), base_url:getHost(), rel_url)
else
@@ -257,7 +257,7 @@ LinkExtractor = {
end
end
end,
-- Gets the depth of the link, relative to our base url eg.
-- base_url = http://www.cqure.net/wp/
-- url = http://www.cqure.net/wp/ - depth: 0
@@ -279,7 +279,7 @@ LinkExtractor = {
end
end
end,
validate_link = function(self, url)
local valid = true
@@ -296,7 +296,7 @@ LinkExtractor = {
if ( -1 == depth or depth > self.options.maxdepth ) then
stdnse.print_debug(3, "%s: Skipping link depth: %d; b_url=%s; url=%s", LIBRARY_NAME, depth, tostring(self.options.base_url), tostring(url))
return false
end
end
end
-- withindomain trumps any whitelisting
@@ -315,7 +315,7 @@ LinkExtractor = {
end
end
-- run through all blacklists
-- run through all blacklists
if ( #self.options.blacklist > 0 ) then
for _, func in ipairs(self.options.blacklist) do
if ( func(url) ) then
@@ -353,12 +353,12 @@ LinkExtractor = {
'[sS][rR][cC]%s*=%s*([^\'\"][^%s>]+)',
'[aA][cC][tT][iI][oO][nN]%s*=%s*[\'"]%s*([^"^\']+%s*)[\'"]',
}
local base_hrefs = {
'[Bb][Aa][Ss][Ee]%s*[Hh][Rr][Ee][Ff]%s*=%s*[\'"](%s*[^"^\']+%s*)[\'"]',
'[Bb][Aa][Ss][Ee]%s*[Hh][Rr][Ee][Ff]%s*=%s*([^\'\"][^%s>]+)'
}
local base_href
for _, pattern in ipairs(base_hrefs) do
base_href = self.html:match(pattern)
@@ -373,11 +373,11 @@ LinkExtractor = {
if ( not(LinkExtractor.isAbsolute(l)) ) then
link = LinkExtractor.createAbsolute(self.url, l, base_href)
end
local url = URL:new(link)
local valid = self:validate_link(url)
if ( valid ) then
stdnse.print_debug(3, "%s: Adding link: %s", LIBRARY_NAME, tostring(url))
links[tostring(url)] = true
@@ -386,24 +386,24 @@ LinkExtractor = {
end
end
end
for link in pairs(links) do
table.insert(self.links, link)
end
end,
-- Gets a table containing all of the retrieved URLs, after filtering
-- has been applied.
getLinks = function(self) return self.links end,
}
-- The URL class, containing code to process URLS
-- This class is heavily inspired by the Java URL class
URL = {
-- Creates a new instance of URL
-- @param url string containing the text representation of a URL
-- @return o instance of URL, in case of parsing being successful
@@ -412,14 +412,14 @@ URL = {
local o = {
raw = url,
}
setmetatable(o, self)
self.__index = self
if ( o:parse() ) then
return o
end
end,
-- Parses the string representation of the URL and splits it into different
-- URL components
-- @return status true on success, false on failure
@@ -430,15 +430,15 @@ URL = {
self.port = tonumber(self.port)
if ( not(self.port) ) then
if ( self.proto:match("https") ) then
self.port = 443
self.port = 443
elseif ( self.proto:match("http")) then
self.port = 80
end
end
self.path = self.file:match("^([^?]*)[%?]?")
self.dir = self.path:match("^(.+%/)") or "/"
self.domain= self.host:match("^[^%.]-%.(.*)")
self.domain= self.host:match("^[^%.]-%.(.*)")
return true
elseif( self.raw:match("^javascript:") ) then
stdnse.print_debug(2, "%s: Skipping javascript url: %s", LIBRARY_NAME, self.raw)
@@ -449,42 +449,42 @@ URL = {
end
return false
end,
-- Get's the host portion of the URL
-- @return host string containing the hostname
getHost = function(self) return self.host end,
-- Get's the protocol representation of the URL
-- @return proto string containing the protocol (ie. http, https)
getProto = function(self) return self.proto end,
-- Returns the filename component of the URL.
-- Returns the filename component of the URL.
-- @return file string containing the path and query components of the url
getFile = function(self) return self.file end,
-- Gets the port component of the URL
-- @return port number containing the port of the URL
getPort = function(self) return self.port end,
-- Gets the path component of the URL
-- @return the full path and filename of the URL
getPath = function(self) return self.path end,
-- Gets the directory component of the URL
-- @return directory string containing the directory part of the URL
-- @return directory string containing the directory part of the URL
getDir = function(self) return self.dir end,
-- Gets the domain component of the URL
-- @return domain string containing the hosts domain
getDomain = function(self)
if ( self.domain ) then
return self.domain
return self.domain
-- fallback to the host, if we can't find a domain
else
return self.host
end
end,
-- Converts the URL to a string
-- @return url string containing the string representation of the url
__tostring = function(self) return self.raw end,
@@ -492,12 +492,12 @@ URL = {
-- An UrlQueue
UrlQueue = {
-- creates a new instance of UrlQueue
-- @param options table containing options
-- @return o new instance of UrlQueue
new = function(self, options)
local o = {
local o = {
urls = {},
options = options
}
@@ -505,23 +505,23 @@ UrlQueue = {
self.__index = self
return o
end,
-- get's the next available url in the queue
getNext = function(self)
return table.remove(self.urls,1)
end,
-- adds a new url to the queue
-- @param url can be either a string or a URL or a table of URLs
add = function(self, url)
assert( type(url) == 'string' or type(url) == 'table', "url was neither a string or table")
local urls = ( 'string' == type(url) ) and URL:new(url) or url
-- if it's a table, it can be either a single URL or an array of URLs
if ( 'table' == type(url) and url.raw ) then
urls = { url }
end
for _, u in ipairs(urls) do
u = ( 'string' == type(u) ) and URL:new(u) or u
if ( u ) then
@@ -531,27 +531,27 @@ UrlQueue = {
end
end
end,
-- dumps the contents of the UrlQueue
dump = function(self)
for _, url in ipairs(self.urls) do
print("url:", url)
end
end,
}
-- The Crawler class
Crawler = {
options = {},
removewww = function(url) return string.gsub(url, "^www%.", "") end,
-- An ultity when defining closures. Checks if the resource exists within host.
-- @param u URL that points to the resource we want to check.
-- @param u URL that points to the resource we want to check.
iswithinhost = function(self, u)
local parsed_u = url.parse(tostring(u))
local parsed_u = url.parse(tostring(u))
if ( self.options.base_url:getPort() ~= 80 and self.options.base_url:getPort() ~= 443 ) then
if ( tonumber(parsed_u.port) ~= tonumber(self.options.base_url:getPort()) ) then
return false
@@ -566,9 +566,9 @@ Crawler = {
end,
-- An ultity when defining closures. Checks if the resource exists within domain.
-- @param u URL that points to the resource we want to check.
-- @param u URL that points to the resource we want to check.
iswithindomain = function(self, u)
local parsed_u = url.parse(tostring(u))
local parsed_u = url.parse(tostring(u))
if ( self.options.base_url:getPort() ~= 80 and self.options.base_url:getPort() ~= 443 ) then
if ( tonumber(parsed_u.port) ~= tonumber(self.options.base_url:getPort()) ) then
return false
@@ -581,10 +581,10 @@ Crawler = {
return true
end,
-- An ultity when defining closures. Checks the type of the resource.
-- @param u URL that points to the resource we want to check.
-- An ultity when defining closures. Checks the type of the resource.
-- @param u URL that points to the resource we want to check.
-- @param ext the extension of the resource.
-- @param signs table of signs that may exist after the extension of the resource.
-- @param signs table of signs that may exist after the extension of the resource.
isresource = function(self, u, ext, signs)
u = tostring(u)
@@ -596,7 +596,7 @@ Crawler = {
if signs then
for _, s in signs do
signstring = signstring .. s
end
end
signstring:gsub('?', '%?')
else
signstring = "#%?"
@@ -604,8 +604,8 @@ Crawler = {
return string.match(u, "." .. ext .. "[" .. signstring .. "]" .. "[^.]*$")
end,
end,
-- creates a new instance of the Crawler instance
-- @param host table as received by the action method
-- @param port table as received by the action method
@@ -643,13 +643,13 @@ Crawler = {
o:loadDefaultArguments()
local response = http.get(o.host, o.port, '/', { timeout = o.options.timeout, redirect_ok = o.options.redirect_ok, no_cache = o.options.no_cache } )
if ( not(response) or 'table' ~= type(response) ) then
return
end
o.url = o.url:match("/?(.*)")
local u_host = o.host.targetname or o.host.name
if ( not(u_host) or 0 == #u_host ) then
u_host = o.host.ip
@@ -662,17 +662,17 @@ Crawler = {
o.options.timeout = o.options.timeout or 10000
o.processed = {}
-- script arguments have precedense
if ( not(o.options.maxdepth) ) then
o.options.maxdepth = tonumber(stdnse.get_script_args("httpspider.maxdepth"))
end
-- script arguments have precedense
if ( not(o.options.maxpagecount) ) then
o.options.maxpagecount = tonumber(stdnse.get_script_args("httpspider.maxpagecount"))
end
if ( not(o.options.noblacklist) ) then
o:addDefaultBlacklist()
end
@@ -689,18 +689,18 @@ Crawler = {
end
end
end
stdnse.print_debug(2, "%s: %s", LIBRARY_NAME, o:getLimitations())
return o
end,
-- Set's the timeout used by the http library
-- @param timeout number containing the timeout in ms.
set_timeout = function(self, timeout)
self.options.timeout = timeout
end,
-- Get's the amount of pages that has been retrieved
-- @return count number of pages retrieved by the instance
getPageCount = function(self)
@@ -710,7 +710,7 @@ Crawler = {
end
return count
end,
-- Adds a default blacklist blocking binary files such as images,
-- compressed archives and executable files
addDefaultBlacklist = function(self)
@@ -740,7 +740,7 @@ Crawler = {
end
end )
end,
-- does the heavy crawling
--
-- The crawler may exit due to a number of different reasons, including
@@ -759,12 +759,12 @@ Crawler = {
end
while(true) do
if ( self.quit or coroutine.status(self.basethread) == 'dead' ) then
table.insert(response_queue, {false, { err = false, msg = "Quit signalled by crawler" } })
break
end
-- in case the user set a max page count to retrieve check how many
-- pages we have retrieved so far
local count = self:getPageCount()
@@ -774,7 +774,7 @@ Crawler = {
condvar "signal"
return
end
-- pull links from the queue until we get a valid one
local url
repeat
@@ -787,18 +787,18 @@ Crawler = {
condvar "signal"
return
end
if ( self.options.maxpagecount ) then
stdnse.print_debug(2, "%s: Fetching url [%d of %d]: %s", LIBRARY_NAME, count, self.options.maxpagecount, tostring(url))
else
stdnse.print_debug(2, "%s: Fetching url: %s", LIBRARY_NAME, tostring(url))
end
end
local scrape = true
local scrape = true
if not (self.options.doscraping(url)) then
stdnse.print_debug(2, "%s: Scraping is not allowed for url: %s", LIBRARY_NAME, tostring(url))
stdnse.print_debug(2, "%s: Scraping is not allowed for url: %s", LIBRARY_NAME, tostring(url))
scrape = false
end
@@ -828,9 +828,9 @@ Crawler = {
-- fetch the url, and then push it to the processed table
response = http.get(url:getHost(), url:getPort(), url:getFile(), { timeout = self.options.timeout, redirect_ok = self.options.redirect_ok, no_cache = self.options.no_cache } )
end
self.processed[tostring(url)] = true
if ( response ) then
-- were we redirected?
if ( response.location ) then
@@ -847,7 +847,7 @@ Crawler = {
if ( response.body ) and scrape then
local links = LinkExtractor:new(url, response.body, self.options):getLinks()
self.urlqueue:add(links)
end
end
else
response = { body = "", headers = {} }
end
@@ -860,7 +860,7 @@ Crawler = {
end
condvar "signal"
end,
-- Loads the argument set on a script level
loadScriptArguments = function(self)
local sn = self.options.scriptname
@@ -868,7 +868,7 @@ Crawler = {
stdnse.print_debug("%s: WARNING: Script argument could not be loaded as scriptname was not set", LIBRARY_NAME)
return
end
if ( nil == self.options.maxdepth ) then
self.options.maxdepth = tonumber(stdnse.get_script_args(sn .. ".maxdepth"))
end
@@ -893,9 +893,9 @@ Crawler = {
if ( nil == self.options.doscraping ) then
self.options.doscraping = stdnse.get_script_args(sn .. ".doscraping")
end
end,
-- Loads the argument on a library level
loadLibraryArguments = function(self)
local ln = LIBRARY_NAME
@@ -925,7 +925,7 @@ Crawler = {
self.options.doscraping = stdnse.get_script_args(ln .. ".doscraping")
end
end,
-- Loads any defaults for arguments that were not set
loadDefaultArguments = function(self)
local function tobool(b)
@@ -948,7 +948,7 @@ Crawler = {
end
return b
end
if self.options.withinhost == 0 then
self.options.withinhost = false
end
@@ -977,8 +977,8 @@ Crawler = {
self.options.maxdepth = tonumber(self.options.maxdepth) or 3
self.options.maxpagecount = tonumber(self.options.maxpagecount) or 20
self.url = self.url or '/'
end,
end,
-- gets a string of limitations imposed on the crawl
getLimitations = function(self)
local o = self.options
@@ -998,12 +998,12 @@ Crawler = {
table.insert(limits, ("withinhost=%s"):format(o.base_url:getHost()))
end
end
if ( #limits > 0 ) then
return ("Spidering limited to: %s"):format(stdnse.strjoin("; ", limits))
end
end,
-- does the crawling
crawl = function(self)
self.response_queue = self.response_queue or {}
@@ -1013,7 +1013,7 @@ Crawler = {
end
if ( #self.response_queue == 0 and coroutine.status(self.thread) ~= 'dead') then
condvar "wait"
condvar "wait"
end
condvar "signal"
if ( #self.response_queue == 0 ) then
@@ -1022,7 +1022,7 @@ Crawler = {
return table.unpack(table.remove(self.response_queue, 1))
end
end,
-- signals the crawler to stop
stop = function(self)
local condvar = nmap.condvar(self.response_queue)

View File

@@ -17,11 +17,11 @@ _ENV = stdnse.module("iax2", stdnse.seeall)
IAX2 = {
FrameType = {
IAX = 6,
IAX = 6,
},
SubClass = {
ACK = 0x04,
REGACK = 0x0f,
@@ -29,21 +29,21 @@ IAX2 = {
REGREL = 0x11,
CALLTOKEN = 0x28,
},
InfoElement = {
USERNAME = 0x06,
USERNAME = 0x06,
CHALLENGE = 0x0f,
MD5_RESULT = 0x10,
CALLTOKEN = 0x36,
},
PacketType = {
FULL = 1,
},
-- The IAX2 Header
Header = {
-- Creates a new Header instance
-- @param src_call number containing the source call
-- @param dst_call number containing the dest call
@@ -68,9 +68,9 @@ IAX2 = {
self.__index = self
return o
end,
-- Parses data, a byte string, and creates a new Header instance
-- @return header instance of Header
-- @return header instance of Header
parse = function(data)
local header = IAX2.Header:new()
local pos, frame_type = bin.unpack("C", data)
@@ -90,13 +90,13 @@ IAX2 = {
end
pos, header.dst_call = bin.unpack(">S", data, pos - 1)
header.dst_call = bit.band(header.dst_call, 0x7FFF)
pos, header.timestamp, header.oseqno,
pos, header.timestamp, header.oseqno,
header.iseqno, header.frametype, header.subclass = bin.unpack(">ICCCC", data, pos)
return header
end,
-- Converts the instance to a string
-- @return str containing the instance
__tostring = function(self)
@@ -114,10 +114,10 @@ IAX2 = {
self.oseqno, self.iseqno, self.frametype, self.subclass)
end,
},
-- The IAX2 Request class
Request = {
-- Creates a new instance
-- @param header instance of Header
new = function(self, header)
@@ -127,9 +127,9 @@ IAX2 = {
}
setmetatable(o, self)
self.__index = self
return o
return o
end,
-- Sets an Info Element or adds one, in case it's missing
-- @param key the key value of the IE to add
-- @param value string containing the value to set or add
@@ -141,7 +141,7 @@ IAX2 = {
end
table.insert(self.ies, { type = key, value = value } )
end,
-- Gets an information element
-- @param key number containing the element number to retrieve
-- @return ie table containing the info element if it exists
@@ -160,24 +160,24 @@ IAX2 = {
for _, ie in ipairs(self.ies) do
data = data .. bin.pack("Cp", ie.type, ie.value )
end
return tostring(self.header) .. data
end,
},
-- The IAX2 Response
Response = {
-- Creates a new instance
new = function(self)
local o = { ies = {} }
setmetatable(o, self)
self.__index = self
return o
return o
end,
-- Sets an Info Element or adds one, in case it's missing
-- @param key the key value of the IE to add
-- @param value string containing the value to set or add
@@ -189,7 +189,7 @@ IAX2 = {
end
table.insert(self.ies, { type = key, value = value } )
end,
-- Gets an information element
-- @param key number containing the element number to retrieve
-- @return ie table containing the info element if it exists
@@ -200,16 +200,16 @@ IAX2 = {
end
end
end,
-- Parses data, a byte string, and creates a response
-- @return resp instance of response
-- @return resp instance of response
parse = function(data)
local resp = IAX2.Response:new()
if ( not(resp) ) then return end
resp.header = IAX2.Header.parse(data)
if ( not(resp.header) ) then return end
local pos = 13
resp.ies = {}
repeat
@@ -219,14 +219,14 @@ IAX2 = {
until( pos > #data )
return resp
end,
}
}
Helper = {
-- Creates a new Helper instance
-- @param host table as received by the action method
-- @param port table as received by the action method
@@ -237,9 +237,9 @@ Helper = {
local o = { host = host, port = port, options = options or {} }
setmetatable(o, self)
self.__index = self
return o
return o
end,
-- Connects the UDP socket to the server
-- @return status true on success, false on failure
-- @return err message containing error if status is false
@@ -248,7 +248,7 @@ Helper = {
self.socket:set_timeout(self.options.timeout or 5000)
return self.socket:connect(self.host, self.port)
end,
-- Sends a request to the server and receives the response
-- @param req instance containing the request to send to the server
-- @return status true on success, false on failure
@@ -263,11 +263,11 @@ Helper = {
if ( not(status) ) then
return false, "Failed to receive response from server"
end
local resp = IAX2.Response.parse(data)
return true, resp
end,
-- Request a session release
-- @param username string containing the extention (username)
-- @param password string containing the password
@@ -299,45 +299,45 @@ Helper = {
if ( not(status) ) then
return false, resp
end
local challenge = resp:getIE(IAX2.InfoElement.CHALLENGE)
if ( not(challenge) ) then
return false, "Failed to retrieve challenge from server"
end
regrel.header.iseqno = 1
regrel.header.oseqno = 1
regrel.header.dst_call = resp.header.src_call
regrel.ies = {}
local hash = stdnse.tohex(openssl.md5(challenge.value .. password))
regrel:setIE(IAX2.InfoElement.USERNAME, username)
regrel:setIE(IAX2.InfoElement.MD5_RESULT, hash)
status, resp = self:exch(regrel)
if ( not(status) ) then
return false, resp
end
if ( IAX2.SubClass.ACK == resp.header.subclass ) then
local data
status, data = self.socket:receive()
status, data = self.socket:receive()
resp = IAX2.Response.parse(data)
end
if ( status and IAX2.SubClass.REGACK == resp.header.subclass ) then
return true
end
return false, "Release failed"
end,
-- Close the connection with the server
-- @return true on success, false on failure
close = function(self)
return self.socket:close()
end,
}
return _ENV;

View File

@@ -33,7 +33,7 @@ _ENV = stdnse.module("imap", stdnse.seeall)
IMAP = {
--- Creates a new instance of the IMAP class
--
-- @param host table as received by the script action method
@@ -42,17 +42,17 @@ IMAP = {
-- <code>timeout<code> - number containing the seconds to wait for
-- a response
new = function(self, host, port, options)
local o = {
local o = {
host = host,
port = port,
counter = 1,
timeout = ( options and options.timeout ) or 10000
counter = 1,
timeout = ( options and options.timeout ) or 10000
}
setmetatable(o, self)
self.__index = self
return o
end,
--- Receives a response from the IMAP server
--
-- @return status true on success, false on failure
@@ -64,10 +64,10 @@ IMAP = {
if( not(status) ) then return false, tmp end
data = data .. tmp
until( tmp:match(("^A%04d"):format(self.counter - 1)) or tmp:match("^%+"))
return true, data
end,
--- Sends a request to the IMAP server
--
-- @param cmd string containing the command to send to the server eg.
@@ -87,7 +87,7 @@ IMAP = {
self.counter = self.counter + 1
return true
end,
--- Connect to the server
--
-- @return status true on success, false on failure
@@ -100,7 +100,7 @@ IMAP = {
self.socket = socket
return true, banner
end,
--- Authenticate to the server (non PLAIN text mode)
-- Currently supported algorithms are CRAM-MD5 and CRAM-SHA1
--
@@ -113,26 +113,26 @@ IMAP = {
authenticate = function(self, username, pass, mech)
assert( mech == "NTLM" or
mech == "DIGEST-MD5" or
mech == "CRAM-MD5" or
mech == "CRAM-MD5" or
mech == "PLAIN",
"Unsupported authentication mechanism")
local status, err = self:send("AUTHENTICATE", mech)
if( not(status) ) then return false, "ERROR: Failed to send data" end
local status, data = self:receive()
if( not(status) ) then return false, "ERROR: Failed to receive challenge" end
if ( mech == "NTLM" ) then
-- sniffed of the wire, seems to always be the same
-- decodes to some NTLMSSP blob greatness
status, data = self.socket:send("TlRMTVNTUAABAAAAB7IIogYABgA3AAAADwAPACgAAAAFASgKAAAAD0FCVVNFLUFJUi5MT0NBTERPTUFJTg==\r\n")
if ( not(status) ) then return false, "ERROR: Failed to send NTLM packet" end
status, data = self:receive()
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
if ( data:match(("^A%04d "):format(self.counter-1)) ) then
return false, "ERROR: Authentication mechanism not supported"
end
@@ -142,19 +142,19 @@ IMAP = {
return false, "ERROR: Failed to receive proper response from server"
end
data = base64.dec(data:match("^+ (.*)"))
-- All mechanisms expect username and pass
-- add the otheronce for those who need them
local mech_params = { username, pass, data, "imap" }
auth_data = sasl.Helper:new(mech):encode(table.unpack(mech_params))
auth_data = base64.enc(auth_data) .. "\r\n"
status, data = self.socket:send(auth_data)
if( not(status) ) then return false, "ERROR: Failed to send data" end
status, data = self:receive()
if( not(status) ) then return false, "ERROR: Failed to receive data" end
if ( mech == "DIGEST-MD5" ) then
local rspauth = data:match("^+ (.*)")
if ( rspauth ) then
@@ -168,7 +168,7 @@ IMAP = {
end
return false, "Login failed"
end,
--- Login to the server using PLAIN text authentication
--
-- @param username string containing the username
@@ -178,16 +178,16 @@ IMAP = {
login = function(self, username, password)
local status, err = self:send("LOGIN", ("\"%s\" \"%s\""):format(username, password))
if( not(status) ) then return false, "ERROR: Failed to send data" end
local status, data = self:receive()
if( not(status) ) then return false, "ERROR: Failed to receive data" end
if ( data:match(("^A%04d OK"):format(self.counter - 1)) ) then
return true
end
return false, "Login failed"
end,
--- Retrieves a list of server capabilities (eg. supported authentication
-- mechanisms, QUOTA, UIDPLUS, ACL ...)
--
@@ -198,11 +198,11 @@ IMAP = {
local proto = (self.port.version and self.port.version.service_tunnel == "ssl" and "ssl") or "tcp"
local status, err = self:send("CAPABILITY")
if( not(status) ) then return false, err end
local status, line = self:receive()
if (not(status)) then
capas.CAPABILITY = false
else
else
while status do
if ( line:match("^%*%s+CAPABILITY") ) then
line = line:gsub("^%*%s+CAPABILITY", "")
@@ -216,17 +216,17 @@ IMAP = {
end
return true, capas
end,
--- Closes the connection to the IMAP server
-- @return true on success, false on failure
close = function(self) return self.socket:close() end
}
-- The helper class, that servers as interface to script writers
Helper = {
-- @param host table as received by the script action method
-- @param port table as received by the script action method
-- @param options table containing options, currently
@@ -238,13 +238,13 @@ Helper = {
self.__index = self
return o
end,
--- Connects to the IMAP server
-- @return status true on success, false on failure
connect = function(self)
return self.client:connect()
end,
--- Login to the server using eithe plain-text or using the authentication
-- mechanism provided in the mech argument.
--
@@ -259,7 +259,7 @@ Helper = {
return self.client:authenticate(username, password, mech)
end
end,
--- Retrieves a list of server capabilities (eg. supported authentication
-- mechanisms, QUOTA, UIDPLUS, ACL ...)
--
@@ -268,13 +268,13 @@ Helper = {
capabilities = function(self)
return self.client:capabilities()
end,
--- Closes the connection to the IMAP server
-- @return true on success, false on failure
close = function(self)
return self.client:close()
end,
}
return _ENV;

File diff suppressed because it is too large Load Diff

View File

@@ -154,12 +154,12 @@ todword = function( ip )
end
---
-- Converts the supplied IPv4 address from a DWORD value into a dotted string.
-- Converts the supplied IPv4 address from a DWORD value into a dotted string.
--
-- For example, the address (((a*256+b)*256+c)*256+d) becomes a.b.c.d.
-- For example, the address (((a*256+b)*256+c)*256+d) becomes a.b.c.d.
--
--@param ip DWORD representing an IPv4 address.
--@return The string representing the address.
--@param ip DWORD representing an IPv4 address.
--@return The string representing the address.
fromdword = function( ip )
if type( ip ) ~= "number" then
stdnse.print_debug(1, "Error in ipOps.todword: Expected IPv4 address.")
@@ -354,7 +354,7 @@ expand_ip = function( ip, family )
if family == "inet6" then
return ( table.concat( { 0,0,0,0,0,"ffff",
stdnse.tohex( 256*octets[1]+octets[2] ),
stdnse.tohex( 256*octets[3]+octets[4] )
stdnse.tohex( 256*octets[3]+octets[4] )
}, ":" ) )
else
return ( table.concat( octets, "." ) )

View File

@@ -17,11 +17,11 @@ _ENV = stdnse.module("ipp", stdnse.seeall)
-- The IPP layer
IPP = {
StatusCode = {
OK = 0,
},
State = {
IPP_JOB_PENDING = 3,
IPP_JOB_HELD = 4,
@@ -31,7 +31,7 @@ IPP = {
IPP_JOB_ABORTED = 8,
IPP_JOB_COMPLETED = 9,
},
StateName = {
[3] = "Pending",
[4] = "Held",
@@ -41,7 +41,7 @@ IPP = {
[8] = "Aborted",
[9] = "Completed",
},
OperationID = {
IPP_CANCEL_JOB = 0x0008,
IPP_GET_JOB_ATTRIBUTES = 0x0009,
@@ -49,13 +49,13 @@ IPP = {
CUPS_GET_PRINTERS = 0x4002,
CUPS_GET_DOCUMENT = 0x4027
},
PrinterState = {
IPP_PRINTER_IDLE = 3,
IPP_PRINTER_PROCESSING = 4,
IPP_PRINTER_STOPPED = 5,
},
Attribute = {
IPP_TAG_OPERATION = 0x01,
@@ -69,25 +69,25 @@ IPP = {
IPP_TAG_URI = 0x45,
IPP_TAG_CHARSET = 0x47,
IPP_TAG_LANGUAGE = 0x48,
new = function(self, tag, name, value)
local o = { tag = tag, name = name, value = value }
setmetatable(o, self)
self.__index = self
return o
end,
parse = function(data, pos)
local attrib = IPP.Attribute:new()
local val
pos, attrib.tag, attrib.name, val = bin.unpack(">CPP", data, pos)
-- print(attrib.name, stdnse.tohex(val))
attrib.value = {}
attrib.value = {}
table.insert(attrib.value, { tag = attrib.tag, val = val })
repeat
local tag, name_len, val
if ( #data < pos + 3 ) then
break
end
@@ -100,7 +100,7 @@ IPP = {
pos = pos - 3
end
until( name_len ~= 0 )
-- do minimal decoding
for i=1, #attrib.value do
if ( attrib.value[i].tag == IPP.Attribute.IPP_TAG_INTEGER ) then
@@ -109,15 +109,15 @@ IPP = {
attrib.value[i].val = select(2, bin.unpack(">I", attrib.value[i].val))
end
end
if ( 1 == #attrib.value ) then
attrib.value = attrib.value[1].val
end
--print(attrib.name, attrib.value, stdnse.tohex(val))
return pos, attrib
end,
__tostring = function(self)
if ( "string" == type(self.value) ) then
return bin.pack(">CSASA", self.tag, #self.name, self.name, #self.value, self.value)
@@ -129,23 +129,23 @@ IPP = {
return data
end
end
},
-- An attribute group, groups several attributes
AttributeGroup = {
new = function(self, tag, attribs)
local o = { tag = tag, attribs = attribs or {} }
setmetatable(o, self)
self.__index = self
return o
end,
addAttribute = function(self, attrib)
table.insert(self.attribs, attrib)
end,
--
-- Gets the first attribute matching name and optionally tag from the
-- attribute group.
@@ -175,23 +175,23 @@ IPP = {
end
end
end,
__tostring = function(self)
local data = bin.pack("C", self.tag)
for _, attrib in ipairs(self.attribs) do
data = data .. tostring(attrib)
end
return data
end
},
-- The IPP request
Request = {
new = function(self, opid, reqid)
local o = {
local o = {
version = 0x0101,
opid = opid,
reqid = reqid,
@@ -201,11 +201,11 @@ IPP = {
self.__index = self
return o
end,
addAttributeGroup = function(self, group)
table.insert( self.attrib_groups, group )
end,
__tostring = function(self)
local data = bin.pack(">SSI", self.version, self.opid, self.reqid )
@@ -215,12 +215,12 @@ IPP = {
data = data .. bin.pack("C", IPP.Attribute.IPP_TAG_END)
return data
end,
},
-- A class to handle responses from the server
Response = {
-- Creates a new instance of response
new = function(self)
local o = {}
@@ -228,7 +228,7 @@ IPP = {
self.__index = self
return o
end,
getAttributeGroups = function(self, tag)
local groups = {}
for _, v in ipairs(self.attrib_groups or {}) do
@@ -238,24 +238,24 @@ IPP = {
end
return groups
end,
parse = function(data)
local resp = IPP.Response:new()
local pos
pos, resp.version, resp.status, resp.reqid = bin.unpack(">SSI", data)
resp.attrib_groups = {}
local group
repeat
local tag, attrib
pos, tag = bin.unpack(">C", data, pos)
if ( tag == IPP.Attribute.IPP_TAG_OPERATION or
tag == IPP.Attribute.IPP_TAG_JOB or
tag == IPP.Attribute.IPP_TAG_PRINTER or
tag == IPP.Attribute.IPP_TAG_END ) then
if ( group ) then
table.insert(resp.attrib_groups, group)
group = IPP.AttributeGroup:new(tag)
@@ -265,27 +265,27 @@ IPP = {
else
pos = pos - 1
end
if ( not(group) ) then
stdnse.print_debug(2, "Unexpected tag: %d", tag)
return
end
pos, attrib = IPP.Attribute.parse(data, pos)
group:addAttribute(attrib)
until( pos == #data + 1)
return resp
end,
},
}
HTTP = {
Request = function(host, port, request)
local headers = {
['Content-Type'] = 'application/ipp',
@@ -301,28 +301,28 @@ HTTP = {
if ( not(response) ) then
return false, "Failed to parse response"
end
return true, response
end,
}
Helper = {
new = function(self, host, port, options)
local o = { host = host, port = port, options = options or {} }
setmetatable(o, self)
self.__index = self
return o
end,
connect = function(self)
self.socket = nmap.new_socket()
self.socket:set_timeout(self.options.timeout or 10000)
return self.socket:connect(self.host, self.port)
end,
getPrinters = function(self)
local attribs = {
@@ -340,17 +340,17 @@ Helper = {
end
local printers = {}
for _, ag in ipairs(response:getAttributeGroups(IPP.Attribute.IPP_TAG_PRINTER)) do
local attrib = {
["printer-name"] = "name",
local attrib = {
["printer-name"] = "name",
["printer-location"] = "location",
["printer-make-and-model"] = "model",
["printer-state"] = "state",
["queued-job-count"] = "queue_count",
["printer-dns-sd-name"] = "dns_sd_name",
}
local printer = {}
for k, v in pairs(attrib) do
if ( ag:getAttributeValue(k) ) then
@@ -361,10 +361,10 @@ Helper = {
end
return true, printers
end,
getQueueInfo = function(self, uri)
local uri = uri or ("ipp://%s/"):format(self.host.ip)
local attribs = {
IPP.Attribute:new(IPP.Attribute.IPP_TAG_CHARSET, "attributes-charset", "utf-8" ),
IPP.Attribute:new(IPP.Attribute.IPP_TAG_LANGUAGE, "attributes-natural-language", "en-us"),
@@ -384,16 +384,16 @@ Helper = {
{ tag = IPP.Attribute.IPP_TAG_KEYWORD, val = "time-at-creation" } } ),
IPP.Attribute:new(IPP.Attribute.IPP_TAG_KEYWORD, "which-jobs", "not-completed" )
}
local ag = IPP.AttributeGroup:new(IPP.Attribute.IPP_TAG_OPERATION, attribs)
local request = IPP.Request:new(IPP.OperationID.IPP_GET_JOBS, 1)
request:addAttributeGroup(ag)
local status, response = HTTP.Request( self.host, self.port, tostring(request) )
if ( not(response) ) then
return status, response
end
local results = {}
for _, ag in ipairs(response:getAttributeGroups(IPP.Attribute.IPP_TAG_JOB)) do
local uri = ag:getAttributeValue("printer-uri")
@@ -407,19 +407,19 @@ Helper = {
local size = ag:getAttributeValue("job-k-octets") .. "k"
local jobname = ag:getAttributeValue("com.apple.print.JobInfo.PMJobName") or "Unknown"
local owner = ag:getAttributeValue("com.apple.print.JobInfo.PMJobOwner") or "Unknown"
results[printer] = results[printer] or {}
table.insert(results[printer], {
id = id,
id = id,
time = os.date("%Y-%m-%d %H:%M:%S", tm),
state = ( IPP.StateName[tonumber(state)] or "Unknown" ),
size = size,
owner = owner,
jobname = jobname })
jobname = jobname })
end
local output = {}
for name, entries in pairs(results) do
for name, entries in pairs(results) do
local t = tab.new(5)
tab.addrow(t, "id", "time", "state", "size (kb)", "owner", "jobname")
for _, entry in ipairs(entries) do
@@ -429,10 +429,10 @@ Helper = {
table.insert(output, { name = name, tab.dump(t) })
end
end
return output
end,
close = function(self)
return self.socket:close()
end,

View File

@@ -8,7 +8,7 @@
-- E.g. <code>LoginRequest</code> and <code>LoginResponse</code>
--
-- Each request can be "serialized" to a string using:
-- <code>tostring(request)</code>.
-- <code>tostring(request)</code>.
-- All responses can be read and instantiated from the socket by calling:
-- <code>local status,resp = Response.fromSocket(sock)</code>
--
@@ -48,15 +48,15 @@ _ENV = stdnse.module("iscsi", stdnse.seeall)
Packet = {
Opcode = {
Opcode = {
LOGIN = 0x03,
TEXT = 0x04,
LOGOUT = 0x06,
},
LoginRequest = {
CSG = {
SecurityNegotiation = 0,
LoginOperationalNegotiation = 1,
@@ -68,7 +68,7 @@ Packet = {
LoginOperationalNegotiation = 1,
FullFeaturePhase = 3,
},
--- Creates a new instance of LoginRequest
--
-- @return instance of LoginRequest
@@ -92,9 +92,9 @@ Packet = {
o.kvp = KVP:new()
return o
end,
setImmediate = function(self, b) self.immediate = ( b and 1 or 0 ) end,
--- Sets the transit bit
--
-- @param b boolean containing the new transit value
@@ -107,12 +107,12 @@ Packet = {
--- Sets the CSG values
--
-- @param csg number containing the new NSG value
-- @param csg number containing the new NSG value
setCSG = function(self, csg) self.flags.csg = csg end,
--- Sets the NSG values
--
-- @param nsg number containing the new NSG value
-- @param nsg number containing the new NSG value
setNSG = function(self, nsg) self.flags.nsg = nsg end,
--- Converts the class instance to string
@@ -130,27 +130,27 @@ Packet = {
for i=1, pad do kvps = kvps .. "\0" end
local len = bit.lshift( self.total_ahs_len, 24 ) + self.data_seg_len
local flags = bit.lshift( ( self.flags.transit or 0 ), 7 )
local flags = bit.lshift( ( self.flags.transit or 0 ), 7 )
flags = flags + bit.lshift( ( self.flags.continue or 0 ), 6)
flags = flags + ( self.flags.nsg or 0 )
flags = flags + bit.lshift( ( self.flags.csg or 0 ), 2 )
local opcode = self.opcode + bit.lshift((self.immediate or 0), 6)
local data = bin.pack(">CCCCICSCSSISSIILLA", opcode,
flags, self.ver_max, self.ver_min, len,
bit.lshift( self.isid.t, 6 ) + bit.band( self.isid.a, 0x3f),
self.isid.b, self.isid.c, self.isid.d, self.tsih,
self.initiator_task_tag, self.cid, reserved, self.cmdsn,
local data = bin.pack(">CCCCICSCSSISSIILLA", opcode,
flags, self.ver_max, self.ver_min, len,
bit.lshift( self.isid.t, 6 ) + bit.band( self.isid.a, 0x3f),
self.isid.b, self.isid.c, self.isid.d, self.tsih,
self.initiator_task_tag, self.cid, reserved, self.cmdsn,
self.expstatsn, reserved, reserved, kvps )
return data
end
},
LoginResponse = {
-- Error messages
ErrorMsgs = {
[0x0000] = "Success",
@@ -172,13 +172,13 @@ Packet = {
[0x0301] = "Service unavailable",
[0x0302] = "Out of resources",
},
-- Error constants
Errors = {
SUCCESS = 0,
AUTH_FAILED = 0x0201,
},
--- Creates a new instance of LoginResponse
--
-- @return instance of LoginResponse
@@ -188,54 +188,54 @@ Packet = {
self.__index = self
return o
end,
--- Returns the error message
getErrorMessage = function( self )
return Packet.LoginResponse.ErrorMsgs[self.status_code] or "Unknown error"
end,
--- Returns the error code
getErrorCode = function( self ) return self.status_code or 0 end,
--- Creates a LoginResponse with data read from the socket
--
-- @return status true on success, false on failure
-- @return resp instance of LoginResponse
fromSocket = function( s )
local status, header = s:recv(48)
if ( not(status) ) then
if ( not(status) ) then
return false, "Failed to read header from socket"
end
local resp = Packet.LoginResponse:new()
local pos, len = bin.unpack(">I", header, 5)
resp.total_ahs_len = bit.rshift(len, 24)
resp.data_seg_len = bit.band(len, 0x00ffffff)
pos, resp.status_code = bin.unpack(">S", header, 37)
local pad = ( 4 - ( resp.data_seg_len % 4 ) )
pad = ( pad == 4 ) and 0 or pad
local status, data = s:recv( resp.data_seg_len + pad )
if ( not(status) ) then
if ( not(status) ) then
return false, "Failed to read data from socket"
end
resp.kvp = KVP:new()
for _, kvp in ipairs(stdnse.strsplit( "\0", data )) do
local k, v = kvp:match("(.*)=(.*)")
if ( v ) then resp.kvp:add( k, v ) end
end
return true, resp
end,
},
TextRequest = {
--- Creates a new instance of TextRequest
--
-- @return instance of TextRequest
@@ -243,7 +243,7 @@ Packet = {
local o = {}
setmetatable(o, self)
self.__index = self
o.opcode = Packet.Opcode.TEXT
o.opcode = Packet.Opcode.TEXT
o.flags = {}
o.flags.final = 0
o.flags.continue = 0
@@ -257,37 +257,37 @@ Packet = {
o.kvp = KVP:new()
return o
end,
--- Sets the final bit of the TextRequest
setFinal = function( self, b ) self.flags.final = ( b and 1 or 0 ) end,
--- Sets the continue bit of the TextRequest
setContinue = function( self, b ) self.flags.continue = ( b and 1 or 0 ) end,
--- Converts the class instance to string
--
-- @return string containing the converted instance
__tostring = function(self)
local flags = bit.lshift( ( self.flags.final or 0 ), 7 )
flags = flags + bit.lshift( (self.flags.continue or 0), 6 )
flags = flags + bit.lshift( (self.flags.continue or 0), 6 )
local kvps = tostring(self.kvp)
for i=1, (#kvps % 2) do kvps = kvps .. "\0" end
self.data_seg_len = #kvps
local len = bit.lshift( self.total_ahs_len, 24 ) + self.data_seg_len
local reserved = 0
local data = bin.pack(">CCSILIIIILLA", self.opcode, flags, reserved,
len, self.lun, self.initiator_task_tag, self.target_trans_tag,
len, self.lun, self.initiator_task_tag, self.target_trans_tag,
self.cmdsn, self.expstatsn, reserved, reserved, kvps)
return data
end,
},
TextResponse = {
--- Creates a new instance of TextResponse
--
-- @return instance of TextResponse
@@ -297,7 +297,7 @@ Packet = {
self.__index = self
return o
end,
--- Creates a TextResponse with data read from the socket
--
-- @return status true on success, false on failure
@@ -306,7 +306,7 @@ Packet = {
fromSocket = function( s )
local resp = Packet.TextResponse:new()
local textdata = ""
repeat
local status, header = s:recv(48)
local pos, _, flags, _, _, len = bin.unpack(">CCCCI", header)
@@ -314,23 +314,23 @@ Packet = {
resp.total_ahs_len = bit.rshift(len, 24)
resp.data_seg_len = bit.band(len, 0x00ffffff)
local data
status, data = s:recv( resp.data_seg_len )
textdata = textdata .. data
until( not(cont) )
resp.records = {}
local kvps = stdnse.strsplit( "\0", textdata )
local record
-- Each target record starts with one text key of the form:
-- TargetName=<target-name-goes-here>
-- Followed by zero or more address keys of the form:
-- TargetAddress=<hostname-or-ipaddress>[:<tcp-port>],
-- TargetAddress=<hostname-or-ipaddress>[:<tcp-port>],
-- <portal-group-tag>
for _, kvp in ipairs(kvps) do
local k, v = kvp:match("(.*)%=(.*)")
@@ -344,7 +344,7 @@ Packet = {
elseif ( k == "TargetAddress" ) then
record.addr = record.addr or {}
table.insert( record.addr, v )
elseif ( not(k) ) then
elseif ( not(k) ) then
-- this should be the ending empty kvp
table.insert(resp.records, record)
break
@@ -352,14 +352,14 @@ Packet = {
stdnse.print_debug("ERROR: iscsi.TextResponse: Unknown target record (%s)", k)
end
end
return true, resp
end,
},
--- Class handling a login request
LogoutRequest = {
--- Creates a new instance of LogoutRequest
--
-- @return instance of LogoutRequest
@@ -377,8 +377,8 @@ Packet = {
o.cmdsn = 0
o.expstatsn = 1
return o
end,
end,
--- Converts the class instance to string
--
-- @return string containing the converted instance
@@ -389,15 +389,15 @@ Packet = {
local data = bin.pack(">CCSILISSIILL", opcode, (0x80 + self.reasoncode),
reserved, len, reserved,self.initiator_task_tag, self.cid,
reserved, self.cmdsn, self.expstatsn, reserved, reserved )
return data
end,
},
--- Class handling the Logout response
LogoutResponse = {
--- Creates a new instance of LogoutResponse
--
-- @return instance of LogoutResponse
@@ -407,7 +407,7 @@ Packet = {
self.__index = self
return o
end,
--- Creates a LogoutResponse with data read from the socket
--
-- @return status true on success, false on failure
@@ -419,7 +419,7 @@ Packet = {
if ( not(status) ) then return status, header end
return true, resp
end
}
}
@@ -427,7 +427,7 @@ Packet = {
-- In addition it keeps track of both immediate packets and the amount of read
-- packets and updates cmdsn and expstatsn accordingly.
Comm = {
--- Creates a new instance of Comm
--
-- @return instance of Comm
@@ -440,39 +440,39 @@ Comm = {
o.socket = socket
return o
end,
--- Sends a packet and retrieves the response
--
-- @param out_packet instance of a packet to send
-- @param in_class class of the packet to read
-- @return status true on success, false on failure
-- @return r decoded instance of in_class
-- @return r decoded instance of in_class
exchange = function( self, out_packet, in_class )
local expstatsn = ( self.expstatsn == 0 ) and 1 or self.expstatsn
if ( out_packet.immediate and out_packet.immediate == 1 ) then
self.cmdsn = self.cmdsn + 1
end
out_packet.expstatsn = expstatsn
out_packet.cmdsn = self.cmdsn
self.socket:send( tostring( out_packet ) )
local status, r = in_class.fromSocket( self.socket )
self.expstatsn = self.expstatsn + 1
return status, r
end,
}
--- A buffered socket implementation
Socket =
{
{
--- Creates a new instance of Socket
--
-- @return instance of Socket
@@ -484,7 +484,7 @@ Socket =
o.Buffer = nil
return o
end,
--- Establishes a connection.
--
@@ -497,7 +497,7 @@ Socket =
self.Socket:set_timeout(10000)
return self.Socket:connect( hostid, port, protocol )
end,
--- Closes an open connection.
--
-- @return Status (true or false).
@@ -505,7 +505,7 @@ Socket =
close = function( self )
return self.Socket:close()
end,
--- Opposed to the <code>socket:receive_bytes</code> function, that returns
-- at least x bytes, this function returns the amount of bytes requested.
--
@@ -515,9 +515,9 @@ Socket =
-- err containing error message if status is false
recv = function( self, count )
local status, data
self.Buffer = self.Buffer or ""
if ( #self.Buffer < count ) then
status, data = self.Socket:receive_bytes( count - #self.Buffer )
if ( not(status) or #data < count - #self.Buffer ) then
@@ -525,13 +525,13 @@ Socket =
end
self.Buffer = self.Buffer .. data
end
data = self.Buffer:sub( 1, count )
self.Buffer = self.Buffer:sub( count + 1)
return true, data
return true, data
end,
--- Sends data over the socket
--
-- @return Status (true or false).
@@ -543,7 +543,7 @@ Socket =
--- Key/Value pairs class
KVP = {
--- Creates a new instance of KVP
--
-- @return instance of KVP
@@ -554,7 +554,7 @@ KVP = {
o.kvp = {}
return o
end,
--- Adds a key/value pair
--
-- @param key string containing the key name
@@ -562,12 +562,12 @@ KVP = {
add = function( self, key, value )
table.insert( self.kvp, {[key]=value} )
end,
--- Gets all values for a specific key
--
-- @param key string containing the name of the key to retrieve
-- @return values table containing all values for the specified key
get = function( self, key )
get = function( self, key )
local values = {}
for _, kvp in ipairs(self.kvp) do
for k, v in pairs( kvp ) do
@@ -578,7 +578,7 @@ KVP = {
end
return values
end,
--- Returns all key value pairs as string delimited by \0
-- eg. "key1=val1\0key2=val2\0"
--
@@ -592,12 +592,12 @@ KVP = {
end
return ret
end,
}
--- CHAP authentication class
CHAP = {
--- Calculate a CHAP - response
--
-- @param identifier number containing the CHAP identifier
@@ -607,12 +607,12 @@ CHAP = {
calcResponse = function( identifier, challenge, secret )
return openssl.md5( identifier .. secret .. challenge )
end,
}
--- The helper class contains functions with more descriptive names
Helper = {
--- Creates a new instance of the Helper class
--
-- @param host table as received by the script action function
@@ -626,7 +626,7 @@ Helper = {
o.socket = Socket:new()
return o
end,
--- Connects to the iSCSI target
--
-- @return status true on success, false on failure
@@ -638,7 +638,7 @@ Helper = {
self.comm = Comm:new( self.socket )
return true
end,
--- Attempts to discover accessible iSCSI targets on the remote server
--
-- @return status true on success, false on failure
@@ -648,18 +648,18 @@ Helper = {
-- err string containing an error message is status is false
discoverTargets = function( self )
local p = Packet.LoginRequest:new()
p:setTransit(true)
p:setNSG(Packet.LoginRequest.NSG.LoginOperationalNegotiation)
p.kvp:add( "InitiatorName", "iqn.1991-05.com.microsoft:nmap_iscsi_probe" )
p.kvp:add( "SessionType", "Discovery" )
p.kvp:add( "AuthMethod", "None" )
local status, resp = self.comm:exchange( p, Packet.LoginResponse )
if ( not(status) ) then
return false, ("ERROR: iscsi.Helper.discoverTargets: %s"):format(resp)
end
local auth_method = resp.kvp:get("AuthMethod")[1]
if ( auth_method:upper() ~= "NONE" ) then
return false, "ERROR: iscsi.Helper.discoverTargets: Unsupported authentication method"
@@ -674,9 +674,9 @@ Helper = {
p.kvp:add( "MaxRecvDataSegmentLength", "65536")
p.kvp:add( "DefaultTime2Wait", "0")
p.kvp:add( "DefaultTime2Retain", "60")
status, resp = self.comm:exchange( p, Packet.LoginResponse )
p = Packet.TextRequest:new()
p:setFinal(true)
p.kvp:add( "SendTargets", "All" )
@@ -685,13 +685,13 @@ Helper = {
if ( not(resp.records) ) then
return false, "iscsi.discoverTargets: response returned no targets"
end
for _, record in ipairs(resp.records) do
table.sort( record.addr, function(a, b) local c = ipOps.compare_ip(a:match("(.-):"), "le", b:match("(.-):")); return c end )
end
return true, resp.records
end,
--- Logs out from the iSCSI target
--
-- @return status true on success, false on failure
@@ -713,25 +713,25 @@ Helper = {
login = function( self, target_name, username, password, auth_method )
local auth_method = auth_method or "None"
if ( not(target_name) ) then
return false, "No target name specified"
end
if ( auth_method:upper()~= "NONE" and
if ( auth_method:upper()~= "NONE" and
auth_method:upper()~= "CHAP" ) then
return false, "Unknown authentication method"
end
local p = Packet.LoginRequest:new()
p:setTransit(true)
p:setNSG(Packet.LoginRequest.NSG.LoginOperationalNegotiation)
p.kvp:add( "InitiatorName", "iqn.1991-05.com.microsoft:nmap_iscsi_probe" )
p.kvp:add( "SessionType", "Normal" )
p.kvp:add( "TargetName", target_name )
p.kvp:add( "AuthMethod", auth_method )
if ( not(self.comm) ) then
return false, "ERROR: iscsi.Helper.login: Not connected"
end
@@ -746,28 +746,28 @@ Helper = {
elseif ( auth_method:upper()=="NONE" ) then
return true, resp
end
p = Packet.LoginRequest:new()
p.kvp:add( "CHAP_A", "5" )
status, resp = self.comm:exchange( p, Packet.LoginResponse )
if ( not(status) ) then
return false, ("ERROR: iscsi.Helper.login: %s"):format(resp)
end
local alg = resp.kvp:get("CHAP_A")[1]
if ( alg ~= "5" ) then return false, "Unsupported authentication algorithm" end
local chall = resp.kvp:get("CHAP_C")[1]
if ( not(chall) ) then return false, "Failed to decode challenge" end
chall = bin.pack("H", chall:sub(3))
local ident = resp.kvp:get("CHAP_I")[1]
if (not(ident)) then return false, "Failed to decoded identifier" end
ident = string.char(tonumber(ident))
local resp = CHAP.calcResponse( ident, chall, password )
resp = "0x" .. select(2, bin.unpack("H16", resp))
p = Packet.LoginRequest:new()
p:setImmediate(true)
p:setTransit(true)
@@ -783,13 +783,13 @@ Helper = {
if ( resp:getErrorCode() ~= Packet.LoginResponse.Errors.SUCCESS ) then
return false, "Login failed"
end
return true, resp
end,
--- Disconnects the socket from the server
close = function(self) self.socket:close() end
}

View File

@@ -15,20 +15,20 @@ local table = require('table')
_ENV = stdnse.module("isns", stdnse.seeall);
iSCSI = {
NodeType = {
TARGET = 1,
INITIATOR = 2,
INITIATOR = 2,
CONTROL = 4,
}
}
Header = {
VERSION = 1,
--
-- Creates a header instance
--
@@ -41,7 +41,7 @@ Header = {
new = function(self, func_id, pdu_len, flags, trans_id, seq_id)
local o = {
ver = Header.VERSION,
func_id = func_id,
func_id = func_id,
flags = flags,
trans_id = trans_id,
seq_id = seq_id,
@@ -51,7 +51,7 @@ Header = {
self.__index = self
return o
end,
--
-- Parses a opaque string and creates a new Header instance
--
@@ -60,25 +60,25 @@ Header = {
parse = function(data)
local hdr = Header:new()
local pos
pos, hdr.ver, hdr.func_id, hdr.pdu_len, hdr.flags, hdr.trans_id,
hdr.seq_id = bin.unpack(">SSSSSS", data)
return hdr
end,
--
-- Converts the instance to an opaque string
-- @return str containing an opaque string
__tostring = function(self)
return bin.pack(">SSSSSS", self.ver, self.func_id,
return bin.pack(">SSSSSS", self.ver, self.func_id,
self.pdu_len, self.flags, self.trans_id, self.seq_id )
end
}
Attribute = {
Tag = {
ISNS_TAG_DELIMITER = 0,
ISNS_TAG_ENTITY_IDENTIFIER = 1,
@@ -164,7 +164,7 @@ Attribute = {
ISNS_VENDOR_SPECIFIC_DDSET_BASE = 1281,
ISNS_VENDOR_SPECIFIC_OTHER_BASE = 1537,
},
--
-- Creates a new Attribute instance
--
@@ -178,7 +178,7 @@ Attribute = {
self.__index = self
return o
end,
--
-- Creates a new Attribute instance
--
@@ -187,20 +187,20 @@ Attribute = {
parse = function(data)
local attr = Attribute:new()
local pos
pos, attr.tag, attr.len = bin.unpack(">II", data)
pos, attr.val = bin.unpack(">A" .. attr.len, pos)
return attr
end,
--
-- Converts the instance to an opaque string
-- @return str containing an opaque string
__tostring = function(self)
return bin.pack(">IIA", self.tag, self.len, self.val)
end,
}
Attributes = {
@@ -214,7 +214,7 @@ Attributes = {
self.__index = self
return o
end,
--
-- Adds a new Attribute to the table
-- @param tag number containing the tag number
@@ -223,7 +223,7 @@ Attributes = {
add = function(self, tag, val, len)
table.insert(self, Attribute:new(tag, val, len))
end,
--
-- Converts the instance to an opaque string
-- @return str containing an opaque string
@@ -234,11 +234,11 @@ Attributes = {
end
return str
end,
}
Request = {
FuncId = {
DevAttrReg = 0x0001,
DevAttrQry = 0x0002,
@@ -255,7 +255,7 @@ Request = {
ESI = 0x000D,
Heartbeat = 0x000E,
},
--
-- Creates a new Request message
-- @param func_id number containing the function ID of the message
@@ -274,7 +274,7 @@ Request = {
self.__index = self
return o
end,
--
-- Converts the instance to an opaque string
-- @return str containing an opaque string
@@ -282,12 +282,12 @@ Request = {
return tostring(self.header) .. tostring(self.data) ..
( self.auth and self.auth or "" )
end,
}
Response = {
Error = {
[0] = "Successful",
[1] = "Unknown Error",
@@ -314,7 +314,7 @@ Response = {
[22] = "Invalid Deregistration",
[23] = "Registration Feature Not Supported",
},
--
-- Creates a new Response instance
-- @return o new instance of Response
@@ -324,7 +324,7 @@ Response = {
self.__index = self
return o
end,
--
-- Creates a new Response instance
--
@@ -334,12 +334,12 @@ Response = {
local hdr = Header.parse(data)
local pos = #(tostring(hdr)) + 1
local resp = Response:new()
pos, resp.error = bin.unpack(">I", data, pos)
if ( resp.error ~= 0 ) then
return resp
end
while( pos < #data ) do
local tag, len, val
pos, tag, len = bin.unpack(">II", data, pos)
@@ -348,12 +348,12 @@ Response = {
end
return resp
end,
}
Session = {
--
-- Creates a new Session instance
-- @param host table
@@ -370,7 +370,7 @@ Session = {
self.__index = self
return o
end,
--
-- Connects to the server
-- @return status true on success, false on failure
@@ -379,7 +379,7 @@ Session = {
self.socket:set_timeout(5000)
return self.socket:connect(self.host, self.port)
end,
--
-- Sends data to the server
-- @return status true on success, false on failure
@@ -392,13 +392,13 @@ Session = {
-- update the sequence and transaction ID's
req.header.seq_id = self.seq_id
req.header.trans_id = self.trans_id
local status, err = self.socket:send(tostring(req))
self.trans_id = self.trans_id + 1
return status, err
end,
--
-- Receives data from the server
-- @return status true on success, false on failure
@@ -409,19 +409,19 @@ Session = {
if ( not(status) ) then
return status, buf_hdr
end
local hdr = Header.parse(buf_hdr)
-- receive the data
local buf_data = nil
status, buf_data = self.socket:receive_buf(match.numbytes(hdr.pdu_len), true)
if ( not(status) ) then
return status, buf_data
end
return true, Response.parse(buf_hdr .. buf_data)
end,
close = function(self)
return self.close()
end
@@ -429,8 +429,8 @@ Session = {
Helper = {
--
--
-- Creates a new Helper instance
-- @param host param
-- @param port param
@@ -441,14 +441,14 @@ Helper = {
self.__index = self
return o
end,
--
-- Connects to the server
-- @return status true on success, false on failure
connect = function(self)
return self.session:connect()
end,
--
-- Lists portals
-- @return status true on success, false on failure
@@ -464,23 +464,23 @@ Helper = {
attribs:add(Attribute.Tag.ISNS_TAG_ENTITY_IDENTIFIER)
local flags = 0x8c00 -- Sender is iSNS client, Last PDU, First PDU
local req = Request:new(Request.FuncId.DevAttrQry, flags, tostring(attribs))
if ( not(self.session:send(req)) ) then
return false, "Failed to send message to server"
end
local status, resp = self.session:receive()
if ( not(status) ) then
return false, "Failed to receive message from server"
end
local results = {}
local addr, proto, port
for _, attr in ipairs(resp.attrs) do
if ( attr.tag == Attribute.Tag.ISNS_TAG_PORTAL_IP_ADDRESS ) then
addr = attr.val
local pos, is_ipv4 = bin.unpack("A12", addr)
local pos, is_ipv4 = bin.unpack("A12", addr)
if ( is_ipv4 == "\0\0\0\0\0\0\0\0\0\0\xFF\xFF" ) then
local pos, bin_ip = bin.unpack("B4", addr, 13)
addr = ipops.bin_to_ip(bin_ip)
@@ -491,7 +491,7 @@ Helper = {
elseif ( attr.tag == Attribute.Tag.ISNS_TAG_PORTAL_TCP_UDP_PORT ) then
local pos, s1
pos, s1, port = bin.unpack(">SS", attr.val)
if ( s1 == 1 ) then
proto = "udp"
elseif ( s1 == 0 ) then
@@ -506,12 +506,12 @@ Helper = {
end
return true, results
end,
--
-- Lists iSCSI nodes
-- @return status true on success, false on failure
-- @return resulst list of iSCSI nodes, err string on failure
listISCINodes = function(self)
listISCINodes = function(self)
local attribs = Attributes:new()
local name = "iqn.control.node\0por"
attribs:add(Attribute.Tag.ISNS_TAG_ISCSI_NAME, name)
@@ -521,17 +521,17 @@ Helper = {
attribs:add(Attribute.Tag.ISNS_TAG_ISCSI_NODE_TYPE)
local flags = 0x8c00 -- Sender is iSNS client, Last PDU, First PDU
local req = Request:new(Request.FuncId.DevAttrQry, flags, tostring(attribs))
if ( not(self.session:send(req)) ) then
return false, "Failed to send message to server"
end
local status, resp = self.session:receive()
if ( not(status) ) then
return false, "Failed to receive message from server"
end
local name, ntype
local results = {}
for _, attr in ipairs(resp.attrs) do
@@ -553,14 +553,14 @@ Helper = {
table.insert(results, { name = name:match("^([^\0]*)"), type = ntype })
name, ntype = nil, nil
end
end
end
return true, results
end,
close = function(self)
return self.session:close()
end,
}
return _ENV;

View File

@@ -1,20 +1,20 @@
--- JDWP (Java Debug Wire Protocol) library implementing a set of commands needed to
-- use remote debugging port and inject java bytecode.
--- JDWP (Java Debug Wire Protocol) library implementing a set of commands needed to
-- use remote debugging port and inject java bytecode.
--
-- There are two basic packet types in JDWP protool.
-- Command packet and reply packet. Command packets are sent by
-- There are two basic packet types in JDWP protool.
-- Command packet and reply packet. Command packets are sent by
-- a debugger to a remote port which replies with a reply packet.
--
-- Simple handshake is needed to start the communication.
--
-- Simple handshake is needed to start the communication.
-- The debugger sends a "JDWP-Handshake" string and gets the same as a reply.
-- Each (command and reply packet) has an id field since communication can be asynchronous.
-- Packet id can be monothonicaly increasing.
-- Although communication can be asynchronous, it is not (at least in my tests) so the same
-- packet id can be used for all communication.
--
-- packet id can be used for all communication.
--
-- To start the connection, script should call <code>jdwp.connect()</code> which returns success
-- status and a socket. All other protocol functions require a socket as their first parameter.
--
--
-- Example of initiating connection:
-- <code>
-- local status,socket = jdwp.connect(host,port)
@@ -27,7 +27,7 @@
--
-- References:
-- * http://docs.oracle.com/javase/6/docs/technotes/guides/jpda/jdwp-spec.html
--
--
--@copyright Same as Nmap--See http://nmap.org/book/man-legal.html
--@author Aleksandar Nikolic
--
@@ -42,7 +42,7 @@ local nmap = require "nmap"
_ENV = stdnse.module("jdwp", stdnse.seeall)
-- JDWP protocol specific constants
-- JDWP protocol specific constants
JDWP_CONSTANTS = {
handshake = "JDWP-Handshake" -- Connection initialization handshake
}
@@ -105,7 +105,7 @@ ERROR_CODES = {
[509] = "TRANSPORT_LOAD Unable to load the transport.",
[510] = "TRANSPORT_INIT Unable to initialize the transport.",
[511] = "NATIVE_METHOD",
[512] = "INVALID_COUNT The count is invalid."
[512] = "INVALID_COUNT The count is invalid."
}
-- JDWP protocol Command packet as described at
@@ -123,17 +123,17 @@ JDWPCommandPacket = {
data = data
}
setmetatable(o, self)
self.__index = self
self.__index = self
return o
end,
-- Packs command packet as a string od bytes, ready to be sent
-- to the target debugee.
pack = function(self)
local packed_packet
if self.data == nil then
if self.data == nil then
packed_packet = bin.pack(">I",11) -- lenght - minimal header is 11 bytes
else
else
packed_packet = bin.pack(">I",11 + #self.data) -- lenght with data
end
packed_packet = packed_packet .. bin.pack(">I",self.id)
@@ -147,7 +147,7 @@ JDWPCommandPacket = {
end
}
-- JDWP protocol Reply packet as described at
-- JDWP protocol Reply packet as described at
-- http://docs.oracle.com/javase/6/docs/technotes/guides/jpda/jdwp-spec.html
-- Reply packets are recognized by 0x80 in flag field.
JDWPReplyPacket = {
@@ -161,10 +161,10 @@ JDWPReplyPacket = {
data = data -- reply data, contents depend on the command
}
setmetatable(o, self)
self.__index = self
self.__index = self
return o
end,
-- Parses the reply into JDWPReplyPacket table.
parse_reply = function(self,reply_packet)
local pos,length,id,flags,error_code,data
@@ -172,21 +172,21 @@ JDWPReplyPacket = {
pos, id = bin.unpack(">I",reply_packet,pos)
pos, flags = bin.unpack(">C",reply_packet,pos)
pos, error_code = bin.unpack(">S",reply_packet,pos)
data = string.sub(reply_packet,pos)
data = string.sub(reply_packet,pos)
if flags == 0x80 then
return true, JDWPReplyPacket:new(length,id,error_code,data)
end
stdnse.print_debug(2,"JDWP error parsing reply. Wrong reply packet flag. Raw data: ", stdnse.tohex(reply_packet))
return false, "JDWP error parsing reply."
end
}
--- Negotiates the initial debugger-debugee handshake.
--
--@param host Host to connect to.
--@param port Port to connect to.
--@return (status,socket) If status is false, socket is error message, otherwise socket is
--@return (status,socket) If status is false, socket is error message, otherwise socket is
-- a newly created socket with initial handshake finished.
function connect(host,port)
local status, result,err
@@ -195,7 +195,7 @@ function connect(host,port)
local status, err = socket:connect(host, port)
if not status then
stdnse.print_debug(2,"JDWP could not connect: %s",err)
return status, err
return status, err
end
status, err = socket:send(JDWP_CONSTANTS.handshake)
if not status then
@@ -215,7 +215,7 @@ function connect(host,port)
end
--- Helper function to pack regular string into UTF-8 string.
--
--
--@param data String to pack into UTF-8.
--@return utf8_string UTF-8 packed string. Four bytes lenght followed by the string its self.
function toUTF8(data)
@@ -223,8 +223,8 @@ function toUTF8(data)
return utf8_string
end
--- Helper function to read all Reply packed data which might be fragmented
-- over multipe packets.
--- Helper function to read all Reply packed data which might be fragmented
-- over multipe packets.
--
--@param socket Socket to receive from.
--@return (status,data) If status is false, error string is returned, else data contains read ReplyPacket bytes.
@@ -238,17 +238,17 @@ function receive_all(socket)
while expected_length > #data do -- read until we get all the ReplyPacket data
status,result = socket:receive()
if not status then
return true, data -- if somethign is wrong,return partial data
return true, data -- if somethign is wrong,return partial data
end
data = data .. result
end
return true,data
return true,data
end
--- Helper function to extract ascii string from UTF-8
--
-- Writen in this way so it can be used interchangeably with bin.unpack().
--
--
--@param data Data from which to extract the string.
--@param pos Offset into data string where to begin.
--@return (pos,ascii_string) Returns position where the string extraction ended and actuall ascii string.
@@ -268,32 +268,32 @@ end
--- Helper function that sends the Command packet and parses the reply.
--
--@param socket Socket to use to send the command.
--@param command <code>JDWPCommandPacket</code> to send.
--@param command <code>JDWPCommandPacket</code> to send.
--@return (status,data) If status is false, data contains specified error code message. If true, data contains data from the reply.
function executeCommand(socket,command)
socket:send(command:pack())
local status, result = receive_all(socket)
if not status then
return false, "JDWP executeCommand() didn't get a reply."
end
end
local reply_packet
status, reply_packet = JDWPReplyPacket:parse_reply(result)
status, reply_packet = JDWPReplyPacket:parse_reply(result)
if not status then
return false, reply_packet
end
end
if not (reply_packet.error_code == 0) then -- we have a packet with error , error code 0 means no error occured
return false, ERROR_CODES[reply_packet.error_code]
end
end
local data = reply_packet.data
return true, data
end
--- VirtualMachine Command Set (1)
--- VirtualMachine Command Set (1)
-- Commands targeted at the debugggee virtual machine.
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_VirtualMachine
--- Version Command (1)
--- Version Command (1)
-- Returns the JDWP version implemented by the target VM as a table.
--
-- Returns a table with following values:
@@ -303,10 +303,10 @@ end
-- * 'vmVersion' String representing version of the debuggee VM.
-- * 'vmName' Name of the debuggee VM.
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_VirtualMachine_Version
--
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@return (status,version_info) If status is false, version_info is an error string, else it contains remote VM version info.
--@param id Packet id.
--@return (status,version_info) If status is false, version_info is an error string, else it contains remote VM version info.
function getVersion(socket,id)
local command = JDWPCommandPacket:new(id,1,1,nil) -- Version Command (1)
local status, data = executeCommand(socket,command)
@@ -332,17 +332,17 @@ end
--- Classes by Signature command (2)
-- Returns reference types for all the classes loaded by the target VM which match the given signature.
--
--
-- Given the class signature (like "Ljava/lang/Class") returns it's reference ID which can be used to reference that class
-- in other commands. Returns a list of tables containing following values:
-- * 'refTypeTag' JNI type tag
-- * 'referenceTypeID' Reference type of the class
-- * 'referenceTypeID' Reference type of the class
-- * 'status' Current class status.
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_VirtualMachine_ClassesBySignature
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param signature Signature of the class.
--@param id Packet id.
--@param signature Signature of the class.
--@return (status,classes) If status is false, classes is an error string, else it contains list of found classes.
function getClassBySignature(socket,id,signature)
local command = JDWPCommandPacket:new(id,1,2,toUTF8(signature))
@@ -356,11 +356,11 @@ function getClassBySignature(socket,id,signature)
local pos,number_of_classes = bin.unpack(">i",data)
for i = 1, number_of_classes do
local class_info = {
local class_info = {
refTypeTag = nil,
referenceTypeID = nil,
status = nil
}
}
pos, class_info.refTypeTag = bin.unpack("c",data,pos)
pos, class_info.referenceTypeID = bin.unpack(">L",data,pos)
pos, class_info.status = bin.unpack(">i",data,pos)
@@ -369,13 +369,13 @@ function getClassBySignature(socket,id,signature)
return true, classes
end
--- AllThreads Command (4)
--- AllThreads Command (4)
-- Returns all threads currently running in the target VM .
--
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_VirtualMachine_AllThreads
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param id Packet id.
--@return (status, threads) If status is false threads contains an error string, else it conatins a list of all threads in the debuggee VM.
function getAllThreads(socket,id)
local command = JDWPCommandPacket:new(id,1,4,nil)
@@ -387,7 +387,7 @@ function getAllThreads(socket,id)
-- parse data
local pos,number_of_threads = bin.unpack(">i",data)
local threads = {}
for i = 1, number_of_threads do
for i = 1, number_of_threads do
local thread
pos, thread = bin.unpack(">L",data,pos)
table.insert(threads,thread)
@@ -395,13 +395,13 @@ function getAllThreads(socket,id)
return true, threads
end
--- Resume Command (9)
--- Resume Command (9)
-- Resumes execution of the application after the suspend command or an event has stopped it.
--
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_VirtualMachine_Resume
--
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param id Packet id.
--@return (status, nil) If status is false error string is returned, else it's null since this command has no data in the reply.
function resumeVM(socket,id)
local command = JDWPCommandPacket:new(id,1,9,nil)
@@ -409,9 +409,9 @@ function resumeVM(socket,id)
if not status then
stdnse.print_debug(2,"JDWP resumeVM() error: %s", data)
return false,data
end
end
-- wait for event notification
status, data = receive_all(socket)
status, data = receive_all(socket)
if not status then
stdnse.print_debug(2,"JDWP resumeVM() event notification failed: %s", data)
end
@@ -424,7 +424,7 @@ end
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_VirtualMachine_CreateString
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param id Packet id.
--@param ascii_string String to create.
--@return (status, stringID) If status is false error string is returned, else stringID is newly created string.
function createString(socket,id,ascii_string)
@@ -433,24 +433,24 @@ function createString(socket,id,ascii_string)
if not status then
stdnse.print_debug(2,"JDWP createString() error: %s", data)
return false,data
end
end
local _,stringID = bin.unpack(">L",data)
return true, stringID
end
--- AllClassesWithGeneric Command (20)
-- Returns reference types and signatures for all classes currently loaded by the target VM.
--
-- Returns a list of tables containing following info:
-- * 'refTypeTag' Kind of following reference type.
-- * 'typeID' Loaded reference type
-- * 'signature' The JNI signature of the loaded reference type.
--
-- Returns a list of tables containing following info:
-- * 'refTypeTag' Kind of following reference type.
-- * 'typeID' Loaded reference type
-- * 'signature' The JNI signature of the loaded reference type.
-- * 'genericSignature' The generic signature of the loaded reference type or an empty string if there is none.
-- * 'status' The current class status.
-- * 'status' The current class status.
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_VirtualMachine_AllClassesWithGeneric
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param id Packet id.
--@return (status, all_classes) If status is false all_classes contains an error string, else it is a list of loaded classes information.
function getAllClassesWithGeneric(socket,id)
local command = JDWPCommandPacket:new(id,1,20,nil)
@@ -462,7 +462,7 @@ function getAllClassesWithGeneric(socket,id)
-- parse data
local all_classes = {}
local pos,number_of_classes = bin.unpack(">i",data)
for i = 0 , number_of_classes do
local class = {
refTypeTag = nil,
@@ -482,7 +482,7 @@ function getAllClassesWithGeneric(socket,id)
return true, all_classes
end
--- ReferenceType Command Set (2)
--- ReferenceType Command Set (2)
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ReferenceType
@@ -492,7 +492,7 @@ end
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ReferenceType_SignatureWithGeneric
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param id Packet id.
--@param classID Reference type id of the class to get the signature from.
--@return (status, signature) If status is false signature contains an error string, else it is class signature (like "Ljava/lang/Class").
function getSignatureWithGeneric(socket,id,classID)
@@ -512,14 +512,14 @@ end
--
-- Returns a list of tables containing following fields for each method:
-- * 'methodID' Method ID which can be used to call the method.
-- * 'name' The name of the method.
-- * 'signature' The JNI signature of the method.
-- * 'generic_signature' The generic signature of the method, or an empty string if there is none.
-- * 'name' The name of the method.
-- * 'signature' The JNI signature of the method.
-- * 'generic_signature' The generic signature of the method, or an empty string if there is none.
-- * 'modBits' The modifier bit flags (also known as access flags) which provide additional information on the method declaration.
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ReferenceType_MethodsWithGeneric
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param id Packet id.
--@param classID Reference type id of the class to get the list of methods.
--@return (status, signature) If status is false methods contains an error string, else it a list of methods information.
function getMethodsWithGeneric(socket,id,classID)
@@ -529,7 +529,7 @@ function getMethodsWithGeneric(socket,id,classID)
stdnse.print_debug(2,"JDWP getMethodsWithGeneric() error : %s",data)
return false,data
end
-- parse data
-- parse data
local methods = {}
local pos,number_of_methods = bin.unpack(">i",data)
@@ -540,7 +540,7 @@ function getMethodsWithGeneric(socket,id,classID)
signature = nil,
generic_signature = nil,
modBits = nil
}
}
pos, method_info.methodID = bin.unpack(">i",data,pos)
pos,method_info.name = extract_string(data,pos)
pos, method_info.signature = extract_string(data,pos)
@@ -554,14 +554,14 @@ end
--- ClassType Command Set (3)
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ClassType
--- InvokeMethod Command (3)
--- InvokeMethod Command (3)
-- Invokes a class' static method and returns the reply data.
--
--
-- Reply data can vary so parsing is left to the function caller.
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ClassType_InvokeMethod
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param id Packet id.
--@param classID Reference type id of the class.
--@param methodID ID of the static method to call.
--@numberOfArguments Number of method arguments.
@@ -575,7 +575,7 @@ function invokeStaticMethod(socket,id,classID,methodID,numberOfArguments,argumen
else
params = bin.pack(">Lii",classID,methodID,numberOfArguments) .. arguments .. bin.pack(">i",options)
end
local command = JDWPCommandPacket:new(id,3,3,params)
local status, data = executeCommand(socket,command)
if not status then
@@ -586,16 +586,16 @@ function invokeStaticMethod(socket,id,classID,methodID,numberOfArguments,argumen
end
--- NewInstance Command (4)
-- Creates a new object of this type, invoking the specified constructor.
-- Creates a new object of this type, invoking the specified constructor.
-- The constructor method ID must be a member of the class type.
--
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ClassType_NewInstance
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param id Packet id.
--@param classID Reference type id of the class.
--@param threadID The thread in which to invoke the constructor.
--@param methodID The constructor to invoke.
--@param threadID The thread in which to invoke the constructor.
--@param methodID The constructor to invoke.
--@numberOfArguments Number of constructor arguments.
--@arguments Already packed arguments.
--@return (status, objectID) If status is false data contains an error string, else it contains a reference ID of the newly created object.
@@ -606,7 +606,7 @@ function newClassInstance(socket,id,classID,threadID,methodID,numberOfArguments,
else
params = bin.pack(">LLii",classID,threadID,methodID,numberOfArguments) .. arguments
end
local command = JDWPCommandPacket:new(id,3,4,params)
local status, data = executeCommand(socket,command)
if not status then
@@ -621,16 +621,16 @@ function newClassInstance(socket,id,classID,threadID,methodID,numberOfArguments,
return true,objectID
end
--- ArrayType Command Set (4)
--- ArrayType Command Set (4)
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ArrayType
--- NewInstance Command (1)
-- Creates a new array object of the specified type with a given length.
-- Creates a new array object of the specified type with a given length.
--
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ArrayType_NewInstance
--
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param id Packet id.
--@param arrayType The array type of the new instance as per JNI (http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/types.html#wp9502).
--@param length Length of the new array.
--@return (status, arrayID) If status is false data contains an error string, else it contains a reference ID of the newly created array.
@@ -642,23 +642,23 @@ function newArrayInstance(socket,id,arrayType,length)
stdnse.print_debug(2,"JDWP newArrayInstance() error: %s", data)
return false,data
end
local pos,_ , tag, arrayID
local pos,_ , tag, arrayID
pos, tag = bin.unpack("C",data)
_, arrayID = bin.unpack(">L",data,pos)
return true, arrayID
end
--- ObjectReference Command Set (9)
--- ObjectReference Command Set (9)
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ObjectReference
--- ReferenceType Command (1)
-- Returns the runtime type of the object. The runtime type will be a class or an array.
-- Returns the runtime type of the object. The runtime type will be a class or an array.
--
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ObjectReference_ReferenceType
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ObjectReference_ReferenceType
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param objectID The ID of an object.
--@param id Packet id.
--@param objectID The ID of an object.
--@return (status, runtime_type) If status is false runtime_type contains an error string, else it contains runtime type of an object.
function getRuntimeType(socket,id,objectID)
local command = JDWPCommandPacket:new(id,9,1,bin.pack(">L",objectID))
@@ -666,35 +666,35 @@ function getRuntimeType(socket,id,objectID)
if not status then
stdnse.print_debug(2,"JDWP resumeVM() error: %s", data)
return false,data
end
end
local _,tag,runtime_type = bin.unpack(">CL",data)
stdnse.print_debug("runtime type: %d",runtime_type)
return true,runtime_type
end
--- InvokeMethod Command (6)
-- Invokes a instance method with specified parameters.
--
--- InvokeMethod Command (6)
-- Invokes a instance method with specified parameters.
--
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ObjectReference_InvokeMethod
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param objectID The ID of an object.
--@param threadID The thread in which to invoke.
--@param classID The class type.
--@param id Packet id.
--@param objectID The ID of an object.
--@param threadID The thread in which to invoke.
--@param classID The class type.
--@param methodID ID of the method to invoke.
--@param numberOfArguments Number of method arguments.
--@param numberOfArguments Number of method arguments.
--@arguments Already packed arguments.
--@return (status, data) If status is false data contains an error string, else it contains a reply data and needs to be parsed manualy.
function invokeObjectMethod(socket,id,objectID,threadID,classID,methodID,numberOfArguments,arguments)
local params
if numberOfArguments == 0 then
params = bin.pack(">LLLii",objectID,threadID,classID,methodID,numberOfArguments)
else
params = bin.pack(">LLLii",objectID,threadID,classID,methodID,numberOfArguments) .. arguments
end
local command = JDWPCommandPacket:new(id,9,6,params)
local status, data = executeCommand(socket,command)
if not status then
@@ -705,17 +705,17 @@ function invokeObjectMethod(socket,id,objectID,threadID,classID,methodID,numberO
return true,data
end
--- StringReference Command Set (10)
--- StringReference Command Set (10)
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_StringReference
--- Value Command (1)
-- Returns the characters contained in the string.
-- Returns the characters contained in the string.
--
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_StringReference_Value
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param stringID The ID of a string to read.
--@param id Packet id.
--@param stringID The ID of a string to read.
--@return (status, data) If status is false result contains an error string, else it contains read string.
function readString(socket,id,stringID)
local command = JDWPCommandPacket:new(id,10,1,bin.pack(">L",stringID))
@@ -723,22 +723,22 @@ function readString(socket,id,stringID)
if not status then
stdnse.print_debug(2,"JDWP readString() error: %s", data)
return false,data
end
end
local _,result = extract_string(data,0)
return true,result
end
--- ThreadReference Command Set (11)
--- ThreadReference Command Set (11)
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ThreadReference
--- Name Command (1)
-- Returns the thread name.
-- Returns the thread name.
--
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ThreadReference_Name
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param id Packet id.
--@param threadID The ID of a thread.
--@return (status, thread_name) If status is false thread_name contains an error string, else it contains thread's name.
function getThreadName(socket,id,threadID)
@@ -751,16 +751,16 @@ function getThreadName(socket,id,threadID)
end
-- parse data
local _,thread_name = extract_string(data,0)
return true, thread_name
return true, thread_name
end
--- Suspend Command (2)
-- Suspends the thread.
-- Suspends the thread.
--
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ThreadReference_Suspend
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param id Packet id.
--@param threadID The ID of a thread.
--@return (status, thread_name) If status is false an error string is returned, else it's nil.
function suspendThread(socket,id,threadID)
@@ -770,7 +770,7 @@ function suspendThread(socket,id,threadID)
if not status then
stdnse.print_debug(2,"JDWP suspendThread() error: %s", data)
return false,data
end
end
return true, nil
end
@@ -781,7 +781,7 @@ end
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ThreadReference_Status
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param id Packet id.
--@param threadID The ID of a thread.
--@return (status, thread_name) If status is false an error string is returned, else unparsed thread status data.
function threadStatus(socket,id,threadID)
@@ -791,12 +791,12 @@ function threadStatus(socket,id,threadID)
if not status then
stdnse.print_debug(2,"JDWP threadStatus() error: %s", data)
return false,data
end
end
stdnse.print_debug("threadStatus %s",stdnse.tohex(data))
return true, data
end
--- ArrayReference Command Set (13)
--- ArrayReference Command Set (13)
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ArrayReference
--- SetValues Command (3)
@@ -805,7 +805,7 @@ end
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ArrayReference_SetValues
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param id Packet id.
--@param objectID The ID of an array object.
--@return (status, data) If status is false an error string is returned, else it's nil.
function setArrayValues(socket,id,objectID,idx,values)
@@ -816,18 +816,18 @@ function setArrayValues(socket,id,objectID,idx,values)
stdnse.print_debug(2,"JDWP setArrayValues() error: %s", data)
return false,data
end
return true, nil
return true, nil
end
--- EventRequest Command Set (15)
--- EventRequest Command Set (15)
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_EventRequest
--- Uses Set Command (1) to set singlesteping to specified thread.
--
--
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_EventRequest_Set
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param id Packet id.
--@param threadID The ID of the thread.
--@return (status, requestID) If status is false an error string is returned, else it contains assigned request id.
function setThreadSinglestep(socket,id,threadID)
@@ -837,9 +837,9 @@ function setThreadSinglestep(socket,id,threadID)
if not status then
stdnse.print_debug(2,"JDWP setThreadSinglestep() error: %s", data)
return false,data
end
end
local _, requestID = bin.unpack(">i",data)
return true, requestID
return true, requestID
end
--- Uses Clear Command (2) to unset singlesteping from a thread by specified event.
@@ -847,7 +847,7 @@ end
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_EventRequest_Clear
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param id Packet id.
--@param eventID The ID of the thread.
--@return (status, requestID) If status is false an error string is returned, else it's nil.
function clearThreadSinglestep(socket,id,eventID)
@@ -857,21 +857,21 @@ function clearThreadSinglestep(socket,id,eventID)
if not status then
stdnse.print_debug(2,"JDWP clearThreadSinglestep() error: %s", data)
return false,data
end
end
return true,nil
end
--- ClassObjectReference Command Set (17)
--- ClassObjectReference Command Set (17)
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ClassObjectReference
--- ReflectedType Command (1)
-- Returns the reference type reflected by this class object.
-- Returns the reference type reflected by this class object.
--
-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ClassObjectReference_ReflectedType
--
--@param socket Socket to use to send the command.
--@param id Packet id.
--@param id Packet id.
--@param classObjectID The ID of the object.
--@return (status, reflected_type) If status is false an error string is returned, else reflected_type is object's reference type.
function getReflectedType(socket,id,classObjectID)
@@ -881,13 +881,13 @@ function getReflectedType(socket,id,classObjectID)
if not status then
stdnse.print_debug(2,"JDWP getReflectedType() error: %s", data)
return false,data
end
end
local reflected_type = {
refTypeTag = nil,
typeID = nil
}
_,reflected_type.refTypeTag, reflected_type.typeID = bin.unpack(">CL",data)
return true, reflected_type
end
@@ -914,7 +914,7 @@ function findMethod(socket,class,methodName,skipFirst)
end
end
end
end
end
return methodID
end
@@ -948,7 +948,7 @@ function injectClass(socket,class_bytes)
return false
end
stdnse.print_debug("Found byte[] id %d",byteArrayID)
-- find SecureClassLoader id by signature
status, classes = getClassBySignature(socket,0,"Ljava/security/SecureClassLoader;")
if not status then
@@ -956,19 +956,19 @@ function injectClass(socket,class_bytes)
end
local secureClassLoader = classes[1].referenceTypeID
stdnse.print_debug("Found SecureClassLoader id %d",secureClassLoader)
-- find SecureClassLoader() constructor
-- find SecureClassLoader() constructor
local constructorMethodID = findMethod(socket,secureClassLoader,"<init>",true)
-- find ClassLoader id by signature
status, classes = getClassBySignature(socket,0,"Ljava/lang/ClassLoader;")
if not status then
return false
end
end
local classLoader = classes[1].referenceTypeID
stdnse.print_debug("Found ClassLoader id %d",classes[1].referenceTypeID)
-- find ClassLoader's defineClass() method
local defineClassMethodID = findMethod(socket,classLoader,"defineClass",false)
-- find ClassLoader's resolveClass() method
local resolveClassMethodID = findMethod(socket,classLoader,"resolveClass",false)
local resolveClassMethodID = findMethod(socket,classLoader,"resolveClass",false)
if constructorMethodID == nil or defineClassMethodID == nil or resolveClassMethodID == nil then
stdnse.print_debug("Either constructor, defineClass or resolveClass method could not be found %s,%s,%s", type(constructorMethodID), type(defineClassMethodID),type(resolveClassMethodID))
return false
@@ -976,13 +976,13 @@ function injectClass(socket,class_bytes)
-- create array to load bytecode into
local arrayID
local arrayID
status, arrayID = newArrayInstance(socket,0,byteArrayID,#class_bytes)
if not status then
stdnse.print_debug("New array failed: %s", arrayID)
return false
end
stdnse.print_debug("Created new byte array of length %d",#class_bytes)
stdnse.print_debug("Created new byte array of length %d",#class_bytes)
-- set array values
local temp
status, temp = setArrayValues(socket,0,arrayID,0,class_bytes)
@@ -990,12 +990,12 @@ function injectClass(socket,class_bytes)
stdnse.print_debug("Set values failed: %s", temp)
return
end
stdnse.print_debug("Set array values to injected class bytes")
-- get main thread id
stdnse.print_debug("Set array values to injected class bytes")
-- get main thread id
-- in order to load a new class file, thread must be suspended by an event
-- so we set it to singlestep, let it run and it get suspended right away
local threads
local threads
status,threads = getAllThreads(socket,0)
if not status then
stdnse.print_debug("get threads failed: %s", threads)
@@ -1003,7 +1003,7 @@ function injectClass(socket,class_bytes)
end
local main_thread
local eventID
stdnse.print_debug("Looking for main thread...")
stdnse.print_debug("Looking for main thread...")
for _,thread in ipairs(threads) do
local thread_name
status, thread_name = getThreadName(socket,0,thread)
@@ -1012,7 +1012,7 @@ function injectClass(socket,class_bytes)
return false
end
if thread_name == "main" then
stdnse.print_debug("Setting singlesteping to main thread.")
stdnse.print_debug("Setting singlesteping to main thread.")
status, eventID = setThreadSinglestep(socket,0,thread)
main_thread = thread
break
@@ -1023,25 +1023,25 @@ function injectClass(socket,class_bytes)
return false
end
-- to trigger the singlestep event, VM must be resumed
stdnse.print_debug("Resuming VM and waiting for single step event from main thread...")
stdnse.print_debug("Resuming VM and waiting for single step event from main thread...")
local status, _ = resumeVM(socket,0)
-- clear singlestep since we need to run our code in this thread and we don't want it to stop after each instruction
clearThreadSinglestep(socket,0,eventID)
stdnse.print_debug("Cleared singlesteping from main thread.")
-- instantiate new class loader
local class_loader_instance
stdnse.print_debug("Cleared singlesteping from main thread.")
-- instantiate new class loader
local class_loader_instance
status, class_loader_instance = newClassInstance(socket,0,secureClassLoader,main_thread,constructorMethodID,0,nil)
if not status then
stdnse.print_debug("newClassInstance failed: %s", class_loader_instance)
return false
end
stdnse.print_debug("Created new instance of SecureClassLoader.")
local injectedClass
stdnse.print_debug("Created new instance of SecureClassLoader.")
local injectedClass
-- invoke defineClass with byte array that contains our bytecode
local defineClassArgs = bin.pack(">CLCiCi",0x5b,arrayID,0x49,0,0x49,#class_bytes) -- argument tags taken from http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/types.html#wp9502
stdnse.print_debug("Calling secureClassLoader.defineClass(byte[],int,int) ...")
stdnse.print_debug("Calling secureClassLoader.defineClass(byte[],int,int) ...")
status, injectedClass = invokeObjectMethod(socket,0,class_loader_instance,main_thread,secureClassLoader,defineClassMethodID,3,defineClassArgs)
if not status then
stdnse.print_debug("invokeObjectMethod failed: %s", injectedClass)
@@ -1053,34 +1053,34 @@ function injectClass(socket,class_bytes)
end
-- extract the injected class' ID
local tag,injectedClassID
_,tag,injectedClassID = bin.unpack(">CL",injectedClass)
_,tag,injectedClassID = bin.unpack(">CL",injectedClass)
-- our class is now injected, but we need to find it's methods by calling Class.getMethods() on it
-- and for that we need its runtime_type which is Class
local runtime_type
local runtime_type
status, runtime_type = getRuntimeType(socket,0,injectedClassID) -- should be Class
-- find the getMethods() id
-- find the getMethods() id
local getMethodsMethod = findMethod(socket,runtime_type,"getMethods",false)
status, _ = invokeObjectMethod(socket,0,injectedClassID,main_thread,runtime_type,getMethodsMethod,0,nil)
status, _ = invokeObjectMethod(socket,0,injectedClassID,main_thread,runtime_type,getMethodsMethod,0,nil)
stdnse.print_debug("New class defined. Injected class id : %d",injectedClassID)
stdnse.print_debug("New class defined. Injected class id : %d",injectedClassID)
local sig, reflected_type
status, sig = getSignatureWithGeneric(socket,0,injectedClassID)
stdnse.print_debug("Injected class signature: %s", sig)
status, reflected_type = getReflectedType(socket,0,injectedClassID)
status, reflected_type = getReflectedType(socket,0,injectedClassID)
-- find injected class constructor
local injectedConstructor = findMethod(socket,injectedClassID,"<init>",false)
if injectedConstructor == nil then
stdnse.print_debug("Couldn't find either evil method or constructor")
return false
end
-- instantiate our evil class
end
-- instantiate our evil class
local injectedClassInstance
status, injectedClassInstance = newClassInstance(socket,0,injectedClassID,main_thread,injectedConstructor,0,nil)
status, injectedClassInstance = newClassInstance(socket,0,injectedClassID,main_thread,injectedConstructor,0,nil)
if not status then
return false, injectedClassInstance
end

View File

@@ -2,7 +2,7 @@
-- Library methods for handling JSON data. It handles JSON encoding and
-- decoding according to RFC 4627.
--
-- There is a test section at the bottom which shows some example
-- There is a test section at the bottom which shows some example
-- parsing. If you want to parse JSON, you can test it by pasting sample JSON
-- into the <code>TESTS</code> table and run the <code>test</code> method
--
@@ -19,9 +19,9 @@
-- Version 0.4
-- Created 01/25/2010 - v0.1 - created by Martin Holst Swende <martin@swende.se>
-- Heavily modified 02/22/2010 - v0.3. Rewrote the parser into an OO-form, to not have to handle
-- all kinds of state with parameters and return values.
-- Modified 02/27/2010 - v0.4 Added unicode handling (written by David Fifield). Renamed toJson
-- and fromJson intogenerate() and parse(), implemented more proper numeric parsing and added some more error checking.
-- all kinds of state with parameters and return values.
-- Modified 02/27/2010 - v0.4 Added unicode handling (written by David Fifield). Renamed toJson
-- and fromJson intogenerate() and parse(), implemented more proper numeric parsing and added some more error checking.
local bit = require "bit"
local nmap = require "nmap"
@@ -72,7 +72,7 @@ do
end
end
-- Escapes a string
-- Escapes a string
--@param str the string
--@return a string where the special chars have been escaped
local function escape(str)
@@ -123,7 +123,7 @@ end
--@return a string containing valid json
function generate(obj)
-- NULL-check must be performed before
-- NULL-check must be performed before
-- checking type == table, since the NULL-object
-- is a table
if obj == NULL then
@@ -177,11 +177,11 @@ end
function Json:eatWhiteSpace()
--Find next non-white char
local a,b = self.input:find("%S",self.pos)
if not a then
if not a then
self:syntaxerror("Empty data")
return
end
self.pos = a
self.pos = a
end
-- Jumps to a specified position
@@ -206,7 +206,7 @@ end
-- If false, triggers a syntax error
--@param str the string to test
function Json:assertStr(str)
local content = self.input:sub(self.pos,self.pos+str:len()-1)
local content = self.input:sub(self.pos,self.pos+str:len()-1)
if(content == str) then-- All ok
-- Jump forward
self:jumpTo(self.pos+str:len())
@@ -231,9 +231,9 @@ function Json:parseStart()
-- of the outermost container can other types appear.
self:eatWhiteSpace()
local c = self:peek()
if c == '{' then
if c == '{' then
return self:parseObject()
elseif c == '[' then
elseif c == '[' then
return self:parseArray()
else
self:syntaxerror(("JSON must start with object or array (started with %s)"):format(c))
@@ -246,13 +246,13 @@ end
function Json:parseValue()
self:eatWhiteSpace()
local c = self:peek()
local value
if c == '{' then
if c == '{' then
value = self:parseObject()
elseif c == '[' then
elseif c == '[' then
value = self:parseArray()
elseif c == '"' then
elseif c == '"' then
value = self:parseString()
elseif c == 'n' then
self:assertStr("null")
@@ -271,7 +271,7 @@ function Json:parseValue()
return
end
value = tonumber(self.input:sub(a,b))
if(value == nil) then
if(value == nil) then
self:syntaxerror("Error 2 parsing numeric value")
return
end
@@ -285,7 +285,7 @@ function Json:parseObject()
local object = {}
make_object(object)
local _= self:next() -- Eat {
while(self:hasMore() and not self:errors()) do
self:eatWhiteSpace()
local c = self:peek()
@@ -293,14 +293,14 @@ function Json:parseObject()
self:next() -- Eat it
return object
end
if(c ~= '"') then
self:syntaxerror(("Expected '\"', got '%s'"):format(c))
return
end
local key = self:parseString()
if self:errors() then
if self:errors() then
return
end
self:eatWhiteSpace()
@@ -310,18 +310,18 @@ function Json:parseObject()
return
end
local value = self:parseValue()
if self:errors() then
if self:errors() then
return
end
object[key] = value
self:eatWhiteSpace()
c = self:next()
-- Valid now is , or }
if(c == '}') then
return object
if(c == '}') then
return object
end
if(c ~= ',') then
self:syntaxerror("Expected ',' or '}', got "..c)
@@ -448,20 +448,20 @@ function Json:parseString()
assert( c == '"')
while(self:hasMore()) do
local c = self:next()
if(c == '"') then -- end of string
break
elseif(c == '\\') then-- Escaped char
local d = self:next()
if REVERSE_ESCAPE_TABLE[d] ~= nil then
val = val .. REVERSE_ESCAPE_TABLE[d]
if REVERSE_ESCAPE_TABLE[d] ~= nil then
val = val .. REVERSE_ESCAPE_TABLE[d]
elseif d == 'u' then -- Unicode chars
local codepoint = self:parseUnicodeEscape()
if not codepoint then
return
end
val = val .. utf8_enc(codepoint)
else
else
self:syntaxerror(("Undefined escape character '%s'"):format(d))
return false
end
@@ -472,7 +472,7 @@ function Json:parseString()
return val
end
--- Parses json data into an object form
-- This is the method you probably want to use if you
-- This is the method you probably want to use if you
-- use this library from a script.
--@param data a json string
--@return status true if ok, false if bad
@@ -510,7 +510,7 @@ local TESTS = {
'{"a" bad :1}', -- error
'["a\\\\t"]', -- Should become Lua {"a\\t"}
'[0.0.0]', -- error
'[-1]',
'[-1]',
'[-1.123e-2]',
'[5e3]',
'[5e+3]',
@@ -531,7 +531,7 @@ function test()
print(v)
status,res = parse(v)
if not status then print( res) end
if(status) then
if(status) then
print(generate(res))
else
print("Error:".. res)

View File

@@ -1,5 +1,5 @@
---
-- Library methods for handling LDAP.
-- Library methods for handling LDAP.
--
-- @author Patrik Karlsson
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
@@ -14,7 +14,7 @@
-- formats
-- Revised 10/29/2011 - v0.5 - Added support for performing wildcard searches via the substring filter.
-- Revised 10/30/2011 - v0.6 - Added support for the ldap extensibleMatch filter type for searches
--
--
local asn1 = require "asn1"
local bin = require "bin"
@@ -48,7 +48,7 @@ APPNO = {
UnbindRequest = 2,
SearchRequest = 3,
SearchResponse = 4,
SearchResDone = 5
SearchResDone = 5
}
-- Filter operation constants
@@ -67,10 +67,10 @@ FILTER = {
-- Scope constants
SCOPE = {
base=0,
one=1,
sub= 2,
children=3,
base=0,
one=1,
sub= 2,
children=3,
default = 0
}
@@ -90,7 +90,7 @@ tagEncoder['table'] = function(self, val)
if (val._ldap == '0A') then
local ival = self.encodeInt(val[1])
local len = self.encodeLength(#ival)
return bin.pack('HAA', '0A', len, ival)
return bin.pack('HAA', '0A', len, ival)
end
if (val._ldaptype) then
local len
@@ -101,17 +101,17 @@ tagEncoder['table'] = function(self, val)
return bin.pack('HAA', val._ldaptype, len, val[1])
end
end
local encVal = ""
for _, v in ipairs(val) do
encVal = encVal .. encode(v) -- todo: buffer?
end
local tableType = bin.pack("H", "30")
if (val["_snmp"]) then
tableType = bin.pack("H", val["_snmp"])
end
if (val["_snmp"]) then
tableType = bin.pack("H", val["_snmp"])
end
return bin.pack('AAA', tableType, self.encodeLength(#encVal), encVal)
end
---
@@ -120,17 +120,17 @@ end
-- @param val Value to be encoded.
-- @return Encoded value.
function encode(val)
local encoder = asn1.ASN1Encoder:new()
local encValue
encoder:registerTagEncoders(tagEncoder)
encValue = encoder:encode(val)
if encValue then
return encValue
end
return ''
end
@@ -179,7 +179,7 @@ local function decodeSeq(encStr, len, pos)
local sPos = 1
local sStr
pos, sStr = bin.unpack("A" .. len, encStr, pos)
if(sStr==nil) then
if(sStr==nil) then
return pos,seq
end
while (sPos < len) do
@@ -217,7 +217,7 @@ end
-- @param socket socket already connected to the ldap server
-- @param params table containing at least <code>scope</code>, <code>derefPolicy</code>, <code>baseObject</code>
-- the field <code>maxObjects</code> may also be included to restrict the amount of records returned
-- @return success true or false.
-- @return success true or false.
-- @return err string containing error message
function searchRequest( socket, params )
@@ -229,35 +229,35 @@ function searchRequest( socket, params )
local attrSeq = ''
local requestData, messageSeq, data
local maxObjects = params.maxObjects or -1
local encoder = asn1.ASN1Encoder:new()
local decoder = asn1.ASN1Decoder:new()
encoder:registerTagEncoders(tagEncoder)
decoder:registerTagDecoders(tagDecoder)
request = request .. encode( { _ldap='0A', params.scope } )--scope
request = request .. encode( { _ldap='0A', params.derefPolicy } )--derefpolicy
request = request .. encode( params.sizeLimit or 0)--sizelimit
request = request .. encode( params.timeLimit or 0)--timelimit
request = request .. encode( params.typesOnly or false)--TypesOnly
if params.filter then
request = request .. createFilter( params.filter )
else
request = request .. encode( { _ldaptype='87', "objectclass" } )-- filter : string, presence
end
if attributes~= nil then
for _,attr in ipairs(attributes) do
for _,attr in ipairs(attributes) do
attrSeq = attrSeq .. encode(attr)
end
end
end
request = request .. encoder:encodeSeq(attrSeq)
requestData = encodeLDAPOp(APPNO.SearchRequest, true, request)
messageSeq = encode(ldapMessageId)
messageSeq = encode(ldapMessageId)
ldapMessageId = ldapMessageId +1
messageSeq = messageSeq .. requestData
messageSeq = messageSeq .. requestData
data = encoder:encodeSeq(messageSeq)
try( socket:send( data ) )
data = ""
@@ -268,13 +268,13 @@ function searchRequest( socket, params )
local _, objectName, attributes, ldapOp
local attributes
local searchResEntry = {}
if ( maxObjects == 0 ) then
break
elseif ( maxObjects > 0 ) then
maxObjects = maxObjects - 1
end
if data:len() > 6 then
pos, len = decoder.decodeLength( data, pos )
else
@@ -285,13 +285,13 @@ function searchRequest( socket, params )
while ( len + pos - 1 > data:len() ) do
data = data .. try( socket:receive() )
end
pos, messageId = decode( data, pos )
pos, tmp = bin.unpack("C", data, pos)
pos, len = decoder.decodeLength( data, pos )
ldapOp = asn1.intToBER( tmp )
searchResEntry = {}
if ldapOp.number == APPNO.SearchResDone then
pos, searchResEntry.resultCode = decode( data, pos )
-- errors may occur after a large amount of data has been received (eg. size limit exceeded)
@@ -303,7 +303,7 @@ function searchRequest( socket, params )
local error_msg
pos, searchResEntry.matchedDN = decode( data, pos )
pos, searchResEntry.errorMessage = decode( data, pos )
error_msg = ERROR_MSG[searchResEntry.resultCode]
error_msg = ERROR_MSG[searchResEntry.resultCode]
-- if the table is empty return a hard error
if #searchResEntries == 0 then
return false, string.format("Code: %d|Error: %s|Details: %s", searchResEntry.resultCode, error_msg or "", searchResEntry.errorMessage or "" )
@@ -319,7 +319,7 @@ function searchRequest( socket, params )
pos, searchResEntry.objectName = decode( data, pos )
if ldapOp.number == APPNO.SearchResponse then
pos, searchResEntry.attributes = decode( data, pos )
table.insert( searchResEntries, searchResEntry )
end
if data:len() > pos then
@@ -345,23 +345,23 @@ function bindRequest( socket, params )
local ldapAuth = encode( { _ldaptype = 80, params.password } )
local bindReq = encode( params.version ) .. encode( params.username ) .. ldapAuth
local ldapMsg = encode(ldapMessageId) .. encodeLDAPOp( APPNO.BindRequest, true, bindReq )
local packet
local packet
local pos, packet_len, resultCode, tmp, len, _
local response = {}
local encoder = asn1.ASN1Encoder:new()
local decoder = asn1.ASN1Decoder:new()
encoder:registerTagEncoders(tagEncoder)
decoder:registerTagDecoders(tagDecoder)
packet = encoder:encodeSeq( ldapMsg )
ldapMessageId = ldapMessageId +1
try( socket:send( packet ) )
packet = try( socket:receive() )
pos, packet_len = decoder.decodeLength( packet, 2 )
pos, response.messageID = decode( packet, pos )
pos, response.messageID = decode( packet, pos )
pos, tmp = bin.unpack("C", packet, pos)
pos, len = decoder.decodeLength( packet, pos )
response.protocolOp = asn1.intToBER( tmp )
@@ -369,20 +369,20 @@ function bindRequest( socket, params )
if response.protocolOp.number ~= APPNO.BindResponse then
return false, string.format("Recieved incorrect Op in packet: %d, expected %d", response.protocolOp.number, APPNO.BindResponse)
end
pos, response.resultCode = decode( packet, pos )
if ( response.resultCode ~= 0 ) then
local error_msg
pos, response.matchedDN = decode( packet, pos )
pos, response.errorMessage = decode( packet, pos )
error_msg = ERROR_MSG[response.resultCode]
return false, string.format("\n Error: %s\n Details: %s",
error_msg = ERROR_MSG[response.resultCode]
return false, string.format("\n Error: %s\n Details: %s",
error_msg or "Unknown error occured (code: " .. response.resultCode ..
")", response.errorMessage or "" )
else
return true, "Success"
end
end
end
--- Performs an LDAP Unbind
@@ -422,13 +422,13 @@ function createFilter( filter )
filter_str = filter_str .. createFilter( v )
end
else
local obj = encode( filter.obj )
local obj = encode( filter.obj )
local val = ''
if ( filter.op == FILTER['substrings'] ) then
local tmptable = stdnse.strsplit('*', filter.val)
local tmp_result = ''
if (#tmptable <= 1 ) then
-- 0x81 = 10000001 = 10 0 00001
-- hex binary Context Primitive value Field: Sequence Value: 1 (any / any position in string)
@@ -446,7 +446,7 @@ function createFilter( filter )
-- hex binary Context Primitive value Field: Sequence Value: 1 (any / match in any position in string)
tmp_result = tmp_result .. bin.pack('HAA' , '81', string.char(#substr), substr)
end
if (indexval == #tmptable) and (substr ~= '') then
-- 0x82 = 10000010 = 10 0 00010
-- hex binary Context Primitive value Field: Sequence Value: 2 (final / match at end of string)
@@ -456,30 +456,30 @@ function createFilter( filter )
end
val = asn1.ASN1Encoder:encodeSeq( tmp_result )
elseif ( filter.op == FILTER['extensibleMatch'] ) then
local tmptable = stdnse.strsplit(':=', filter.val)
local tmp_result = ''
local OID, bitmask
if ( tmptable[1] ~= nil ) then
OID = tmptable[1]
else
return false, ("ERROR: Invalid extensibleMatch query format")
end
if ( tmptable[2] ~= nil ) then
bitmask = tmptable[2]
else
return false, ("ERROR: Invalid extensibleMatch query format")
end
-- Format and create matchingRule using OID
-- 0x81 = 10000001 = 10 0 00001
-- hex binary Context Primitive value Field: matchingRule Value: 1
tmp_result = bin.pack('HAA' , '81', string.char(#OID), OID)
-- Format and create type using ldap attribute
-- 0x82 = 10000010 = 10 0 00010
-- hex binary Context Primitive value Field: Type Value: 2
@@ -488,7 +488,7 @@ function createFilter( filter )
-- Format and create matchValue using bitmask
-- 0x83 = 10000011 = 10 0 00011
-- hex binary Context Primitive value Field: matchValue Value: 3
tmp_result = tmp_result .. bin.pack('HAA' , '83', string.char(#bitmask), bitmask)
tmp_result = tmp_result .. bin.pack('HAA' , '83', string.char(#bitmask), bitmask)
-- Format and create dnAttributes, defaulting to false
-- 0x84 = 10000100 = 10 0 00100
@@ -496,7 +496,7 @@ function createFilter( filter )
--
-- 0x01 = field length
-- 0x00 = boolean value, in this case false
tmp_result = tmp_result .. bin.pack('H' , '840100')
tmp_result = tmp_result .. bin.pack('H' , '840100')
-- Format the overall extensibleMatch block
-- 0xa9 = 10101001 = 10 1 01001
@@ -505,9 +505,9 @@ function createFilter( filter )
else
val = encode( filter.val )
end
filter_str = filter_str .. obj .. val
end
filter_str = filter_str .. obj .. val
end
return encode( { _ldaptype=bin.pack("A", string.format("%X", asn1_type)), filter_str } )
@@ -528,7 +528,7 @@ function searchResultToTable( searchEntries )
for _, v in ipairs( searchEntries ) do
local result_part = {}
if v.objectName and v.objectName:len() > 0 then
result_part.name = string.format("dn: %s", v.objectName)
result_part.name = string.format("dn: %s", v.objectName)
else
result_part.name = "<ROOT>"
end
@@ -553,7 +553,7 @@ function searchResultToTable( searchEntries )
end
end
table.insert( result_part, attribs )
end
end
table.insert( result, result_part )
end
return result
@@ -573,16 +573,16 @@ end
function searchResultToFile( searchEntries, filename )
local f = io.open( filename, "w")
if ( not(f) ) then
return false, ("ERROR: Failed to open file (%s)"):format(filename)
end
-- Build table structure. Using a multi pass approach ( build table then populate table )
-- because the objects returned may not necessarily have the same number of attributes
-- making single pass CSV output generation problematic.
-- Unfortunately the searchEntries table passed to this function is not organized in a
-- way that make particular attributes for a given hostname directly addressable.
-- Unfortunately the searchEntries table passed to this function is not organized in a
-- way that make particular attributes for a given hostname directly addressable.
--
-- At some point restructuring the searchEntries table may be a good optimization target
@@ -597,15 +597,15 @@ function searchResultToFile( searchEntries, filename )
end
end
end
end
end
end
-- build table of hosts
local host_table = {}
for _, v in ipairs( searchEntries ) do
if v.objectName and v.objectName:len() > 0 then
local host = {}
if v.objectName and v.objectName:len() > 0 then
-- use a copy of the table here, assigning attrib_table into host_table
-- links the values so setting it for one host changes the specific attribute
@@ -614,44 +614,44 @@ function searchResultToFile( searchEntries, filename )
end
end
end
-- populate the host table with values for each attribute that has valid data
for _, v in ipairs( searchEntries ) do
if ( v.attributes ~= nil ) then
for _, attrib in ipairs( v.attributes ) do
for i=2, #attrib do
for i=2, #attrib do
-- do some additional Windows decoding
if ( attrib[1] == "objectSid" ) then
host_table[string.format("%s", v.objectName)].attributes[attrib[1]] = string.format( "%d", decode( attrib[i] ) )
elseif ( attrib[1] == "objectGUID") then
local _, o1, o2, o3, o4, o5, o6, o7, o8, o9, oa, ob, oc, od, oe, of = bin.unpack("C16", attrib[i] )
host_table[string.format("%s", v.objectName)].attributes[attrib[1]] = string.format( "%x%x%x%x-%x%x-%x%x-%x%x-%x%x%x%x%x", o4, o3, o2, o1, o5, o6, o7, o8, o9, oa, ob, oc, od, oe, of )
elseif ( attrib[1] == "lastLogon" or attrib[1] == "lastLogonTimestamp" or attrib[1] == "pwdLastSet" or attrib[1] == "accountExpires" or attrib[1] == "badPasswordTime" ) then
host_table[string.format("%s", v.objectName)].attributes[attrib[1]] = convertADTimeStamp(attrib[i])
elseif ( attrib[1] == "whenChanged" or attrib[1] == "whenCreated" or attrib[1] == "dSCorePropagationData" ) then
host_table[string.format("%s", v.objectName)].attributes[attrib[1]] = convertZuluTimeStamp(attrib[i])
else
host_table[v.objectName].attributes[attrib[1]] = string.format( "%s", attrib[i] )
end
end
end
end
end
end
-- write the new, fully populuated table out to CSV
-- initialize header row
local output = "\"name\""
for attribute, value in pairs(attrib_table) do
output = output .. ",\"" .. attribute .. "\""
end
end
output = output .. "\n"
-- gather host data from fields, add to output.
for name, attribs in pairs(host_table) do
output = output .. "\"" .. name .. "\""
@@ -661,13 +661,13 @@ function searchResultToFile( searchEntries, filename )
end
output = output .. "\n"
end
-- write the output to file
if ( not(f:write( output .."\n" ) ) ) then
f:close()
return false, ("ERROR: Failed to write file (%s)"):format(filename)
end
f:close()
return true
end
@@ -684,7 +684,7 @@ function extractAttribute( searchEntries, attributeName )
if ( v.attributes ~= nil ) then
for _, attrib in ipairs( v.attributes ) do
local attribType = attrib[1]
for i=2, #attrib do
for i=2, #attrib do
if ( attribType:upper() == attributeName:upper() ) then
table.insert( attributeTbl, attrib[i])
end
@@ -706,22 +706,22 @@ function convertADTimeStamp(timestamp)
local base_time = tonumber(os.time({year=1601, month=1, day=1, hour=0, minute=0, sec =0}))
timestamp = tonumber(timestamp)
if (timestamp and timestamp > 0) then
-- The result value was 3036 seconds off what Microsoft says it should be.
-- I have been unable to find an explaination for this, and have resorted to
-- manually adjusting the formula.
result = ( timestamp / 10000000 ) - 3036
result = result + base_time
result = os.date("%Y/%m/%d %H:%M:%S UTC", result)
else
result = 'Never'
end
return result
end
--- Converts a non-delimited Zulu timestamp format to a human readable form
@@ -741,13 +741,13 @@ function convertZuluTimeStamp(timestamp)
local mins = string.sub(timestamp,11,12)
local secs = string.sub(timestamp,13,14)
local result = year .. "/" .. month .. "/" .. day .. " " .. hour .. ":" .. mins .. ":" .. secs .. " UTC"
return result
else
return 'Invalid date format'
return 'Invalid date format'
end
end
--- Creates a copy of a table
@@ -757,8 +757,8 @@ end
-- @return table object containing copy of original
function copyTable(targetTable)
local temp = { }
for key, val in pairs(targetTable) do
temp[key] = val
for key, val in pairs(targetTable) do
temp[key] = val
end
return setmetatable(temp, getmetatable(targetTable))
end

View File

@@ -6,7 +6,7 @@
-- <code>listop</code> module tries to bring much of the functionality from
-- functional languages to Lua using Lua's central data structure, the table, as
-- a base for its list operations. Highlights include a <code>map</code>
-- function applying a given function to each element of a list.
-- function applying a given function to each element of a list.
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
local stdnse = require "stdnse"
@@ -32,8 +32,8 @@ Functional programming style 'list' operations
value ncar(list, x)
list cdr(list)
list ncdr(list, x)
where 'list' is an indexed table
where 'list' is an indexed table
where 'value' is an lua datatype
--]]
@@ -58,7 +58,7 @@ end
-- @param f The function to call.
-- @param l A list.
-- @return List of function results.
function map(f, l)
function map(f, l)
local results = {}
for _, v in ipairs(l) do
results[#results+1] = f(v);
@@ -87,7 +87,7 @@ end
-- @param f The function.
-- @param l The list.
-- @return Filtered list.
function filter(f, l)
function filter(f, l)
local results = {}
for i, v in ipairs(l) do
if(f(v)) then
@@ -125,7 +125,7 @@ end
-- @param x Element index.
-- @return Elements after index <code>x</code> or after index <code>1</code> if
-- <code>x</code> is not given.
function ncdr(l, x)
function ncdr(l, x)
return {table.unpack(l, x or 2)};
end

View File

@@ -11,12 +11,12 @@ _ENV = stdnse.module("match", stdnse.seeall)
--various functions for use with nse's nsock:receive_buf - function
-- e.g.
-- e.g.
-- sock:receive_buf(regex("myregexpattern")) - does a match using pcre- regular-
-- - expressions
-- sock:receive_buf(numbytes(80)) - is the buffered version of
-- sock:receive_buf(numbytes(80)) - is the buffered version of
-- sock:receive_bytes(80) - i.e. it returns
-- exactly 80 bytes and no more
-- exactly 80 bytes and no more
--- Return a function that allows delimiting with a regular expression.
--
@@ -41,7 +41,7 @@ end
-- This function can be used to get a buffered version of
-- <code>sock:receive_bytes(n)</code> in case a script requires more than one
-- fixed-size chunk, as the unbuffered version may return more bytes than
-- requested and thus would require you to do the parsing on your own.
-- requested and thus would require you to do the parsing on your own.
-- @param num Number of bytes.
-- @usage sock:receive_buf(match.numbytes(80))
-- @see nmap.receive_buf

View File

@@ -17,16 +17,16 @@ _ENV = stdnse.module("membase", stdnse.seeall)
-- A minimalistic implementation of the Couchbase Membase TAP protocol
TAP = {
-- Operations
Op = {
LIST_SASL_MECHS = 0x20,
AUTHENTICATE = 0x21,
},
-- Requests
Request = {
-- Header breakdown
-- Field (offset) (value)
-- Magic (0): 0x80 (PROTOCOL_BINARY_REQ)
@@ -38,8 +38,8 @@ TAP = {
-- Total body (8-11): 0x00000000 (0)
-- Opaque (12-15): 0x00000000 (0)
-- CAS (16-23): 0x0000000000000000 (0)
Header = {
Header = {
-- Creates a new instance of Header
-- @param opcode number containing the operation
-- @return o new instance of Header
@@ -59,7 +59,7 @@ TAP = {
self.__index = self
return o
end,
-- Converts the header to string
-- @return string containing the Header as string
__tostring = function(self)
@@ -68,7 +68,7 @@ TAP = {
self.opaque, self.CAS)
end,
},
-- List SASL authentication mechanism
SASLList = {
@@ -90,7 +90,7 @@ TAP = {
return tostring(self.header)
end,
},
-- Authenticates using SASL
Authenticate = {
@@ -119,7 +119,7 @@ TAP = {
if ( self.mech == "PLAIN" ) then
local mech_params = { self.username, self.password }
local auth_data = sasl.Helper:new(self.mech):encode(table.unpack(mech_params))
self.header.keylen = #self.mech
self.header.total_body = #auth_data + #self.mech
return tostring(self.header) .. self.mech .. auth_data
@@ -127,12 +127,12 @@ TAP = {
end,
}
},
-- Responses
Response = {
-- The response header
-- Header breakdown
-- Field (offset) (value)
@@ -146,7 +146,7 @@ TAP = {
-- Opaque (12-15): 0x00000000 (0)
-- CAS (16-23): 0x0000000000000000 (0)
Header = {
-- Creates a new instance of Header
-- @param data string containing the raw data
-- @return o new instance of Header
@@ -160,7 +160,7 @@ TAP = {
return o
end
end,
-- Parse the raw header and populates the class members
-- @return status true on success, false on failure
parse = function(self)
@@ -169,17 +169,17 @@ TAP = {
return false, "Packet to short"
end
local pos
pos, self.magic, self.opcode, self.keylen, self.extlen,
pos, self.magic, self.opcode, self.keylen, self.extlen,
self.data_type, self.status, self.total_body, self.opaque,
self.CAS = bin.unpack(">CCSCCSIIL", self.data)
return true
end
},
-- Decoders
Decoder = {
-- TAP.Op.LIST_SASL_MECHS
[0x20] = {
-- Creates a new instance of the decoder
@@ -203,7 +203,7 @@ TAP = {
return true
end
},
-- Login response
[0x21] = {
-- Creates a new instance of the decoder
@@ -227,23 +227,23 @@ TAP = {
return true
end
}
}
},
}
-- The Helper class is the main script interface
Helper = {
-- Creates a new instance of the helper
-- @param host table as received by the action method
-- @param port table as received by the action method
-- @param options table including options to the helper, currently:
-- <code>timeout</code> - socket timeout in milliseconds
new = function(self, host, port, options)
local o = {
local o = {
host = host,
port = port,
mech = stdnse.get_script_args("membase.authmech"),
@@ -253,7 +253,7 @@ Helper = {
self.__index = self
return o
end,
-- Connects the socket to the server
-- @return true on success, false on failure
connect = function(self)
@@ -261,12 +261,12 @@ Helper = {
self.socket:set_timeout(self.options.timeout or 10000)
return self.socket:connect(self.host, self.port)
end,
-- Closes the socket
close = function(self)
return self.socket:close()
end,
-- Sends a request to the server, receives and parses the response
-- @param req a Request instance
-- @return status true on success, false on failure
@@ -276,7 +276,7 @@ Helper = {
if ( not(status) ) then
return false, "Failed to send data"
end
local data
status, data = self.socket:receive_buf(match.numbytes(24), true)
if ( not(status) ) then
@@ -284,32 +284,32 @@ Helper = {
end
local header = TAP.Response.Header:new(data)
if ( header.opcode ~= req.header.opcode ) then
stdnse.print_debug("WARNING: Received invalid op code, request contained (%d), response contained (%d)", req.header.opcode, header.opcode)
end
if ( not(TAP.Response.Decoder[tonumber(header.opcode)]) ) then
return false, ("No response handler for opcode: %d"):format(header.opcode)
end
local status, data = self.socket:receive_buf(match.numbytes(header.total_body), true)
if ( not(status) ) then
return false, "Failed to receive data"
end
local response = TAP.Response.Decoder[tonumber(header.opcode)]:new(data)
if ( not(response) ) then
return false, "Failed to parse response from server"
end
return true, response
end,
-- Gets list of supported SASL authentication mechanisms
getSASLMechList = function(self)
return self:exch(TAP.Request.SASLList:new())
end,
-- Logins to the server
-- @param username string containing the username
-- @param password string containing the password

View File

@@ -7,15 +7,15 @@ _ENV = stdnse.module("mobileme", stdnse.seeall)
---
-- A MobileMe web service client that allows discovering Apple devices
-- using the "find my iPhone" functionality.
--
-- using the "find my iPhone" functionality.
--
-- @author "Patrik Karlsson <patrik@cqure.net>"
--
MobileMe = {
-- headers used in all requests
headers = {
headers = {
["Content-Type"] = "application/json; charset=utf-8",
["X-Apple-Find-Api-Ver"] = "2.0",
["X-Apple-Authscheme"] = "UserIdGuest",
@@ -26,7 +26,7 @@ MobileMe = {
["Accept-Language"] = "en-us",
["Connection"] = "keep-alive"
},
-- Creates a MobileMe instance
-- @param username string containing the Apple ID username
-- @param password string containing the Apple ID password
@@ -42,7 +42,7 @@ MobileMe = {
self.__index = self
return o
end,
-- Sends a message to an iOS device
-- @param devid string containing the device id to which the message should
-- be sent
@@ -59,14 +59,14 @@ MobileMe = {
local auth = { username = self.username, password = self.password }
local response = http.post(self.host, self.port, url, { header = self.headers, auth = auth, timeout = 10000 }, nil, data)
if ( response.status == 200 ) then
local status, resp = json.parse(response.body)
if ( not(status) ) then
stdnse.print_debug(2, "Failed to parse JSON response from server")
return false, "Failed to parse JSON response from server"
end
if ( resp.statusCode ~= "200" ) then
stdnse.print_debug(2, "Failed to send message to server")
return false, "Failed to send message to server"
@@ -74,7 +74,7 @@ MobileMe = {
end
return true
end,
-- Updates location information for all devices controlled by the Apple ID
-- @return status true on success, false on failure
-- @return json parsed json table or string containing an error message on
@@ -97,20 +97,20 @@ MobileMe = {
if ( response.header["x-apple-mme-host"] ) then
self.host = response.header["x-apple-mme-host"]
end
if ( response.status == 401 ) then
return false, "Authentication failed"
elseif ( response.status ~= 200 and response.status ~= 330 ) then
return false, "An unexpected error occured"
end
retries = retries - 1
until ( 200 == response.status or 0 == retries)
if ( response.status ~= 200 ) then
return false, "Received unexpected response from server"
end
local status, parsed_json = json.parse(response.body)
if ( not(status) or parsed_json.statusCode ~= "200" ) then
@@ -122,7 +122,7 @@ MobileMe = {
return true, parsed_json
end,
-- Get's a list of devices
-- @return devices table containing a list of devices
getDevices = function(self)
@@ -136,7 +136,7 @@ MobileMe = {
Helper = {
-- Creates a Helper instance
-- @param username string containing the Apple ID username
-- @param password string containing the Apple ID password
@@ -150,7 +150,7 @@ Helper = {
o.mm:update()
return o
end,
-- Get's the geolocation from each device
--
-- @return status true on success, false on failure
@@ -162,7 +162,7 @@ Helper = {
-- * <code>accuracy</code> - the location accuracy
-- * <code>timestamp</code> - the time the location was acquired
-- * <code>postype</code> - the position type (GPS or WiFi)
-- * <code>finished</code> -
-- * <code>finished</code> -
-- or string containing an error message on failure
getLocation = function(self)
-- do 3 tries, with a 5 second timeout to allow the location to update
@@ -171,10 +171,10 @@ Helper = {
-- success with that.
local tries, timeout = 3, 5
local result = {}
repeat
local status, response = self.mm:update()
if ( not(status) or not(response) ) then
return false, "Failed to retrieve response from server"
end
@@ -197,7 +197,7 @@ Helper = {
until( tries == 0 )
return true, result
end,
-- Gets a list of names and ids of devices associated with the Apple ID
-- @return status true on success, false on failure
-- @return table of devices containing the following fields:
@@ -209,7 +209,7 @@ Helper = {
end
return true, devices
end,
-- Send a message to an iOS Device
--
-- @param devid string containing the device id to which the message should
@@ -222,7 +222,7 @@ Helper = {
sendMessage = function(self, ...)
return self.mm:sendMessage(...)
end
}
return _ENV;

View File

@@ -35,14 +35,14 @@ end
local err =stdnse.print_debug
----------------------------------------------------------------------
-- First of all comes a Bson parsing library. This can easily be moved out into a separate library should other
-- First of all comes a Bson parsing library. This can easily be moved out into a separate library should other
-- services start to use Bson
----------------------------------------------------------------------
-- Library methods for handling the BSON format
-- Library methods for handling the BSON format
--
-- For more documentation about the BSON format,
---and more details about it's implementations, check out the
-- python BSON implementation which is available at
-- For more documentation about the BSON format,
---and more details about it's implementations, check out the
-- python BSON implementation which is available at
-- http://github.com/mongodb/mongo-python-driver/blob/master/pymongo/bson.py
-- and licensed under the Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0)
--
@@ -72,18 +72,18 @@ end
--@return status : true if ok, false if error
--@return result : the packed binary data OR error message
local function _element_to_bson(key, value)
--Some constraints-checking
if type(key) ~= 'string' then
return false, "Documents must have only string keys, key was " .. type(key)
if type(key) ~= 'string' then
return false, "Documents must have only string keys, key was " .. type(key)
end
if key:sub(1,1) == "$" then
return false, "key must not start with $: ".. key
if key:sub(1,1) == "$" then
return false, "key must not start with $: ".. key
end
if key:find("%.") then
return false, ("key %r must not contain '.'"):format(tostring(key))
end
local name =bin.pack("z",key) -- null-terminated string
if type(value) == 'string' then
local cstring = bin.pack("z",value) -- null-terminated string
@@ -99,17 +99,17 @@ local function _element_to_bson(key, value)
-- Use 01 - double for - works better than 10
return true, bin.pack('H','01') .. name .. bin.pack("<d", value)
end
local _ = ("cannot convert value of type %s to bson"):format(type(value))
return false, _
end
--Converts a table of elements to binary bson format
--@param dict the table
--@return status : true if ok, false if error
--@return status : true if ok, false if error
--@return result : a string of binary data OR error message
function toBson(dict)
local elements = ""
--Put id first
if dict._id then
@@ -134,7 +134,7 @@ function toBson(dict)
end
-- Get length
local length = #elements + 5
if length > 4 * 1024 * 1024 then
return false, "document too large - BSON documents are limited to 4 MB"
end
@@ -143,24 +143,24 @@ function toBson(dict)
return true, bin.pack("I", length) .. elements .. bin.pack('H',"00")
end
-- Reads a null-terminated string. If length is supplied, it is just cut
-- out from the data, otherwise the data is scanned for at null-char.
-- Reads a null-terminated string. If length is supplied, it is just cut
-- out from the data, otherwise the data is scanned for at null-char.
--@param data the data which starts with a c-string
--@param length optional length of the string
--@return the string
--@return the string
--@return the remaining data (*without* null-char)
local function get_c_string(data,length)
if not length then
local index = data:find(string.char(0))
if index == nil then
error({code="C-string did not contain NULL char"})
if index == nil then
error({code="C-string did not contain NULL char"})
end
length = index
end
local value = data:sub(1,length-1)
--dbg("Found char at pos %d, data is %s c-string is %s",length, data, value)
return value, data:sub(length+1)
end
@@ -170,25 +170,25 @@ end
-- @return Unpacked value
-- @return error string if error occurred
local function parse(code,data)
if 1 == code then -- double
if 1 == code then -- double
return bin.unpack("<d", data)
elseif 2 == code then -- string
-- data length = first four bytes
local _,len = bin.unpack("<i",data)
local _,len = bin.unpack("<i",data)
-- string data = data[5] -->
local value = get_c_string(data:sub(5), len)
-- Count position as header (=4) + length of string (=len)+ null char (=1)
return 4+len+1,value
elseif 3 == code or 4 == code then -- table or array
elseif 3 == code or 4 == code then -- table or array
local object, err
-- Need to know the length, to return later
local _,obj_size = bin.unpack("<i", data)
-- Now, get the data object
dbg("Recursing into bson array")
object, data, err = fromBson(data)
dbg("Recurse finished, got data object")
-- And return where the parsing stopped
-- And return where the parsing stopped
return obj_size+1, object
--6 = _get_null
--7 = _get_oid
@@ -206,7 +206,7 @@ local function parse(code,data)
elseif 16 == code then -- 4 byte integer
return bin.unpack("<i", data)
--17= _get_timestamp
elseif 18 == code then -- long
elseif 18 == code then -- long
return bin.unpack("<l", data)
end
local err = ("Getter for %d not implemented"):format(code)
@@ -217,7 +217,7 @@ end
-- Reads an element from binary to BSon
--@param data a string of data to convert
--@return Name of the element
--@return Value of the element
--@return Value of the element
--@return Residual data not used
--@return any error that occurred
local function _element_to_dict(data)
@@ -225,17 +225,17 @@ local function _element_to_dict(data)
--local element_size = data:byte(1)
element_type = data:byte(1)
element_name, data = get_c_string(data:sub(2))
dbg(" Read element name '%s' (type:%s), data left: %d",element_name, element_type,data:len())
--pos,value,err = parsers.get(element_type)(data)
pos,value,err = parse(element_type,data)
if(err ~= nil) then
if(err ~= nil) then
dbg_err(err)
return nil,nil, data, err
return nil,nil, data, err
end
data=data:sub(pos)
dbg(" Read element value '%s', data left: %d",tostring(value), data:len())
return element_name, value, data
end
@@ -265,11 +265,11 @@ function isPacketComplete(data)
local err_msg = "Not enough data in buffer, at least 4 bytes header info expected"
return false
end
local _,obj_size = bin.unpack("<i", data)
dbg("BSon packet size is %s", obj_size)
-- Check that all data is read and the packet is complete
if data:len() < obj_size then
return false,obj_size
@@ -284,16 +284,16 @@ end
--@return remaining data
--@return error message if not enough data was in packet
function fromBson(data)
dbg("Decoding, got %s bytes of data", data:len())
local complete, object_size = isPacketComplete(data)
if not complete then
local err_msg = ("Not enough data in buffer, expected %s but only has %d"):format(object_size or "?", data:len())
dbg(err_msg)
return {},data, err_msg
return {},data, err_msg
end
local element_portion = data:sub(5,object_size)
local remainder = data:sub(object_size+1)
return _elements_to_dict(element_portion), remainder
@@ -305,7 +305,7 @@ end
----------------------------------------------------------------------------------
function testBson()
local p = toBson({hello="world", test="ok"})
print( "Encoded something ok")
local orig = fromBson(p)
print(" Decoded something else ok")
@@ -321,7 +321,7 @@ end
--[[ MongoDB wire protocol format
Standard message header :
Standard message header :
struct {
int32 messageLength; // total size of the message, including the 4 bytes of length
int32 requestID; // client or database-generated identifier for this message
@@ -329,7 +329,7 @@ struct {
int32 opCode; // request type - see table below
}
Opcodes :
Opcodes :
OP_REPLY 1 Reply to a client request. responseTo is set
OP_MSG 1000 generic msg command followed by a string
OP_UPDATE 2001 update document
@@ -338,9 +338,9 @@ OP_GET_BY_OID 2003 is this used?
OP_QUERY 2004 query a collection
OP_GET_MORE 2005 Get more data from a query. See Cursors
OP_DELETE 2006 Delete documents
OP_KILL_CURSORS 2007 Tell database client is done with a cursor
OP_KILL_CURSORS 2007 Tell database client is done with a cursor
Query message :
Query message :
struct {
MsgHeader header; // standard message header
int32 opts; // query options. See below for details.
@@ -399,11 +399,11 @@ end
function MongoData:addBSON(dict)
-- status, res = bson.toBson(dict)
local status, res = toBson(dict)
if not status then
if not status then
dbg(res)
return status,res
end
self.valueString = self.valueString..res
return true
end
@@ -429,15 +429,15 @@ local function createQuery(collectionName, query)
packet:addUnsignedInt32(0) -- number to skip
packet:addUnsignedInt32(-1) -- number to return : no limit
local status, error = packet:addBSON(query)
if not status then
return status, error
end
return true, packet:data()
end
-- 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 packet data OR error message
function lastErrorQuery(responseTo)
@@ -446,7 +446,7 @@ function lastErrorQuery(responseTo)
return createQuery(collectionName, query)
end
-- 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 packet data OR error message
function serverStatusQuery(responseTo)
@@ -455,7 +455,7 @@ function serverStatusQuery(responseTo)
return createQuery(collectionName, query)
end
-- 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 packet data OR error message
function opTimeQuery(responseTo)
@@ -464,7 +464,7 @@ function opTimeQuery(responseTo)
return createQuery(collectionName, query)
end
-- 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 packet data OR error message
function listDbQuery(responseTo)
@@ -473,7 +473,7 @@ function listDbQuery(responseTo)
return createQuery(collectionName, query)
end
-- 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
--@return status : true for OK, false for error
--@return packet data OR error message
--@return status : true for OK, false for error
@@ -487,15 +487,15 @@ end
--@return int32 value
--@return data unread
local function parseInt32(data)
local pos,val = bin.unpack("<i",data)
local pos,val = bin.unpack("<i",data)
return val, data:sub(pos)
end
local function parseInt64(data)
local pos,val = bin.unpack("<l",data)
local pos,val = bin.unpack("<l",data)
return val, data:sub(pos)
end
-- Parses response header
-- The response header looks like this :
-- The response header looks like this :
--[[
struct {
MsgHeader header; // standard message header
@@ -511,7 +511,7 @@ struct {
local function parseResponseHeader(data)
local response= {}
local hdr, rflag, cID, sfrom, nRet, docs
-- First std message header
hdr ={}
hdr["messageLength"], data = parseInt32(data)
@@ -537,11 +537,11 @@ function isPacketComplete(data)
local err_msg = "Not enough data in buffer, at least 4 bytes header info expected"
return false
end
local _,obj_size = bin.unpack("<i", data)
dbg("MongoDb Packet size is %s, (got %d)", obj_size,data:len())
-- Check that all data is read and the packet is complete
if data:len() < obj_size then
return false,obj_size
@@ -572,25 +572,25 @@ function query(socket, data)
dbg("mongo: waiting for data from socket, got %d bytes so far...",data:len())
data = data .. try( socket:receive() )
isComplete, pSize = isPacketComplete(data)
end
end
-- All required data shold be read now
local packetData = data:sub(1,pSize)
local residualData = data:sub(pSize+1)
local responseHeader = parseResponseHeader(packetData)
if responseHeader["responseFlag"] ~= 0 then
dbg("Response flag not zero : %d, some error occurred", responseHeader["responseFlag"])
end
local bsonData = responseHeader["bson"]
if #bsonData == 0 then
if #bsonData == 0 then
dbg("No BSon data returned ")
return false, "No Bson data returned"
end
-- result, data, err_msg = bson.fromBson(bsonData)
result, data, err_msg = fromBson(bsonData)
if err_msg then
dbg("Got error converting from bson: %s" , err_msg)
return false, ("Got error converting from bson: %s"):format(err_msg)
@@ -608,11 +608,11 @@ function login(socket, db, username, password)
if ( not(status) or not(response.nonce) ) then
return false, "Failed to retrieve nonce"
end
local nonce = response.nonce
local pwdigest = stdnse.tohex(openssl.md5(username .. ':mongo:' ..password))
local digest = stdnse.tohex(openssl.md5(nonce .. username .. pwdigest))
query = { user = username, nonce = nonce, key = digest }
query._cmd = { authenticate = 1 }
@@ -642,16 +642,16 @@ function queryResultToTable( resultTable )
else
table.insert(result,(("%s = %s"):format(tostring(k), tostring(v))))
end
end
end
return result
end
----------------------------------------------------------------------------------
-- Test-code for debugging purposes below
----------------------------------------------------------------------------------
--- Prints data (string) as Hex values, e.g so it more easily can
--- Prints data (string) as Hex values, e.g so it more easily can
-- be compared with a packet dump
-- @param strData the data in a string format
@@ -667,7 +667,7 @@ local function printBuffer(strData)
end
--if ch > 64 and ch < 123 then
-- out = out .. string.char(ch)
--else
--else
out = out .. ch
--end
end

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,17 @@
---
-- This module is designed to parse the <code>PERF_DATA_BLOCK</code> structure, which is
-- stored in the registry under HKEY_PERFORMANCE_DATA. By querying this structure, you can
-- get a whole lot of information about what's going on.
-- get a whole lot of information about what's going on.
--
-- To use this from a script, see <code>get_performance_data</code>, it is the only
-- "public" function in this module.
-- To use this from a script, see <code>get_performance_data</code>, it is the only
-- "public" function in this module.
--
-- My primary sources of information were:
-- * This 1996 journal by Matt Pietrek: <http://www.microsoft.com/msj/archive/S271.aspx>
-- * The followup article: <http://www.microsoft.com/msj/archive/S2A9.aspx>
-- * The WinPerf.h header file
--
-- And my primary inspiration was PsTools, specifically, <code>pstasklist.exe</code>.
-- And my primary inspiration was PsTools, specifically, <code>pstasklist.exe</code>.
--
--@author Ron Bowes <ron@skullsecurity.net>
--@copyright Same as Nmap--See http://nmap.org/book/man-legal.html
@@ -24,10 +24,10 @@ local msrpctypes = require "msrpctypes"
local stdnse = require "stdnse"
_ENV = stdnse.module("msrpcperformance", stdnse.seeall)
---Parses the title database, which is a series of null-terminated string pairs.
---Parses the title database, which is a series of null-terminated string pairs.
--
--@param data The data being processed.
--@param pos The position within <code>data</code>.
--@param data The data being processed.
--@param pos The position within <code>data</code>.
--@return (status, pos, result) The status (true if successful), the new position in <code>data</code> (or an error
-- message), and a table representing the datatype, if any.
local function parse_perf_title_database(data, pos)
@@ -86,8 +86,8 @@ end
-- } PERF_DATA_BLOCK, *PPERF_DATA_BLOCK;
--</code>
--
--@param data The data being processed.
--@param pos The position within <code>data</code>.
--@param data The data being processed.
--@param pos The position within <code>data</code>.
--@return (status, pos, result) The status (true if successful), the new position in <code>data</code> (or an error
-- message), and a table representing the datatype, if any.
local function parse_perf_data_block(data, pos)
@@ -121,7 +121,7 @@ local function parse_perf_data_block(data, pos)
-- Ensure that the system name is directly after the header. This technically shouldn't matter, but Microsoft's documentation
-- (in WinPref.h) says that the actual object comes "after the PERF_DATA_BLOCK", so it doesn't make sense that the SystemName
-- could be anywhere else.
-- could be anywhere else.
if(pos ~= result['SystemNameOffset'] + 1) then
return false, "MSRPC: PERF_DATA_BLOCK has SystemName in the wrong location"
end
@@ -215,8 +215,8 @@ end
-- } PERF_OBJECT_TYPE, *PPERF_OBJECT_TYPE;
--</code>
--
--@param data The data being processed.
--@param pos The position within <code>data</code>.
--@param data The data being processed.
--@param pos The position within <code>data</code>.
--@return (status, pos, result) The status (true if successful), the new position in <code>data</code> (or an error
-- message), and a table representing the datatype, if any.
local function parse_perf_object_type(data, pos)
@@ -285,8 +285,8 @@ end
-- } PERF_COUNTER_DEFINITION, *PPERF_COUNTER_DEFINITION;
--</code>
--
--@param data The data being processed.
--@param pos The position within <code>data</code>.
--@param data The data being processed.
--@param pos The position within <code>data</code>.
--@return (status, pos, result) The status (true if successful), the new position in <code>data</code> (or an error
-- message), and a table representing the datatype, if any.
local function parse_perf_counter_definition(data, pos)
@@ -310,14 +310,14 @@ local function parse_perf_counter_definition(data, pos)
end
---Parse the actual counter value. This is a fairly simple function, it takes a counter
-- definition and pulls out data based on it.
-- definition and pulls out data based on it.
--
-- Note: I don't think this is doing the 8-byte values right, I suspect that they're supposed
-- to be doubles.
-- to be doubles.
--
--@param data The data being processed.
--@param pos The position within <code>data</code>.
--@param counter_definition The matching counter_definition.
--@param data The data being processed.
--@param pos The position within <code>data</code>.
--@param counter_definition The matching counter_definition.
--@return (status, pos, result) The status (true if successful), the new position in <code>data</code> (or an error
-- message), and a table representing the datatype, if any.
local function parse_perf_counter(data, pos, counter_definition)
@@ -374,8 +374,8 @@ end
-- } PERF_INSTANCE_DEFINITION, *PPERF_INSTANCE_DEFINITION;
--</code>
--
--@param data The data being processed.
--@param pos The position within <code>data</code>.
--@param data The data being processed.
--@param pos The position within <code>data</code>.
--@return (status, pos, result) The status (true if successful), the new position in <code>data</code> (or an error
-- message), and a table representing the datatype, if any.
local function parse_perf_instance_definition(data, pos)
@@ -406,11 +406,11 @@ end
-- DWORD ByteLength; // Length in bytes of this structure,
-- // including the following counters
-- } PERF_COUNTER_BLOCK, *PPERF_COUNTER_BLOCK;
--
--
--</code>
--
--@param data The data being processed.
--@param pos The position within <code>data</code>.
--@param data The data being processed.
--@param pos The position within <code>data</code>.
--@return (status, pos, result) The status (true if successful), the new position in <code>data</code> (or an error
-- message), and a table representing the datatype, if any.
local function parse_perf_counter_block(data, pos)
@@ -422,12 +422,12 @@ local function parse_perf_counter_block(data, pos)
end
---Retrieve the parsed performance data from the given host for the requested object values. To get a list of possible
-- object values, leave 'objects' blank and look at <code>result['title_database']</code> -- it'll contain a list of
-- indexes that can be looked up. These indexes are passed as a string or as a series of space-separated strings (eg,
-- "230" for "Process" and "238" for "Process" and "Processor").
-- object values, leave 'objects' blank and look at <code>result['title_database']</code> -- it'll contain a list of
-- indexes that can be looked up. These indexes are passed as a string or as a series of space-separated strings (eg,
-- "230" for "Process" and "238" for "Process" and "Processor").
--
--@param host The host object
--@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)
-- Create the SMB session
@@ -508,7 +508,7 @@ function get_performance_data(host, objects)
--stdnse.print_debug("Index = %d\n", object_type['ObjectNameTitleIndex'])
local object_name = result['title_database'][object_type['ObjectNameTitleIndex']]
result[object_name] = {}
--stdnse.print_debug("\n\nOBJECT: %s\n", object_name)
--stdnse.print_debug(" Counters: %d\n", object_type['NumCounters'])
--stdnse.print_debug(" Instances: %d\n", object_type['NumInstances'])
@@ -547,7 +547,7 @@ function get_performance_data(host, objects)
-- Set up the instance array
local instance_name = object_instances[j]['InstanceName']
result[object_name][instance_name] = {}
-- Bring the pos to the start of the counter block
pos = instance_start + object_instances[j]['ByteLength']
@@ -556,7 +556,7 @@ function get_performance_data(host, objects)
--stdnse.print_debug(" NameOffset: %d\n", object_instances[j]['NameOffset'])
--stdnse.print_debug(" NameLength: %d\n", object_instances[j]['NameLength'])
--stdnse.print_debug(" --------------\n")
-- The counter block
local status, counter_block
status, pos, counter_block = parse_perf_counter_block(queryvalue_result['value'], pos)
@@ -564,7 +564,7 @@ function get_performance_data(host, objects)
msrpc.stop_smb(smbstate)
return false, pos
end
for k = 1, object_type['NumCounters'], 1 do
-- Each individual counter
local status, counter_result
@@ -580,7 +580,7 @@ function get_performance_data(host, objects)
-- Save it in the result
result[object_name][instance_name][counter_name] = counter_result
end
-- Bring the pos to the end of the next section
pos = instance_start + object_instances[j]['ByteLength'] + counter_block['ByteLength']
end
@@ -608,7 +608,7 @@ function get_performance_data(host, objects)
end
msrpc.stop_smb(smbstate)
return true, result
end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -17,7 +17,7 @@ _ENV = stdnse.module("mysql", stdnse.seeall)
-- Version 0.3
--
-- Created 01/15/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Created 01/15/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 01/23/2010 - v0.2 - added query support, cleanup, documentation
-- Revised 08/24/2010 - v0.3 - added error handling for recieveGreeting
-- fixed a number of incorrect receives and changed
@@ -27,7 +27,7 @@ local tab = require('tab')
local HAVE_SSL, openssl = pcall(require,'openssl')
Capabilities =
Capabilities =
{
LongPassword = 0x1,
FoundRows = 0x2,
@@ -58,7 +58,7 @@ Charset =
latin1_COLLATE_latin1_swedish_ci = 0x8
}
ServerStatus =
ServerStatus =
{
InTransaction = 0x1,
AutoCommit = 0x2,
@@ -72,7 +72,7 @@ ServerStatus =
NoBackslashEscapes = 0x200
}
Command =
Command =
{
Query = 3
}
@@ -86,14 +86,14 @@ local HEADER_SIZE = 4
-- @param data string of raw data
-- @return response table containing the fields <code>len</code> and <code>packetno</code>
local function decodeHeader( data, pos )
local response = {}
local pos, tmp = pos or 1, 0
pos, tmp = bin.unpack( "I", data, pos )
response.len = bit.band( tmp,255 )
response.number = bit.rshift( tmp, 24 )
return pos, response
end
@@ -106,21 +106,21 @@ end
-- <code>status</code> or error message on failure (status == false)
function receiveGreeting( socket )
local catch = function() socket:close() stdnse.print_debug("receiveGreeting(): failed") end
local catch = function() socket:close() stdnse.print_debug("receiveGreeting(): failed") end
local try = nmap.new_try(catch)
local data = try( socket:receive_bytes(HEADER_SIZE) )
local pos, response, tmp, _
pos, response = decodeHeader( data, 1 )
pos, response = decodeHeader( data, 1 )
-- do we need to read the remainder
if ( #data - HEADER_SIZE < response.len ) then
local tmp = try( socket:receive_bytes( response.len - #data + HEADER_SIZE ) )
data = data .. tmp
end
local is_error
pos, is_error = bin.unpack( "C", data, pos )
pos, is_error = bin.unpack( "C", data, pos )
if ( is_error == 0xff ) then
pos, response.errorcode = bin.unpack( "S", data, pos )
@@ -128,7 +128,7 @@ function receiveGreeting( socket )
return false, response.errormsg
end
pos, response.proto = bin.unpack( "C", data, pos )
pos, response.version = bin.unpack( "z", data, pos )
pos, response.threadid = bin.unpack( "I", data, pos )
@@ -138,12 +138,12 @@ function receiveGreeting( socket )
pos, response.status = bin.unpack( "S", data, pos )
pos, _ = bin.unpack( "A13", data, pos )
pos, tmp = bin.unpack( "A12", data, pos )
response.salt = response.salt .. tmp
response.errorcode = 0
return true, response
end
@@ -193,7 +193,7 @@ end
-- @return response table or error message on failure
function loginRequest( socket, params, username, password, salt )
local catch = function() socket:close() stdnse.print_debug("loginRequest(): failed") end
local catch = function() socket:close() stdnse.print_debug("loginRequest(): failed") end
local try = nmap.new_try(catch)
local packetno = 1
local authversion = params.authversion or "post41"
@@ -201,7 +201,7 @@ function loginRequest( socket, params, username, password, salt )
if not(HAVE_SSL) then
return false, "No OpenSSL"
end
end
if authversion ~= "post41" then
return false, "Unsupported authentication version: " .. authversion
@@ -214,70 +214,70 @@ function loginRequest( socket, params, username, password, salt )
clicap = clicap + Capabilities.InteractiveClient
clicap = clicap + Capabilities.SupportsTransactions
clicap = clicap + Capabilities.Support41Auth
local extcapabilities = ExtCapabilities.SupportsMultipleStatments
extcapabilities = extcapabilities + ExtCapabilities.SupportsMultipleResults
local packet = bin.pack( "S", clicap )
packet = packet .. bin.pack( "S", extcapabilities )
packet = packet .. bin.pack( "I", MAXPACKET )
packet = packet .. bin.pack( "C", Charset.latin1_COLLATE_latin1_swedish_ci )
packet = packet .. bin.pack( "A", string.char(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) )
packet = packet .. bin.pack( "z", username )
if ( password ~= nil and password:len() > 0 ) then
local hash = createLoginHash( password, salt )
packet = packet .. bin.pack( "A", string.char( 0x14 ) .. hash )
else
packet = packet .. bin.pack( "C", 0 )
end
local tmp = packet:len() + bit.lshift( packetno, 24 )
packet = bin.pack( "I", tmp ) .. packet
try( socket:send(packet) )
packet = try( socket:receive_bytes(HEADER_SIZE) )
local pos, response = decodeHeader( packet )
-- do we need to read the remainder
if ( #packet - HEADER_SIZE < response.len ) then
local tmp = try( socket:receive_bytes( response.len - #packet + HEADER_SIZE ) )
packet = packet .. tmp
end
local is_error
pos, is_error = bin.unpack( "C", packet, pos )
pos, is_error = bin.unpack( "C", packet, pos )
if is_error > 0 then
pos, response.errorcode = bin.unpack( "S", packet, pos )
local has_sqlstate
pos, has_sqlstate = bin.unpack( "C", packet, pos )
if has_sqlstate == 35 then
pos, response.sqlstate = bin.unpack( "A5", packet, pos )
end
pos, response.errormessage = bin.unpack( "z", packet, pos )
pos, response.errormessage = bin.unpack( "z", packet, pos )
return false, response.errormessage
else
response.errorcode = 0
pos, response.affectedrows = bin.unpack( "C", packet, pos )
pos, response.serverstatus = bin.unpack( "S", packet, pos )
pos, response.warnings = bin.unpack( "S", packet, pos )
pos, response.warnings = bin.unpack( "S", packet, pos )
end
return true, response
end
--- Decodes a single column field
--
-- http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Field_Packet
--
--
-- @param data string containing field packets
-- @param pos number containing position from which to start decoding
-- the position should point to the data in this buffer (ie. after the header)
@@ -286,14 +286,14 @@ end
-- <code>origt_table</code>, <code>name</code>, <code>orig_name</code>,
-- <code>length</code> and <code>type</code>
function decodeField( data, pos )
local header, len
local def, _
local field = {}
pos, len = bin.unpack( "C", data, pos )
pos, field.catalog = bin.unpack( "A" .. len, data, pos )
pos, len = bin.unpack( "C", data, pos )
pos, field.database = bin.unpack( "A" .. len, data, pos )
@@ -311,15 +311,15 @@ function decodeField( data, pos )
-- should be 0x0C
pos, _ = bin.unpack( "C", data, pos )
-- charset, in my case 0x0800
pos, _ = bin.unpack( "S", data, pos )
pos, field.length = bin.unpack( "I", data, pos )
pos, field.type = bin.unpack( "A6", data, pos )
return pos, field
end
--- Decodes the result set header packet into it's sub components
@@ -330,13 +330,13 @@ end
-- @return table containing the following <code>header</code>, <code>fields</code> and <code>data</code>
function decodeQueryResponse( socket )
local catch = function() socket:close() stdnse.print_debug("decodeQueryResponse(): failed") end
local catch = function() socket:close() stdnse.print_debug("decodeQueryResponse(): failed") end
local try = nmap.new_try(catch)
local data, header, pos
local rs, blocks = {}, {}
local block_start, block_end
local EOF_MARKER = 254
data = try( socket:receive_bytes(HEADER_SIZE) )
pos, header = decodeHeader( data, pos )
@@ -346,9 +346,9 @@ function decodeQueryResponse( socket )
if data:len() < header.len then
data = data .. try( socket:receive_bytes( header.len - #data + HEADER_SIZE ) )
end
rs.header = data:sub( 1, HEADER_SIZE + header.len )
-- abort on MySQL error
if rs.header:sub(HEADER_SIZE + 1, HEADER_SIZE + 1) == string.char(0xFF) then
-- is this a 4.0 or 4.1 error message
@@ -360,29 +360,29 @@ function decodeQueryResponse( socket )
end
pos = HEADER_SIZE + header.len + 1
-- Second, Let's attempt to read the "Field Packets" and "Row Data Packets"
-- They're separated by an "EOF Packet"
for i=1,2 do
-- marks the start of our block
block_start = pos
while true do
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
pos, header = decodeHeader( data, pos )
if data:len() - pos < header.len - 1 then
data = data .. try( socket:receive_bytes( header.len - ( data:len() - pos ) ) )
end
if header.len > 0 then
local _, b = bin.unpack("C", data, pos )
local _, b = bin.unpack("C", data, pos )
-- Is this the EOF packet?
if b == EOF_MARKER then
-- we don't want the EOF Packet included
@@ -397,15 +397,15 @@ function decodeQueryResponse( socket )
end
blocks[i] = data:sub( block_start, block_end )
end
rs.fields = blocks[1]
rs.data = blocks[2]
return true, rs
end
--- Decodes as field packet and returns a table of field tables
@@ -415,23 +415,23 @@ end
-- @param data string containing field packets
-- @param count number containing the amount of fields to decode
-- @return status boolean (true on success, false on failure)
-- @return fields table containing field tables as returned by <code>decodeField</code>
-- @return fields table containing field tables as returned by <code>decodeField</code>
-- or string containing error message if status is false
function decodeFieldPackets( data, count )
local pos, header
local field, fields = {}, {}
if count < 1 then
return false, "Field count was less than one, aborting"
end
for i=1, count do
pos, header = decodeHeader( data, pos )
pos, field = decodeField( data, pos )
table.insert( fields, field )
end
return true, fields
end
@@ -442,15 +442,15 @@ end
-- @param data string containing the result set header packet
-- @return number containing the amount of fields
function decodeResultSetHeader( data )
local _, fields
if data:len() ~= HEADER_SIZE + 1 then
return false, "Result set header was incorrect"
end
end
_, fields = bin.unpack( "C", data, HEADER_SIZE + 1 )
return true, fields
end
@@ -463,25 +463,25 @@ end
-- @return status true on success, false on failure
-- @return rows table containing row tables
function decodeDataPackets( data, count )
local len, pos = 0, 1, 1
local header, row, rows = {}, {}, {}
while pos < data:len() do
row = {}
pos, header = decodeHeader( data, pos )
for i=1, count do
pos, len = bin.unpack("C", data, pos )
pos, row[i] = bin.unpack("A" .. len, data, pos)
end
table.insert( rows, row )
end
return true, rows
end
--- Sends the query to the MySQL server and then attempts to decode the response
@@ -492,13 +492,13 @@ end
-- @return rows table containing row tabels as decoded by <code>decodeDataPackets</code>
function sqlQuery( socket, query )
local catch = function() socket:close() stdnse.print_debug("sqlQuery(): failed") end
local catch = function() socket:close() stdnse.print_debug("sqlQuery(): failed") end
local try = nmap.new_try(catch)
local packetno = 0
local querylen = query:len() + 1
local packet, packet_len, pos, header
local status, fields, field_count, rows, rs
packet = bin.pack("ICA", querylen, Command.Query, query )
--
@@ -509,18 +509,18 @@ function sqlQuery( socket, query )
-- (EOF Packet) marker: end of Field Packets
-- (Row Data Packets) row contents
-- (EOF Packet) marker: end of Data Packets
try( socket:send(packet) )
--
-- Let's read all the data into a table
-- This way we avoid the hustle with reading from the socket
status, rs = decodeQueryResponse( socket )
if not status then
return false, rs
end
status, field_count = decodeResultSetHeader(rs.header)
if not status then
@@ -528,7 +528,7 @@ function sqlQuery( socket, query )
end
status, fields = decodeFieldPackets(rs.fields, field_count)
if not status then
return false, fields
end
@@ -538,8 +538,8 @@ function sqlQuery( socket, query )
if not status then
return false, rows
end
return true, { cols = fields, rows = rows }
return true, { cols = fields, rows = rows }
end
---
@@ -557,16 +557,16 @@ function formatResultset(rs, options)
local restab = tab.new(#rs.cols)
local colnames = {}
if ( not(options.noheaders) ) then
for _, col in ipairs(rs.cols) do table.insert(colnames, col.name) end
tab.addrow(restab, table.unpack(colnames))
end
for _, row in ipairs(rs.rows) do
tab.addrow(restab, table.unpack(row))
end
return tab.dump(restab)
end

View File

@@ -2,7 +2,7 @@
-- This library implements the basics of NAT-PMP as described in the
-- NAT Port Mapping Protocol (NAT-PMP) draft:
-- o http://tools.ietf.org/html/draft-cheshire-nat-pmp-03
--
--
--
-- @author "Patrik Karlsson <patrik@cqure.net>"
--
@@ -12,7 +12,7 @@ local nmap = require "nmap"
local stdnse = require "stdnse"
_ENV = stdnse.module("natpmp", stdnse.seeall)
local ResultCode = {
local ResultCode = {
SUCCESS = 0,
UNSUPPORTED_VERSION = 1,
NOT_AUTHORIZED = 2,
@@ -31,27 +31,27 @@ local ErrorMessage = {
Request = {
GetWANIP = {
new = function(self)
local o = { version = 0, op = 0 }
setmetatable(o, self)
self.__index = self
return o
end,
__tostring = function(self)
return bin.pack(">CC", self.version, self.op)
end,
},
MapPort = {
new = function(self, pubport, privport, proto, lifetime)
assert(proto == "udp" or proto == "tcp", "Unsupported protocol")
local o = {
local o = {
version = 0,
pubport = pubport,
privport = privport,
@@ -64,22 +64,22 @@ Request = {
end,
__tostring = function(self)
return bin.pack(">CCSSSI",
self.version,
return bin.pack(">CCSSSI",
self.version,
(self.proto=="udp" and 1 or 2),
0, -- reserved
self.privport, self.pubport,
self.lifetime)
end,
}
}
Response = {
GetWANIP = {
new = function(self, data)
local o = { data = data }
setmetatable(o, self)
@@ -93,24 +93,24 @@ Response = {
if ( #self.data ~= 12 ) then
return
end
local pos
pos, self.version, self.op, self.rescode = bin.unpack("<CCS", self.data)
if ( self.rescode ~= ResultCode.SUCCESS or self.op ~= 128 ) then
return
end
pos, self.time, self.ip = bin.unpack("<II", self.data, pos)
self.ip = ipOps.fromdword(self.ip)
self.time = stdnse.format_timestamp(self.time)
return true
end,
},
MapPort = {
new = function(self, data)
local o = { data = data }
setmetatable(o, self)
@@ -124,20 +124,20 @@ Response = {
if ( #self.data ~= 16 ) then
return
end
local pos
pos, self.version, self.op, self.rescode = bin.unpack("<CCS", self.data)
if ( self.rescode ~= ResultCode.SUCCESS ) then
return
end
pos, self.time, self.privport, self.pubport, self.lifetime = bin.unpack(">ISSI", self.data, pos)
return true
end,
}
}
@@ -145,33 +145,33 @@ Response = {
Helper = {
new = function(self, host, port)
local o = { host = host, port = port }
setmetatable(o, self)
self.__index = self
return o
end,
exchPacket = function(self, data)
local socket = nmap.new_socket("udp")
socket:set_timeout(5000)
local status = socket:sendto(self.host, self.port, data)
if ( not(status) ) then
socket:close()
return false, "Failed to send request to device"
end
local response
status, response = socket:receive()
status, response = socket:receive()
socket:close()
if ( not(status) ) then
return false, "Failed to receive response from router"
end
return true, response
end,
--- Gets the WAN ip of the router
getWANIP = function(self)
local packet = Request.GetWANIP:new()
@@ -179,7 +179,7 @@ Helper = {
if ( not(status) ) then
return status, response
end
response = Response.GetWANIP:new(response)
if ( not(response) ) then
return false, "Failed to parse response from router"
@@ -187,7 +187,7 @@ Helper = {
return true, response
end,
--- Maps a public port to a private port
-- @param pubport number containing the public external port to map
-- @param privport number containing the private internal port to map
@@ -199,7 +199,7 @@ Helper = {
if ( not(status) ) then
return status, response
end
response = Response.MapPort:new(response)
if ( not(response) ) then
return false, "Failed to parse response from router"
@@ -207,15 +207,15 @@ Helper = {
return true, response
end,
unmapPort = function(self, pubport, privport)
return self:mapPort(pubport, privport, 0)
end,
unmapAllPorts = function(self)
return self.mapPort(0, 0, 0)
end,
}
return _ENV;

View File

@@ -24,7 +24,7 @@
-- * NCP
-- - Contains the "native" NCP functions sending the actual request to the
-- server.
--
--
-- * Socket
-- - A buffered socket implementation
--
@@ -85,13 +85,13 @@ NCPFunction = {
NCPVerb = {
Resolve = 1,
List = 5,
List = 5,
Search = 6,
}
-- The NCP Packet
Packet = {
--- Creates a new instance of Packet
-- @return o instance of Packet
new = function(self)
@@ -111,7 +111,7 @@ Packet = {
--- Sets the NCP packet length
-- @param n number containing the length
setNCPLength = function(self, n) self.ncp_ip.length = n end,
--- Gets the NCP packet length
-- @return n number containing the NCP length
getNCPLength = function(self) return self.ncp_ip.length end,
@@ -119,59 +119,59 @@ Packet = {
--- Sets the NCP packet type
-- @param t number containing the NCP packet type
setType = function(self, t) self.type = t end,
--- Gets the NCP packet type
-- @return type number containing the NCP packet type
getType = function(self) return self.type end,
--- Sets the NCP packet function
-- @param t number containing the NCP function
setFunc = function(self, f) self.func = f end,
--- Gets the NCP packet function
-- @return func number containing the NCP packet function
getFunc = function(self) return self.func end,
--- Sets the NCP sequence number
-- @param seqno number containing the sequence number
setSeqNo = function(self, n) self.seqno = n end,
--- Sets the NCP connection number
-- @param conn number containing the connection number
setConnNo = function(self, n) self.conn = n end,
--- Gets the NCP connection number
-- @return conn number containing the connection number
getConnNo = function(self) return self.conn end,
--- Sets the NCP sub function
-- @param subfunc number containing the subfunction
setSubFunc = function(self, n) self.subfunc = n end,
--- Gets the NCP sub function
-- @return subfunc number containing the subfunction
getSubFunc = function(self) return self.subfunc end,
--- Gets the Sequence number
-- @return seqno number containing the sequence number
getSeqNo = function(self) return self.seqno end,
--- Sets the packet length
-- @param len number containing the packet length
setLength = function(self, n) self.length = n end,
--- Sets the packet data
-- @param data string containing the packet data
setData = function(self, data) self.data = data end,
--- Gets the packet data
-- @return data string containing the packet data
getData = function(self) return self.data end,
--- Sets the packet task
-- @param task number containing the packet number
setTask = function(self, task) self.task = task end,
--- "Serializes" the packet to a string
__tostring = function(self)
local UNKNOWN = 0
@@ -183,15 +183,15 @@ Packet = {
if ( self.length ) then data = data .. bin.pack(">S", self.length) end
if ( self.subfunc ) then data = data .. bin.pack("C", self.subfunc) end
if ( self.data ) then data = data .. bin.pack("A", self.data) end
return data
end,
}
-- Parses different responses into suitable tables
ResponseParser = {
--- Determines what parser to call based on the contents of the client
-- request and server response.
-- @param req instance of Packet containing the request to the server
@@ -224,10 +224,10 @@ ResponseParser = {
return false, "ResponseParser: Failed to parse response"
end
end
return false, "ResponseParser: Failed to parse response"
end,
--- Decodes a GetFileServerInfo response
-- @param resp string containing the response as received from the server
-- @return status true on success, false on failure
@@ -258,28 +258,28 @@ ResponseParser = {
[NCPFunction.GetFileServerInfo] = function(resp)
local data = resp:getData()
local len = #data
if ( len < 78 ) then
return false, "Failed to decode GetFileServerInfo"
end
local result = {}
local pos
pos, result.srvname, result.os_major, result.os_minor,
pos, result.srvname, result.os_major, result.os_minor,
result.conns_supported, result.conns_inuse,
result.vols_supported, result.os_rev, result.sft_support,
result.tts_level, result.conns_max_use, result.acct_version,
result.vap_version, result.qms_version, result.print_version,
result.virt_console_ver, result.sec_restrict_ver,
result.internet_bridge_ver, result.mixed_mode_path,
result.virt_console_ver, result.sec_restrict_ver,
result.internet_bridge_ver, result.mixed_mode_path,
result.local_login_info, result.product_major,
result.product_minor, result.product_rev, result.os_lang_id,
result.product_minor, result.product_rev, result.os_lang_id,
result.support_64_bit = bin.unpack(">A48CCSSSCCCSCCCCCCCCCSSSCC", data)
return true, result
end,
--- Decodes a GetMountVolumeList response
-- @param resp string containing the response as received from the server
-- @return status true on success, false on failure
@@ -290,7 +290,7 @@ ResponseParser = {
[NCPFunction.GetMountVolumeList] = function(resp)
local data = resp:getData()
local len = #data
local pos, items, next_vol_no = bin.unpack("<II", data)
local vols = {}
for i=1, items do
@@ -300,7 +300,7 @@ ResponseParser = {
end
return true, vols
end,
--- Decodes a Ping response
-- @param resp string containing the response as received from the server
-- @return status true on success, false on failure
@@ -312,19 +312,19 @@ ResponseParser = {
local len = #data
local pos
local result = {}
if ( len < 40 ) then return false, "NCP Ping result too short" end
pos, result.nds_version = bin.unpack("C", data)
-- move to the offset of the
pos = pos + 7
pos, result.tree_name = bin.unpack("A32", data, pos)
result.tree_name = (result.tree_name:match("^([^_]*)_*$"))
return true, result
end,
--- Decodes a EnumerateNetworkAddress response
-- @param resp string containing the response as received from the server
-- @return status true on success, false on failure
@@ -336,24 +336,24 @@ ResponseParser = {
local items
local data = resp:getData()
local len = #data
pos, result.time_since_boot, result.console_version, result.console_revision,
result.srvinfo_flags, result.guid, result.next_search,
items = bin.unpack("<ICCSA16II", data)
local function DecodeAddress(data, pos)
local COMM_TYPES = { [5] = "udp", [6] = "tcp" }
local comm_type, port, ip, _
pos, comm_type, _, _, _, port, ip = bin.unpack(">CCISS<I", data, pos)
return pos, { port = port, ip = ipOps.fromdword(ip),
return pos, { port = port, ip = ipOps.fromdword(ip),
proto = COMM_TYPES[comm_type] or "unknown" }
end
if ( ( pos - 1 ) + (items * 14 ) > len ) then
return false, "EnumerateNetworkAddress packet too short"
end
result.addr = {}
for i=1, items do
local addr = {}
@@ -362,8 +362,8 @@ ResponseParser = {
end
return true, result
end,
--- Decodes a Resolve response
-- @param resp string containing the response as received from the server
-- @return status true on success, false on failure
@@ -373,28 +373,28 @@ ResponseParser = {
Resolve = function(resp)
local data = resp:getData()
local len = #data
if ( len < 12 ) then
return false, "ResponseParser: NCP Resolve, packet too short"
end
local pos, frag_size, frag_handle, comp_code = bin.unpack("<III", data)
if ( len < 38 ) then
return false, "ResponseParser: message too short"
end
if ( comp_code ~= 0 ) then
return false, ("ResponseParser: Completion code returned" ..
" non-zero value (%d)"):format(comp_code)
end
local pos, tag, entry = bin.unpack("<II", data, pos)
return true, { tag = tag, id = entry }
end,
--- Decodes a Search response
-- @param resp string containing the response as received from the server
-- @return status true on success, false on failure
@@ -405,22 +405,22 @@ ResponseParser = {
local data = resp:getData()
local len = #data
local entries = {}
if ( len < 12 ) then
return false, "ResponseParser: NCP Resolve, packet too short"
end
local pos, frag_size, frag_handle, comp_code, iter_handle = bin.unpack("<IIII", data)
if ( comp_code ~= 0 ) then
return false, ("ResponseParser: Completion code returned" ..
" non-zero value (%d)"):format(comp_code)
end
pos = pos + 12
local entry_count
pos, entry_count = bin.unpack("<I", data, pos)
for i=1, entry_count do
local entry
pos, entry = ResponseParser.EntryDecoder(data, pos)
@@ -430,14 +430,14 @@ ResponseParser = {
end
return true, entries
end,
--- The EntryDecoder is used by the Search and List function, for decoding
-- the returned entries.
-- @param data containing the response as returned by the server
-- @param pos number containing the offset into data to start decoding
-- @return pos number containing the new offset after decoding
-- @return entry table containing the decoded entry, currently it contains
-- one or more of the following fields:
-- one or more of the following fields:
-- <code>flags</code>
-- <code>mod_time</code>
-- <code>sub_count</code>
@@ -490,11 +490,11 @@ ResponseParser = {
if ( iflags.Entry ) then
pos, entry.flags, entry.sub_count = bin.unpack("<II", data, pos)
end
if ( iflags.ModTime ) then
pos, entry.mod_time = bin.unpack("<I", data, pos)
end
if ( iflags.BaseClass ) then
pos, len = bin.unpack("<I", data, pos)
pos, entry.baseclass = bin.unpack("A" .. len, data, pos)
@@ -510,7 +510,7 @@ ResponseParser = {
entry.rdn = Util.CToLuaString(entry.rdn)
pos = ( len % 4 == 0 ) and pos or pos + ( 4 - ( len % 4 ) )
end
if ( iflags.DN ) then
pos, len = bin.unpack("<I", data, pos)
pos, entry.name = bin.unpack("A" .. len, data, pos)
@@ -518,11 +518,11 @@ ResponseParser = {
entry.name = Util.CToLuaString(entry.name)
pos = ( len % 4 == 0 ) and pos or pos + ( 4 - ( len % 4 ) )
end
return pos, entry
end,
--- Decodes a List response
-- @param resp string containing the response as received from the server
-- @return status true on success, false on failure
@@ -532,29 +532,29 @@ ResponseParser = {
List = function(resp)
local data = resp:getData()
local len = #data
if ( len < 12 ) then
return false, "ResponseParser: NCP Resolve, packet too short"
end
local pos, frag_size, frag_handle, comp_code, iter_handle = bin.unpack("<IIII", data)
if ( comp_code ~= 0 ) then
return false, ("ResponseParser: Completion code returned" ..
" non-zero value (%d)"):format(comp_code)
end
local entry_count
pos, entry_count = bin.unpack("<I", data, pos)
local entries = {}
for i=1, entry_count do
local entry = {}
pos, entry = ResponseParser.EntryDecoder(data, pos)
table.insert(entries, entry)
end
return true, entries
end,
}
@@ -581,11 +581,11 @@ Response = {
--- Parses the Response
parse = function(self)
local pos, _
pos, self.signature, self.length, self.type,
self.seqno, self.conn, _, self.compl_code,
pos, self.signature, self.length, self.type,
self.seqno, self.conn, _, self.compl_code,
self.status_code = bin.unpack(">IISCCSCC", self.header)
if ( self.data ) then
local len = #self.data - pos
if ( ( #self.data - pos ) ~= ( self.length - 33 ) ) then
@@ -594,7 +594,7 @@ Response = {
end
end
end,
--- Gets the sequence number
-- @return seqno number
getSeqNo = function(self) return self.seqno end,
@@ -602,11 +602,11 @@ Response = {
--- Gets the connection number
-- @return conn number
getConnNo = function(self) return self.conn end,
--- Gets the data portion of the response
-- @return data string
getData = function(self) return self.data end,
--- Gets the header portion of the response
getHeader = function(self) return self.header end,
@@ -615,9 +615,9 @@ Response = {
hasErrors = function(self)
return not( ( self.compl_code == Status.COMPLETION_OK ) and
( self.status_code == Status.CONNECTION_OK ) )
end,
--- Creates a Response instance from the data read of the socket
-- @param socket socket connected to server and ready to receive data
-- @return Response containing a new Response instance
@@ -627,26 +627,26 @@ Response = {
local pos, sig, len = bin.unpack(">II", header)
if ( len < 8 ) then return false, "NCP packet too short" end
local data
if ( 0 < len - 16 ) then
status, data = socket:recv(len - 16)
if ( not(status) ) then return false, "Failed to receive data" end
end
return true, Response:new(header, data)
end,
--- "Serializes" the Response instance to a string
__tostring = function(self)
return bin.pack("AA", self.header, self.data)
end,
}
-- The NCP class
NCP = {
--- Creates a new NCP instance
-- @param socket containing a socket connected to the NCP server
-- @return o instance of NCP
@@ -659,7 +659,7 @@ NCP = {
o.conn = 0
return o
end,
--- Handles sending and receiving a NCP message
-- @param p Packet containing the request to send to the server
-- @return status true on success false on failure
@@ -669,16 +669,16 @@ NCP = {
Exch = function(self, p)
local status, err = self:SendPacket(p)
if ( not(status) ) then return status, err end
local status, resp = Response.fromSocket(self.socket)
if ( not(status) or resp:hasErrors() ) then return false, resp end
self.seqno = resp:getSeqNo()
self.conn = resp:getConnNo()
return ResponseParser.parse(p, resp)
end,
--- Sends a packet to the server
-- @param p Packet to be sent to the server
-- @return status true on success, false on failure
@@ -686,34 +686,34 @@ NCP = {
SendPacket = function(self, p)
if ( not(p:getSeqNo() ) ) then p:setSeqNo(self.seqno + 1) end
if ( not(p:getConnNo() ) ) then p:setConnNo(self.conn) end
if ( not(p:getNCPLength()) ) then
local len = #(tostring(p))
p:setNCPLength(len)
end
local status, err = self.socket:send(tostring(p))
if ( not(status) ) then return status, "Failed to send data" end
return true
end,
--- Creates a connection to the NCP server
-- @return status true on success, false on failure
CreateConnect = function(self)
local p = Packet:new()
p:setType(NCPType.CreateConnection)
local resp = self:Exch( p )
return true
end,
--- Destroys a connection established with the NCP server
-- @return status true on success, false on failure
DestroyConnect = function(self)
local p = Packet:new()
p:setType(NCPType.DestroyConnection)
local resp = self:Exch( p )
return true
end,
@@ -767,12 +767,12 @@ NCP = {
-- p:setLength(5)
-- p:setSubFunc(28)
-- p:setTask(4)
--
--
-- local data = bin.pack("<I", conn_no)
-- p:setData(data)
-- return self:Exch( p )
-- end,
--- Sends a PING to the server which responds with the tree name
-- @return status true on success, false on failure
-- @return response table (if status is true) containing:
@@ -810,28 +810,28 @@ NCP = {
-- @return status true on success, false on failure
-- @return response table (if status is true) containing:
-- <code>tag</code> and <code>id</code>
-- @return error message (if status is false)
-- @return error message (if status is false)
ResolveName = function(self, name)
local p = Packet:new()
p:setType(NCPType.ServiceRequest)
p:setFunc(NCPFunction.SendFragmentedRequest)
p:setSubFunc(2)
p:setNCPReplyBuf(4108)
local pad = (4 - ( #name % 4 ) )
name = Util.ZeroPad(name, #name + pad)
local w_name = Util.ToWideChar(name)
local frag_handle, frag_size = 0xffffffff, 64176
local msg_size, unknown, proto_flags, nds_verb = 44 + #w_name, 0, 0, 1
local nds_reply_buf, version, flags, scope = 4096, 1, 0x2062, 0
local unknown2 = 0x0e
local ZERO = 0
local data = bin.pack("<IIISSIIISSIIA", frag_handle, frag_size, msg_size,
unknown, proto_flags, nds_verb, nds_reply_buf, version, flags,
unknown, scope, #w_name, w_name, ZERO)
local comms = { { transport = "TCP" } }
local walkers= { { transport = "TCP" } }
local PROTOCOLS = { ["TCP"] = 9 }
@@ -840,7 +840,7 @@ NCP = {
for _, comm in ipairs(comms) do
data = data .. bin.pack("<I", PROTOCOLS[comm.transport])
end
data = data .. bin.pack("<I", #walkers)
for _, walker in ipairs(walkers) do
data = data .. bin.pack("<I", PROTOCOLS[walker.transport])
@@ -849,7 +849,7 @@ NCP = {
p:setData(data)
return self:Exch( p )
end,
--- Gets a list of volumes from the server
-- @return status true on success, false on failure
-- @return response table of vol entries (if status is true)
@@ -864,16 +864,16 @@ NCP = {
p:setNCPReplyBuf(538)
p:setTask(4)
p:setLength(12)
local start_vol = 0
local vol_req_flags = 1
local src_name_space = 0
local data = bin.pack("<III", start_vol, vol_req_flags, src_name_space )
p:setData(data)
p:setData(data)
return self:Exch( p )
end,
--- Searches the directory
-- @param base entry as resolved by <code>Resolve</code>
-- @param class string containing a class name (or * wildcard)
@@ -886,7 +886,7 @@ NCP = {
-- @return error string (if status is false) containing the error
Search = function(self, base, class, name, options)
assert( ( base and base.id ), "No base entry was specified")
local class = class and class .. '\0' or '*\0'
local name = name and name .. '\0' or '*\0'
local w_name = Util.ToWideChar(name)
@@ -898,7 +898,7 @@ NCP = {
p:setSubFunc(2)
p:setNCPReplyBuf(64520)
p:setTask(5)
local frag_handle, frag_size, msg_size = 0xffffffff, 64176, 98
local unknown, proto_flags, nds_verb, version, flags = 0, 0, 6, 3, 0
local nds_reply_buf = 64520
@@ -909,16 +909,16 @@ NCP = {
local info_flags = 0x0000381d
-- a bunch of unknowns
local u2, u3, u4, u5, u6, u7, u8, u9 = 0, 0, 2, 2, 0, 0x10, 0, 0x11
local data = bin.pack("<IIISSIIIIIIIIIIIIIIIIIAIIIA",
local data = bin.pack("<IIISSIIIIIIIIIIIIIIIIIAIIIA",
frag_handle, frag_size, msg_size, unknown, proto_flags,
nds_verb, nds_reply_buf, version, flags, iter_handle,
base.id, repl_type, numobjs, info_types, info_flags, u2, u3, u4,
u5, u6, u7, #w_name, w_name, u8, u9, #w_class, w_class )
p:setData(data)
p:setData(data)
return self:Exch( p )
end,
--- Lists the contents of entry
-- @param entry entry as resolved by <code>Resolve</code>
-- @return status true on success false on failure
@@ -932,7 +932,7 @@ NCP = {
p:setSubFunc(2)
p:setNCPReplyBuf(4112)
p:setTask(2)
local frag_handle, frag_size = 0xffffffff, 64176
local msg_size, unknown, proto_flags, nds_verb = 40, 0, 0, 5
local nds_reply_buf, version, flags = 4100, 1, 0x0001
@@ -940,24 +940,24 @@ NCP = {
local unknown2 = 0x0e
local ZERO = 0
local info_flags = 0x0000381d
local data = bin.pack("<IIISSIIISSIII", frag_handle, frag_size, msg_size,
unknown, proto_flags, nds_verb, nds_reply_buf, version, flags,
unknown, iter_handle, entry.id, info_flags )
-- no name filter
data = data .. "\0\0\0\0"
-- no class filter
data = data .. "\0\0\0\0"
p:setData(data)
local status, entries = self:Exch( p )
if ( not(status) ) then return false, entries end
return true, entries
end,
}
@@ -980,17 +980,17 @@ Helper = {
self.socket = Socket:new()
local status, err = self.socket:connect(self.host, self.port)
if ( not(status) ) then return status, err end
self.ncp = NCP:new(self.socket)
return self.ncp:CreateConnect()
end,
--- Closes the helper connection
close = function(self)
self.ncp:DestroyConnect()
self.socket:close()
end,
--- Performs a directory search
-- @param base string containing the name of the base to search
-- @param class string containing the type of class to search
@@ -1000,17 +1000,17 @@ Helper = {
search = function(self, base, class, name, options)
local base = base or "[Root]"
local status, entry = self.ncp:ResolveName(base)
if ( not(status) ) then
return false, "Search failed, base could not be resolved"
end
local status, result = self.ncp:Search(entry, class, name, options)
if (not(status)) then return false, result end
return status, result
end,
--- Retrieves some information from the server using the following NCP
-- functions:
-- <code>GetFileServerInfo</code>
@@ -1021,33 +1021,33 @@ Helper = {
getServerInfo = function(self)
local status, srv_info = self.ncp:GetFileServerInfo()
if ( not(status) ) then return false, srv_info end
local status, ping_info = self.ncp:Ping()
if ( not(status) ) then return false, ping_info end
local status, net_info = self.ncp:EnumerateNetworkAddress()
if ( not(status) ) then return false, net_info end
local status, mnt_list = self.ncp:GetMountVolumeList()
if ( not(status) ) then return false, mnt_list end
local output = {}
table.insert(output, ("Server name: %s"):format(srv_info.srvname))
table.insert(output, ("Tree Name: %s"):format(ping_info.tree_name))
table.insert(output,
("OS Version: %d.%d (rev %d)"):format(srv_info.os_major,
table.insert(output,
("OS Version: %d.%d (rev %d)"):format(srv_info.os_major,
srv_info.os_minor, srv_info.os_rev))
table.insert(output,
table.insert(output,
("Product version: %d.%d (rev %d)"):format(srv_info.product_major,
srv_info.product_minor, srv_info.product_rev))
table.insert(output, ("OS Language ID: %d"):format(srv_info.os_lang_id))
local niceaddr = {}
for _, addr in ipairs(net_info.addr) do
table.insert(niceaddr, ("%s %d/%s"):format(addr.ip,addr.port,
table.insert(niceaddr, ("%s %d/%s"):format(addr.ip,addr.port,
addr.proto))
end
niceaddr.name = "Addresses"
table.insert(output, niceaddr)
@@ -1055,15 +1055,15 @@ Helper = {
for _, mount in ipairs(mnt_list) do
table.insert(mounts, mount.vol_name)
end
mounts.name = "Mounts"
table.insert(output, mounts)
if ( nmap.debugging() > 0 ) then
table.insert(output, ("Acct version: %d"):format(srv_info.acct_version))
table.insert(output, ("VAP version: %d"):format(srv_info.vap_version))
table.insert(output, ("QMS version: %d"):format(srv_info.qms_version))
table.insert(output,
table.insert(output,
("Print server version: %d"):format(srv_info.print_version))
table.insert(output,
("Virtual console version: %d"):format(srv_info.virt_console_ver))
@@ -1074,11 +1074,11 @@ Helper = {
end
return true, output
end,
end,
}
Socket =
{
{
new = function(self)
local o = {}
setmetatable(o, self)
@@ -1087,7 +1087,7 @@ Socket =
o.Buffer = nil
return o
end,
--- Sets the socket timeout (@see nmap.set_timeout)
-- @param tm number containing the socket timeout in ms
set_timeout = function(self, tm) self.Socket:set_timeout(tm) end,
@@ -1103,7 +1103,7 @@ Socket =
self.Socket:set_timeout(5000)
return self.Socket:connect( hostid, port, protocol )
end,
--- Closes an open connection.
--
-- @return Status (true or false).
@@ -1111,7 +1111,7 @@ Socket =
close = function( self )
return self.Socket:close()
end,
--- Opposed to the <code>socket:receive_bytes</code> function, that returns
-- at least x bytes, this function returns the amount of bytes requested.
--
@@ -1121,9 +1121,9 @@ Socket =
-- err containing error message if status is false
recv = function( self, count )
local status, data
self.Buffer = self.Buffer or ""
if ( #self.Buffer < count ) then
status, data = self.Socket:receive_bytes( count - #self.Buffer )
if ( not(status) or #data < count - #self.Buffer ) then
@@ -1131,13 +1131,13 @@ Socket =
end
self.Buffer = self.Buffer .. data
end
data = self.Buffer:sub( 1, count )
self.Buffer = self.Buffer:sub( count + 1)
return true, data
return true, data
end,
--- Sends data over the socket
--
-- @return Status (true or false).
@@ -1148,7 +1148,7 @@ Socket =
}
--- "static" Utility class containing mostly conversion functions
Util =
Util =
{
--- Converts a string to a wide string
--
@@ -1158,8 +1158,8 @@ Util =
ToWideChar = function( str )
return str:gsub("(.)", "%1" .. string.char(0x00) )
end,
--- Concerts a wide string to string
--
-- @param wstr containing the wide string to convert
@@ -1181,27 +1181,27 @@ Util =
for i=1, len - str:len() do str = str .. string.char(0) end
return str
end,
-- Removes trailing nulls
--
-- @param str containing the string
-- @return ret the string with any trailing nulls removed
CToLuaString = function( str )
local ret
if ( not(str) ) then return "" end
if ( str:sub(-1, -1 ) ~= "\0" ) then return str end
for i=1, #str do
if ( str:sub(-i,-i) == "\0" ) then
ret = str:sub(1, -i - 1)
if ( str:sub(-i,-i) == "\0" ) then
ret = str:sub(1, -i - 1)
else
break
end
end
return ret
end,
}
return _ENV;

View File

@@ -14,7 +14,7 @@ local table = require "table"
_ENV = stdnse.module("ndmp", stdnse.seeall)
NDMP = {
-- Message types
MessageType = {
CONFIG_GET_HOST_INFO = 0x00000100,
@@ -23,24 +23,24 @@ NDMP = {
CONFIG_GET_SERVER_INFO = 0x00000108,
CONNECT_CLIENT_AUTH = 0x00000901,
},
-- The fragment header, 4 bytes where the highest bit is used to determine
-- whether the fragment is the last or not.
-- whether the fragment is the last or not.
FragmentHeader = {
size = 4,
-- Creates a new instance of fragment header
-- @return o instance of Class
new = function(self)
local o = {
local o = {
last = true,
length = 24,
}
setmetatable(o, self)
self.__index = self
return o
return o
end,
-- Parse data stream and create a new instance of this class
-- @param data opaque string
-- @return fh new instance of FragmentHeader class
@@ -51,7 +51,7 @@ NDMP = {
fh.last= bit.rshift(tmp, 31)
return fh
end,
-- Serializes the instance to an opaque string
-- @return str string containing the serialized class
__tostring = function(self)
@@ -62,9 +62,9 @@ NDMP = {
tmp = tmp + self.length
return bin.pack(">I", tmp)
end,
},
-- The ndmp 24 byte header
Header = {
size = 24,
@@ -72,7 +72,7 @@ NDMP = {
-- creates a new instance of Header
-- @return o instance of Header
new = function(self)
local o = {
local o = {
seq = 0,
time = os.time(),
type = 0,
@@ -82,9 +82,9 @@ NDMP = {
}
setmetatable(o, self)
self.__index = self
return o
return o
end,
-- Create a Header instance from opaque data string
-- @param data opaque string
-- @return hdr new instance of Header
@@ -94,16 +94,16 @@ NDMP = {
pos, hdr.seq, hdr.time, hdr.type, hdr.msg, hdr.reply_seq, hdr.error = bin.unpack(">IIIIII", data)
return hdr
end,
-- Serializes the instance to an opaque string
-- @return str string containing the serialized class instance
__tostring = function(self)
return bin.pack(">IIIIII", self.seq, self.time, self.type, self.msg, self.reply_seq, self.error)
end,
},
}
NDMP.Message = {}
NDMP.Message.ConfigGetServerInfo = {
@@ -119,9 +119,9 @@ NDMP.Message.ConfigGetServerInfo = {
o.header.msg = NDMP.MessageType.CONFIG_GET_SERVER_INFO
setmetatable(o, self)
self.__index = self
return o
return o
end,
-- Create a ConfigGetServerInfo instance from opaque data string
-- @param data opaque string
-- @return msg new instance of ConfigGetServerInfo
@@ -131,7 +131,7 @@ NDMP.Message.ConfigGetServerInfo = {
data = data:sub(NDMP.FragmentHeader.size + 1)
msg.header = NDMP.Header.parse(data)
msg.data = data:sub(NDMP.Header.size + 1)
msg.serverinfo = {}
local pos, err = bin.unpack(">I", msg.data)
pos, msg.serverinfo.vendor = Util.parseString(msg.data, pos)
@@ -144,7 +144,7 @@ NDMP.Message.ConfigGetServerInfo = {
-- @return str string containing the serialized class instance
__tostring = function(self)
return tostring(self.frag_header) .. tostring(self.header) .. tostring(self.data or "")
end,
end,
}
@@ -158,7 +158,7 @@ NDMP.Message.ConfigGetHostInfo = {
o.header.msg = NDMP.MessageType.CONFIG_GET_HOST_INFO
setmetatable(o, self)
self.__index = self
return o
return o
end,
parse = function(data)
@@ -167,19 +167,19 @@ NDMP.Message.ConfigGetHostInfo = {
data = data:sub(NDMP.FragmentHeader.size + 1)
msg.header = NDMP.Header.parse(data)
msg.data = data:sub(NDMP.Header.size + 1)
msg.hostinfo = {}
local pos, err = bin.unpack(">I", msg.data)
pos, msg.hostinfo.hostname = Util.parseString(msg.data, pos)
pos, msg.hostinfo.ostype = Util.parseString(msg.data, pos)
pos, msg.hostinfo.osver = Util.parseString(msg.data, pos)
pos, msg.hostinfo.hostid = Util.parseString(msg.data, pos)
pos, msg.hostinfo.hostid = Util.parseString(msg.data, pos)
return msg
end,
__tostring = function(self)
return tostring(self.frag_header) .. tostring(self.header) .. tostring(self.data or "")
end,
end,
}
NDMP.Message.ConfigGetFsInfo = {
@@ -194,16 +194,16 @@ NDMP.Message.ConfigGetFsInfo = {
o.header.msg = NDMP.MessageType.CONFIG_GET_FS_INFO
setmetatable(o, self)
self.__index = self
return o
return o
end,
parse = function(data)
local msg = NDMP.Message.ConfigGetFsInfo:new()
msg.frag_header = NDMP.FragmentHeader.parse(data)
data = data:sub(NDMP.FragmentHeader.size + 1)
msg.header = NDMP.Header.parse(data)
msg.data = data:sub(NDMP.Header.size + 1)
local pos, err, count = bin.unpack(">II", msg.data)
for i=1, count do
local item = {}
@@ -217,19 +217,19 @@ NDMP.Message.ConfigGetFsInfo = {
pos, item.total_inodes = bin.unpack(">L", msg.data, pos)
pos, item.used_inodes = bin.unpack(">L", msg.data, pos)
pos, item.fs_env = Util.parseString(msg.data, pos)
pos, item.fs_status = Util.parseString(msg.data, pos)
pos, item.fs_status = Util.parseString(msg.data, pos)
table.insert(msg.fsinfo, item)
end
return msg
end,
__tostring = function(self)
return tostring(self.frag_header) .. tostring(self.header) .. tostring(self.data or "")
end,
end,
}
NDMP.Message.UnhandledMessage = {
new = function(self)
local o = {
frag_header = NDMP.FragmentHeader:new(),
@@ -238,9 +238,9 @@ NDMP.Message.UnhandledMessage = {
}
setmetatable(o, self)
self.__index = self
return o
return o
end,
parse = function(data)
local msg = NDMP.Message.ConfigGetFsInfo:new()
msg.frag_header = NDMP.FragmentHeader.parse(data)
@@ -249,22 +249,22 @@ NDMP.Message.UnhandledMessage = {
msg.data = data:sub(NDMP.Header.size + 1)
return msg
end,
__tostring = function(self)
return tostring(self.frag_header) .. tostring(self.header) .. tostring(self.data or "")
end
}
Util = {
parseString = function(data, pos)
local pos, str = bin.unpack(">a", data, pos)
local pad = ( 4 - ( #str % 4 ) ~= 4 ) and 4 - ( #str % 4 ) or 0
return pos + pad, str
end,
}
NDMP.TypeToMessage = {
@@ -275,7 +275,7 @@ NDMP.TypeToMessage = {
-- Handles the communication with the NDMP service
Comm = {
-- Creates new Comm instance
-- @param host table as received by the action method
-- @param port table as receuved by the action method
@@ -290,9 +290,9 @@ Comm = {
}
setmetatable(o, self)
self.__index = self
return o
return o
end,
-- Connects to the NDMP server
-- @return status true on success, false on failure
connect = function(self)
@@ -300,11 +300,11 @@ Comm = {
self.socket:set_timeout(10000)
return self.socket:connect(self.host, self.port)
end,
-- Receives a message from the server
-- @return status true on success, false on failure
-- @return msg NDMP message when a parser exists, otherwise nil
sock_recv = function(self)
sock_recv = function(self)
local status, frag_data = self.socket:receive_buf(match.numbytes(4), true)
if ( not(status) ) then
return false, "Failed to read NDMP 4-byte fragment header"
@@ -321,20 +321,20 @@ Comm = {
if ( not(status) ) then
return false, "Failed to read NDMP data"
end
if ( NDMP.TypeToMessage[header.msg] ) then
return true, NDMP.TypeToMessage[header.msg].parse(frag_data .. header_data .. data)
end
return true, NDMP.Message.UnhandledMessage.parse(frag_data .. header_data .. data)
end,
recv = function(self)
if ( #self.in_queue > 0 ) then
return true, table.remove(self.in_queue, 1)
end
return self:sock_recv()
end,
-- Sends a message to the server
-- @param msg NDMP message
-- @return status true on success, false on failure
@@ -344,8 +344,8 @@ Comm = {
msg.header.seq = self.seq
return self.socket:send(tostring(msg))
end,
exch = function(self, msg)
local status, err = self:send(msg)
if ( not(status) ) then
@@ -363,50 +363,50 @@ Comm = {
local reply
status, reply = self:sock_recv()
if ( not(status) ) then
return false, "Failed to receive msg from server"
return false, "Failed to receive msg from server"
elseif ( reply and reply.header and reply.header.reply_seq == s_seq ) then
return true, reply
else
table.insert(self.in_queue, reply)
end
end
end
end,
close = function(self) return self.socket:close() end,
}
Helper = {
new = function(self, host, port)
local o = { comm = Comm:new(host, port) }
setmetatable(o, self)
self.__index = self
return o
return o
end,
connect = function(self)
return self.comm:connect()
end,
getFsInfo = function(self)
return self.comm:exch(NDMP.Message.ConfigGetFsInfo:new())
end,
getHostInfo = function(self)
return self.comm:exch(NDMP.Message.ConfigGetHostInfo:new())
end,
getServerInfo = function(self)
return self.comm:exch(NDMP.Message.ConfigGetServerInfo:new())
end,
close = function(self)
return self.comm:close()
end
}
return _ENV;

View File

@@ -1,6 +1,6 @@
---
-- Creates and parses NetBIOS traffic. The primary use for this is to send
-- NetBIOS name requests.
-- NetBIOS name requests.
--
-- @author Ron Bowes <ron@skullsecurity.net>
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
@@ -27,15 +27,15 @@ types = {
-- pass case-sensitive data in a case-insensitive way)
--
-- There are two levels of encoding performed:
-- * L1: Pad the string to 16 characters withs spaces (or NULLs if it's the
-- * L1: Pad the string to 16 characters withs spaces (or NULLs if it's the
-- wildcard "*") and replace each byte with two bytes representing each
-- of its nibbles, plus 0x41.
-- of its nibbles, plus 0x41.
-- * L2: Prepend the length to the string, and to each substring in the scope
-- (separated by periods).
--@param name The name that will be encoded (eg. "TEST1").
-- (separated by periods).
--@param name The name that will be encoded (eg. "TEST1").
--@param scope [optional] The scope to encode it with. I've never seen scopes used
-- in the real world (eg, "insecure.org").
--@return The L2-encoded name and scope
-- in the real world (eg, "insecure.org").
--@return The L2-encoded name and scope
-- (eg. "\x20FEEFFDFEDBCACACACACACACACACAAA\x08insecure\x03org")
function name_encode(name, scope)
@@ -65,7 +65,7 @@ function name_encode(name, scope)
L1_encoded = L1_encoded .. string.char(bit.rshift(bit.band(b, 0x0F), 0) + 0x41)
end
-- Do the L2 encoding
-- Do the L2 encoding
local L2_encoded = string.char(32) .. L1_encoded
if scope ~= nil then
@@ -84,7 +84,7 @@ end
--- Does the exact opposite of name_encode. Converts an encoded name to
-- the string representation. If the encoding is invalid, it will still attempt
-- to decode the string as best as possible.
-- to decode the string as best as possible.
--@param encoded_name The L2-encoded name
--@return the decoded name and the scope. The name will still be padded, and the
-- scope will never be nil (empty string is returned if no scope is present)
@@ -124,11 +124,11 @@ function name_decode(encoded_name)
end
--- Sends out a UDP probe on port 137 to get a human-readable list of names the
-- the system is using.
--@param host The IP or hostname to check.
--@param prefix [optional] The prefix to put on each line when it's returned.
--@return (status, result) If status is true, the result is a human-readable
-- list of names. Otherwise, result is an error message.
-- the system is using.
--@param host The IP or hostname to check.
--@param prefix [optional] The prefix to put on each line when it's returned.
--@return (status, result) If status is true, the result is a human-readable
-- list of names. Otherwise, result is an error message.
function get_names(host, prefix)
local status, names, statistics = do_nbstat(host)
@@ -151,11 +151,11 @@ function get_names(host, prefix)
end
--- Sends out a UDP probe on port 137 to get the server's name (that is, the
-- entry in its NBSTAT table with a 0x20 suffix).
--@param host The IP or hostname of the server.
--@param names [optional] The names to use, from <code>do_nbstat</code>.
--@return (status, result) If status is true, the result is the NetBIOS name.
-- otherwise, result is an error message.
-- entry in its NBSTAT table with a 0x20 suffix).
--@param host The IP or hostname of the server.
--@param names [optional] The names to use, from <code>do_nbstat</code>.
--@return (status, result) If status is true, the result is the NetBIOS name.
-- otherwise, result is an error message.
function get_server_name(host, names)
local status
@@ -163,7 +163,7 @@ function get_server_name(host, names)
if names == nil then
status, names = do_nbstat(host)
if(status == false) then
return false, names
end
@@ -178,13 +178,13 @@ function get_server_name(host, names)
return false, "Couldn't find NetBIOS server name"
end
--- Sends out a UDP probe on port 137 to get the user's name (that is, the
--- Sends out a UDP probe on port 137 to get the user's name (that is, the
-- entry in its NBSTAT table with a 0x03 suffix, that isn't the same as
-- the server's name. If the username can't be determined, which is frequently
-- the case, nil is returned.
--@param host The IP or hostname of the server.
--@param names [optional] The names to use, from <code>do_nbstat</code>.
--@return (status, result) If status is true, the result is the NetBIOS name or nil.
-- the case, nil is returned.
--@param host The IP or hostname of the server.
--@param names [optional] The names to use, from <code>do_nbstat</code>.
--@return (status, result) If status is true, the result is the NetBIOS name or nil.
-- otherwise, result is an error message.
function get_user_name(host, names)
@@ -196,7 +196,7 @@ function get_user_name(host, names)
if(names == nil) then
status, names = do_nbstat(host)
if(status == false) then
return false, names
end
@@ -207,15 +207,15 @@ function get_user_name(host, names)
return true, names[i]['name']
end
end
return true, nil
end
--- This is the function that actually handles the UDP query to retrieve
-- the NBSTAT information. We make use of the Nmap registry here, so if another
-- script has already performed a nbstat query, the result can be re-used.
-- script has already performed a nbstat query, the result can be re-used.
--
-- The NetBIOS request's header looks like this:
--<code>
@@ -231,7 +231,7 @@ end
--</code>
--
-- In this case, the TRN_ID is a constant (0x1337, what else?), the flags
-- are 0, and we have one question. All fields are network byte order.
-- are 0, and we have one question. All fields are network byte order.
--
-- The body of the packet is a list of names to check for in the following
-- format:
@@ -254,10 +254,10 @@ end
-- * (2 bytes) flags
-- * (variable) statistics (usually mac address)
--
--@param host The IP or hostname of the system.
--@param host The IP or hostname of the system.
--@return (status, names, statistics) If status is true, then the servers names are
-- returned as a table containing 'name', 'suffix', and 'flags'.
-- Otherwise, names is an error message and statistics is undefined.
-- returned as a table containing 'name', 'suffix', and 'flags'.
-- Otherwise, names is an error message and statistics is undefined.
function do_nbstat(host)
local status, err
@@ -288,7 +288,7 @@ function do_nbstat(host)
end
-- Create the query header
local query = bin.pack(">SSSSSS",
local query = bin.pack(">SSSSSS",
0x1337, -- Transaction id
0x0000, -- Flags
1, -- Questions
@@ -297,7 +297,7 @@ function do_nbstat(host)
0 -- Extra
)
query = query .. bin.pack(">zSS",
query = query .. bin.pack(">zSS",
encoded_name, -- Encoded name
0x0021, -- Query type (0x21 = NBSTAT)
0x0001 -- Class = IN
@@ -364,8 +364,8 @@ function do_nbstat(host)
for i = 1, name_count do
local name, suffix, flags
-- Instead of reading the 16-byte name and pulling off the suffix,
-- we read the first 15 bytes and then the 1-byte suffix.
-- Instead of reading the 16-byte name and pulling off the suffix,
-- we read the first 15 bytes and then the 1-byte suffix.
pos, name, suffix, flags = bin.unpack(">A15CS", result, pos)
name = string.gsub(name, "[ ]*$", "")
@@ -403,14 +403,14 @@ function nbquery(host, nbname, options)
options.host = host.ip
options.flags = options.flags or ( options.multiple and 0x0110 )
options.id = math.random(0xFFFF)
-- encode and chop off the leading byte, as the dns library takes care of
-- specifying the length
local encoded_name = name_encode(nbname):sub(2)
local status, response = dns.query( encoded_name, options )
if ( not(status) ) then return false, "ERROR: nbquery failed" end
local results = {}
-- discard any additional responses
if ( options.multiple and #response > 0 ) then
@@ -426,10 +426,10 @@ function nbquery(host, nbname, options)
else
local dname = string.char(#response.answers[1].dname) .. response.answers[1].dname
return true, { { peer = host.ip, name = name_decode(dname) } }
end
end
end
---Convert the 16-bit flags field to a string.
---Convert the 16-bit flags field to a string.
--@param flags The 16-bit flags field
--@return A string representing the flags
function flags_to_string(flags)

View File

@@ -17,7 +17,7 @@
-- - A helper class that provides easy access to the rest of the library
--
-- o DominoSocket
-- - This is a copy of the DB2Socket class which provides fundamental
-- - This is a copy of the DB2Socket class which provides fundamental
-- buffering
--
--
@@ -50,11 +50,11 @@ _ENV = stdnse.module("nrpc", stdnse.seeall)
-- The Domino Packet
DominoPacket = {
--- Creates a new DominoPacket instance
--
-- @param data string containing the packet data
-- @return a new DominoPacket instance
-- @return a new DominoPacket instance
new = function( self, data )
local o = {}
setmetatable(o, self)
@@ -62,7 +62,7 @@ DominoPacket = {
o.data = data
return o
end,
--- Reads a packet from the DominoSocket
--
-- @param domsock DominoSocket connected to the server
@@ -79,12 +79,12 @@ DominoPacket = {
__tostring = function(self)
return bin.pack("<SA", #self.data, self.data )
end,
}
DominoSocket =
{
{
new = function(self)
local o = {}
setmetatable(o, self)
@@ -105,7 +105,7 @@ DominoSocket =
self.Socket:set_timeout(5000)
return self.Socket:connect( hostid, port, protocol )
end,
--- Closes an open connection.
--
-- @return Status (true or false).
@@ -113,7 +113,7 @@ DominoSocket =
close = function( self )
return self.Socket:close()
end,
--- Opposed to the <code>socket:receive_bytes</code> function, that returns
-- at least x bytes, this function returns the amount of bytes requested.
--
@@ -123,9 +123,9 @@ DominoSocket =
-- err containing error message if status is false
recv = function( self, count )
local status, data
self.Buffer = self.Buffer or ""
if ( #self.Buffer < count ) then
status, data = self.Socket:receive_bytes( count - #self.Buffer )
if ( not(status) or #data < count - #self.Buffer ) then
@@ -133,13 +133,13 @@ DominoSocket =
end
self.Buffer = self.Buffer .. data
end
data = self.Buffer:sub( 1, count )
self.Buffer = self.Buffer:sub( count + 1)
return true, data
return true, data
end,
--- Sends data over the socket
--
-- @return Status (true or false).
@@ -150,7 +150,7 @@ DominoSocket =
}
Helper = {
--- Creates a new Helper instance
--
-- @param host table as recieved by the script action method
@@ -169,13 +169,13 @@ Helper = {
--
-- @return status true on success, false on failure
-- @return err error message if status is false
connect = function( self )
connect = function( self )
if( not( self.domsock:connect( self.host.ip, self.port.number, "tcp" ) ) ) then
return false, ("ERROR: Failed to connect to Domino server %s:%d\n"):format(self.host, self.port)
end
return true
end,
--- Disconnects from the Lotus Domino Server
--
-- @return status true on success, false on failure
@@ -190,14 +190,14 @@ Helper = {
-- @return status true on success false on failure
-- @return domino_id if it exists and status is true
-- err if status is false
isValidUser = function( self, username )
isValidUser = function( self, username )
local data = bin.pack("H", "00001e00000001000080000007320000700104020000fb2b2d00281f1e000000124c010000000000")
local status, id_data
local data_len, pos, total_len, pkt_type, valid_user
self.domsock:send( tostring(DominoPacket:new( data )) )
data = DominoPacket:new():read( self.domsock )
data = bin.pack("HCHAH", "0100320002004f000100000500000900", #username + 1, "000000000000000000000000000000000028245573657273290000", username, "00")
self.domsock:send( tostring(DominoPacket:new( data ) ) )
status, id_data = DominoPacket:new():read( self.domsock )
@@ -205,7 +205,7 @@ Helper = {
pos, pkt_type = bin.unpack("C", id_data, 3)
pos, valid_user = bin.unpack("C", id_data, 11)
pos, total_len = bin.unpack("<S", id_data, 13)
if ( pkt_type == 0x16 ) then
if ( valid_user == 0x19 ) then
return true
@@ -213,7 +213,7 @@ Helper = {
return false
end
end
if ( pkt_type ~= 0x7e ) then
return false, "Failed to retrieve ID file"
end
@@ -222,10 +222,10 @@ Helper = {
id_data = id_data:sub(33)
id_data = id_data .. data:sub(11, total_len - #id_data + 11)
return true, id_data
end,
}
return _ENV;

View File

@@ -1,9 +1,9 @@
---
-- Debugging functions for Nmap scripts.
-- Debugging functions for Nmap scripts.
--
-- This module contains various handy functions for debugging. These should
-- never be used for actual results, only during testing.
--
-- never be used for actual results, only during testing.
--
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
local coroutine = require "coroutine"
@@ -18,13 +18,13 @@ _ENV = stdnse.module("nsedebug", stdnse.seeall)
local EMPTY = {}; -- Empty constant table
---
-- Converts an arbitrary data type into a string. Will recursively convert
-- tables. This can be very useful for debugging.
-- Converts an arbitrary data type into a string. Will recursively convert
-- tables. This can be very useful for debugging.
--
--@param data The data to convert.
--@param data The data to convert.
--@param indent (optional) The number of times to indent the line. Default
-- is 0.
--@return A string representation of a data, will be one or more full lines.
-- is 0.
--@return A string representation of a data, will be one or more full lines.
function tostr(data, indent)
local str
@@ -108,7 +108,7 @@ function print_hex(str)
end
io.write(string.format("%c", ch))
end
io.write("\n")
end
@@ -117,7 +117,7 @@ function print_hex(str)
end
---Print out a stacktrace. The stacktrace will naturally include this function call.
---Print out a stacktrace. The stacktrace will naturally include this function call.
function print_stack()
local thread = coroutine.running()
local trace = debug.traceback(thread);

View File

@@ -39,7 +39,7 @@ if pcall(require,'openssl') then
HAVE_SSL = true
end
--- A Session class holds connection and interaction with the server
--- A Session class holds connection and interaction with the server
Session = {
--- Creates a new session object

View File

@@ -114,7 +114,7 @@ OSPF = {
Hello = {
new = function(self)
local o = {
local o = {
header = OSPF.Header:new(OSPF.Message.HELLO),
options = 0x02,
prio = 0,
@@ -250,7 +250,7 @@ OSPF = {
if ( self.more ) then flags = flags + 2 end
if ( self.master) then flags= flags + 1 end
local data = bin.pack(">SCCI", self.mtu, self.options, flags, self.sequence)
local data = bin.pack(">SCCI", self.mtu, self.options, flags, self.sequence)
self.header:setLength(#data)
return tostring(self.header) .. data
end
@@ -276,7 +276,7 @@ OSPF = {
return desc
end
return desc
return desc
end,
},
@@ -291,9 +291,9 @@ OSPF = {
return OSPF.DBDescription.parse(data)
end
return
end,
end,
}
}
}
return _ENV;

View File

@@ -625,14 +625,14 @@ function Packet:u32(index)
return u32(self.buf, index)
end
--- Return part of the packet contents as a byte string.
-- @param index The beginning of the part of the packet to extract. The index
-- @param index The beginning of the part of the packet to extract. The index
-- is 0-based. If omitted the default value is 0 (begining of the string)
-- @param length The length of the part of the packet to extract. If omitted
-- @param length The length of the part of the packet to extract. If omitted
-- the remaining contents from index to the end of the string are returned.
-- @return A string.
function Packet:raw(index, length)
if not index then index = 0 end
if not length then length = #self.buf-index end
if not length then length = #self.buf-index end
return string.char(string.byte(self.buf, index+1, index+1+length-1))
end
@@ -753,7 +753,7 @@ end
-- @param id packet ID.
function Packet:ip_set_id(id)
self:set_u16(self.ip_offset + 4, id)
self.ip_id = id
self.ip_id = id
end
--- Set the TTL.
-- @param ttl TTL.
@@ -1125,7 +1125,7 @@ function Packet:udp_parse(force_continue)
end
self.udp_len = self:u16(self.udp_offset + 4)
self.udp_sum = self:u16(self.udp_offset + 6)
return true
end

View File

@@ -21,8 +21,8 @@ local table = require "table"
_ENV = stdnse.module("pgsql", stdnse.seeall)
-- Version 0.3
-- Created 02/05/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 02/20/2010 - v0.2 - added detectVersion to automaticaly detect and return
-- Created 02/05/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 02/20/2010 - v0.2 - added detectVersion to automaticaly detect and return
-- the correct version class
-- Revised 03/04/2010 - v0.3 - added support for trust authentication method
@@ -46,7 +46,7 @@ AuthenticationType = {
-- Version 2 of the protocol
v2 =
{
--- Pad a string with zeroes
--
-- @param str string containing the string to be padded
@@ -63,9 +63,9 @@ v2 =
end
return str
end,
messageDecoder = {
--- Decodes an Auth Request packet
--
-- @param data string containing raw data recieved from socket
@@ -105,7 +105,7 @@ v2 =
-- @param pos number containing the offset into the data buffer
-- @return pos number containing the offset after decoding
-- @return response table containing zero or more of the following <code>error.severity</code>,
-- <code>error.code</code>, <code>error.message</code>, <code>error.file</code>,
-- <code>error.code</code>, <code>error.message</code>, <code>error.file</code>,
-- <code>error.line</code> and <code>error.routine</code>
[MessageType.Error] = function( data, len, pos )
local tmp = data:sub(pos, pos + len - 4)
@@ -143,8 +143,8 @@ v2 =
end
return -1, "Decoding failed"
end,
--- Reads a packet and handles additional socket reads to retrieve remaining data
--
-- @param socket socket already connected to the pgsql server
@@ -159,7 +159,7 @@ v2 =
local tmp = ""
local ptype, len
local catch = function() socket:close() stdnse.print_debug("processResponse(): failed") end
local catch = function() socket:close() stdnse.print_debug("processResponse(): failed") end
local try = nmap.new_try(catch)
if ( data == nil or data:len() == 0 ) then
@@ -167,7 +167,7 @@ v2 =
end
return data
end,
--- Sends a startup message to the server containing the username and database to connect to
--
-- @param socket socket already connected to the pgsql server
@@ -204,9 +204,9 @@ v2 =
return true, response
end,
--- Attempts to authenticate to the pgsql server
-- Supports plain-text and MD5 authentication
-- Supports plain-text and MD5 authentication
--
-- @param socket socket already connected to the pgsql server
-- @param params table containing any additional parameters <code>authtype</code>, <code>version</code>
@@ -215,10 +215,10 @@ v2 =
-- @param salt string containing the crypthographic salt value
-- @return status true on success, false on failure
-- @return result table containing parameter status information,
-- result string containing an error message if login fails
-- result string containing an error message if login fails
loginRequest = function ( 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 response = {}
local status, data, len, pos, tmp
@@ -251,7 +251,7 @@ v2 =
return true, response
end,
}
-- Version 3 of the protocol
@@ -313,7 +313,7 @@ v3 =
-- @param pos number containing the offset into the data buffer
-- @return pos number containing the offset after decoding
-- @return response table containing zero or more of the following <code>error.severity</code>,
-- <code>error.code</code>, <code>error.message</code>, <code>error.file</code>,
-- <code>error.code</code>, <code>error.message</code>, <code>error.file</code>,
-- <code>error.line</code> and <code>error.routine</code>
[MessageType.Error] = function( data, len, pos )
local tmp = data:sub(pos, pos + len - 4)
@@ -353,7 +353,7 @@ v3 =
-- error string containing error message if pos is -1
[MessageType.BackendKeyData] = function( data, len, pos )
local response = {}
if len ~= 12 then
return -1, "ERROR: Invalid BackendKeyData packet"
end
@@ -376,12 +376,12 @@ v3 =
if len ~= 5 then
return -1, "ERROR: Invalid ReadyForQuery packet"
end
pos, response.status = bin.unpack("C", data, pos )
return pos, response
end,
},
--- Reads a packet and handles additional socket reads to retrieve remaining data
--
-- @param socket socket already connected to the pgsql server
@@ -397,7 +397,7 @@ v3 =
local ptype, len
local header
local catch = function() socket:close() stdnse.print_debug("processResponse(): failed") end
local catch = function() socket:close() stdnse.print_debug("processResponse(): failed") end
local try = nmap.new_try(catch)
if ( data:len() - pos < 5 ) then
@@ -419,7 +419,7 @@ v3 =
end
return data
end,
--- Decodes the postgres header
--
-- @param data string containing the server response
@@ -428,11 +428,11 @@ v3 =
-- @return header table containing <code>type</code> and <code>len</code>
decodeHeader = function(data, pos)
local ptype, len
pos, ptype, len = bin.unpack("C>I", data, pos)
return pos, { ['type'] = ptype, ['len'] = len }
end,
--- Process the server response
--
-- @param data string containing the server response
@@ -444,7 +444,7 @@ v3 =
local ptype, len, status, response
local pos = pos or 1
local header
pos, header = v3.decodeHeader( data, pos )
if v3.messageDecoder[header.type] then
@@ -460,9 +460,9 @@ v3 =
end
return -1, "Decoding failed"
end,
--- Attempts to authenticate to the pgsql server
-- Supports plain-text and MD5 authentication
-- Supports plain-text and MD5 authentication
--
-- @param socket socket already connected to the pgsql server
-- @param params table containing any additional parameters <code>authtype</code>, <code>version</code>
@@ -471,10 +471,10 @@ v3 =
-- @param salt string containing the crypthographic salt value
-- @return status true on success, false on failure
-- @return result table containing parameter status information,
-- result string containing an error message if login fails
-- result string containing an error message if login fails
loginRequest = function ( 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 response, header = {}, {}
local status, data, len, tmp, _
@@ -516,7 +516,7 @@ v3 =
return true, response
end,
--- Sends a startup message to the server containing the username and database to connect to
--
-- @param socket socket already connected to the pgsql server
@@ -541,7 +541,7 @@ v3 =
if ( not(status) ) then
return false, "sendStartup failed"
end
if ( not(status) or data:match("^EF") ) then
return false, "Incorrect version"
end
@@ -559,7 +559,7 @@ v3 =
--- Sends a packet requesting SSL communication to be activated
--
--
-- @param socket socket already connected to the pgsql server
-- @return boolean true if request was accepted, false if request was denied
function requestSSL(socket)
@@ -567,14 +567,14 @@ function requestSSL(socket)
local ssl_req_code = 80877103
local data = bin.pack( ">I>I", 8, ssl_req_code)
local status, response
socket:send(data)
status, response = socket:receive_bytes(1)
if ( not(status) ) then
return false
end
if ( response == 'S' ) then
return true
end
@@ -617,11 +617,11 @@ function detectVersion(host, port)
socket:connect(host, port)
status, response = v3.sendStartup(socket, "versionprobe", "versionprobe")
socket:close()
if ( not(status) and response == 'Incorrect version' ) then
if ( not(status) and response == 'Incorrect version' ) then
return v2
end
return v3
end

View File

@@ -44,10 +44,10 @@ function login_user(socket, user, pw)
local status, line = socket:receive_lines(1)
if not stat(line) then return false, err.user_error end
socket:send("PASS " .. pw .. "\r\n")
status, line = socket:receive_lines(1)
if stat(line) then return true, err.none
if stat(line) then return true, err.none
else return false, err.pwError
end
end
@@ -61,15 +61,15 @@ end
-- @return Status (true or false).
-- @return Error code if status is false.
function login_sasl_plain(socket, user, pw)
local auth64 = base64.enc(user .. "\0" .. user .. "\0" .. pw)
socket:send("AUTH PLAIN " .. auth64 .. "\r\n")
local status, line = socket:receive_lines(1)
if stat(line) then
if stat(line) then
return true, err.none
else
else
return false, err.pwError
end
end
@@ -84,28 +84,28 @@ end
function login_sasl_login(socket, user, pw)
local user64 = base64.enc(user)
local pw64 = base64.enc(pw)
socket:send("AUTH LOGIN\r\n")
local status, line = socket:receive_lines(1)
if not base64.dec(string.sub(line, 3)) == "User Name:" then
return false, err.userError
if not base64.dec(string.sub(line, 3)) == "User Name:" then
return false, err.userError
end
socket:send(user64)
local status, line = socket:receive_lines(1)
if not base64.dec(string.sub(line, 3)) == "Password:" then
if not base64.dec(string.sub(line, 3)) == "Password:" then
return false, err.userError
end
socket:send(pw64)
local status, line = socket:receive_lines(1)
if stat(line) then
return true, err.none
else
@@ -126,10 +126,10 @@ function login_apop(socket, user, pw, challenge)
local apStr = stdnse.tohex(openssl.md5(challenge .. pw))
socket:send(("APOP %s %s\r\n"):format(user, apStr))
local status, line = socket:receive_lines(1)
if (stat(line)) then
if (stat(line)) then
return true, err.none
else
return false, err.pwError
@@ -153,17 +153,17 @@ function capabilities(host, port)
if not stat(first_line) then
return nil, "No Response"
end
local capas = {}
if string.find(first_line, "<[%p%w]+>") then
capas.APOP = {}
end
local status = socket:send("CAPA\r\n")
if( not(status) ) then
return nil, "Failed to send"
end
status, line = socket:receive_buf("%.", false)
if( not(status) ) then
return nil, "Failed to receive"
@@ -171,11 +171,11 @@ function capabilities(host, port)
socket:close()
local lines = stdnse.strsplit("\r\n",line)
if not stat(table.remove(lines,1)) then
if not stat(table.remove(lines,1)) then
capas.capa = false
return capas
end
end
for _, line in ipairs(lines) do
if ( line and #line>0 ) then
local capability = line:sub(line:find("[%w-]+"))
@@ -187,7 +187,7 @@ function capabilities(host, port)
end
end
end
return capas
end
@@ -201,20 +201,20 @@ end
function login_sasl_crammd5(socket, user, pw)
socket:send("AUTH CRAM-MD5\r\n")
local status, line = socket:receive_lines(1)
local challenge = base64.dec(string.sub(line, 3))
local digest = stdnse.tohex(openssl.hmac('md5', pw, challenge))
local authStr = base64.enc(user .. " " .. digest)
socket:send(authStr .. "\r\n")
local status, line = socket:receive_lines(1)
if stat(line) then
if stat(line) then
return true, err.none
else
else
return false, err.pwError
end
end

View File

@@ -1,7 +1,7 @@
--- A minimalistic PPPoE (Point-to-point protocol over Ethernet)
-- library, implementing basic support for PPPoE
-- Discovery and Configuration requests. The PPPoE protocol is ethernet based
-- and hence does not use any IPs or port numbers.
-- and hence does not use any IPs or port numbers.
--
-- The library contains a number of classes to support packet creation,
-- parsing and sending/receiving responses. The classes are:
@@ -33,14 +33,14 @@ _ENV = stdnse.module("pppoe", stdnse.seeall)
EtherType = {
PPPOE_DISCOVERY = 0x8863,
PPPOE_SESSION = 0x8864,
PPPOE_SESSION = 0x8864,
}
-- A Class to handle the Link Control Protocol LCP
LCP = {
ConfigOption = {
RESERVED = 0,
MRU = 1,
AUTH_PROTO = 3,
@@ -51,7 +51,7 @@ LCP = {
-- Value has already been encoded, treat it as a byte stream
RAW = -1,
-- Creates a new config option
-- @param option number containing the configuration option
-- @param value containing the configuration option value
@@ -67,7 +67,7 @@ LCP = {
self.__index = self
return o
end,
-- Parses a byte stream and builds a new instance of the ConfigOption
-- class
-- @param data string containing raw bytes to parse
@@ -76,14 +76,14 @@ LCP = {
local opt, pos, len = {}, 1, 0
pos, opt.option, len = bin.unpack("CC", data, pos)
pos, opt.raw = bin.unpack("A" .. ( len - 2 ), data, pos)
-- MRU
if ( 1 == opt.option ) then
opt.value = select(2, bin.unpack(">S", opt.raw))
end
return LCP.ConfigOption:new(opt.option, opt.value, opt.raw)
end,
-- Converts the class instance to string
-- @return string containing the raw config option
__tostring = function(self)
@@ -97,10 +97,10 @@ LCP = {
end
end,
},
-- A class to hold multiple ordered config options
ConfigOptions = {
new = function(self, options)
local o = {
options = options or {},
@@ -109,13 +109,13 @@ LCP = {
self.__index = self
return o
end,
-- Adds a new config option to the table
-- @param option instance of ConfigOption
add = function(self, option)
table.insert(self.options, option)
end,
-- Gets a config option by ID
-- @param opt number containing the configuration option to retrieve
-- @return v instance of ConfigOption
@@ -126,7 +126,7 @@ LCP = {
end
end
end,
-- Returns all config options in an ordered table
-- @return tab table containing all configuration options
getTable = function(self)
@@ -136,8 +136,8 @@ LCP = {
end
return tab
end,
-- Parses a byte stream and builds a new instance of the ConfigOptions
-- class
-- @param data string containing raw bytes to parse
@@ -148,13 +148,13 @@ LCP = {
repeat
pos, opt, len = bin.unpack(">CC", data, pos)
if ( 0 == opt ) then break end
if ( 0 == opt ) then break end
pos, opt_val = bin.unpack("A"..len, data, (pos - 2))
options:add(LCP.ConfigOption.parse(opt_val))
until( pos == #data )
return options
end,
-- Converts the class instance to string
-- @return string containing the raw config option
__tostring = function(self)
@@ -164,9 +164,9 @@ LCP = {
end
return str
end,
},
ConfigOptionName = {
[0] = "Reserved",
[1] = "Maximum receive unit",
@@ -176,7 +176,7 @@ LCP = {
[7] = "Protocol field compression",
[8] = "Address and control field compression",
},
Code = {
CONFIG_REQUEST = 1,
CONFIG_ACK = 2,
@@ -184,10 +184,10 @@ LCP = {
TERMINATE_REQUEST = 5,
TERMINATE_ACK = 6,
},
-- The LCP Header
Header = {
-- Creates a new instance of the LCP header
-- @param code number containing the LCP code of the request
-- @param identifier number containing the LCP identifier
@@ -218,11 +218,11 @@ LCP = {
__tostring = function(self)
return bin.pack(">CCS", self.code, self.identifier, self.length)
end,
},
ConfigRequest = {
-- Creates a new instance of the ConfigRequest class
-- @param identifier number containing the LCP identifier
-- @param options table of <code>LCP.ConfigOption</code> options
@@ -236,7 +236,7 @@ LCP = {
self.__index = self
return o
end,
-- Parses a byte stream and builds a new instance of the ConfigRequest
-- class
-- @param data string containing raw bytes to parse
@@ -247,7 +247,7 @@ LCP = {
req.options = LCP.ConfigOptions.parse(data:sub(#tostring(req.header) + 1))
return req
end,
-- Converts the class instance to string
-- @return string containing the raw config option
__tostring = function(self)
@@ -255,9 +255,9 @@ LCP = {
return tostring(self.header) .. tostring(self.options)
end,
},
ConfigNak = {
-- Creates a new instance of the ConfigNak class
-- @param identifier number containing the LCP identifier
-- @param options table of <code>LCP.ConfigOption</code> options
@@ -271,7 +271,7 @@ LCP = {
self.__index = self
return o
end,
-- Converts the class instance to string
-- @return string containing the raw config option
__tostring = function(self)
@@ -279,9 +279,9 @@ LCP = {
return tostring(self.header) .. tostring(self.options)
end,
},
ConfigAck = {
-- Creates a new instance of the ConfigAck class
-- @param identifier number containing the LCP identifier
-- @param options table of <code>LCP.ConfigOption</code> options
@@ -295,7 +295,7 @@ LCP = {
self.__index = self
return o
end,
-- Parses a byte stream and builds a new instance of the ConfigAck class
-- @param data string containing raw bytes to parse
-- @return o instance of ConfigRequest
@@ -305,21 +305,21 @@ LCP = {
ack.options = LCP.ConfigOptions.parse(data:sub(#tostring(ack.header) + 1))
return ack
end,
-- Converts the class instance to string
-- @return string containing the raw config option
__tostring = function(self)
self.header.length = 4 + #tostring(self.options)
return tostring(self.header) .. tostring(self.options)
end,
},
TerminateRequest = {
-- Creates a new instance of the TerminateRequest class
-- @param identifier number containing the LCP identifier
-- @return o instance of ConfigNak
-- @return o instance of ConfigNak
new = function(self, identifier, data)
local o = {
header = LCP.Header:new(LCP.Code.TERMINATE_REQUEST, identifier),
@@ -329,7 +329,7 @@ LCP = {
self.__index = self
return o
end,
-- Converts the class instance to string
-- @return string containing the raw config option
__tostring = function(self)
@@ -337,22 +337,22 @@ LCP = {
return tostring(self.header) .. self.data
end,
}
}
-- The PPPoE class
PPPoE = {
-- Supported PPPoE codes (requests/responses)
Code = {
SESSION_DATA = 0x00,
PADO = 0x07,
PADI = 0x09,
PADR = 0x19,
PADS = 0x65,
PADT = 0xa7,
PADS = 0x65,
PADT = 0xa7,
},
-- Support PPPoE Tag types
TagType = {
SERVICE_NAME = 0x0101,
@@ -360,7 +360,7 @@ PPPoE = {
HOST_UNIQUE = 0x0103,
AC_COOKIE = 0x0104,
},
-- Table used to convert table IDs to Names
TagName = {
[0x0101] = "Service-Name",
@@ -368,14 +368,14 @@ PPPoE = {
[0x0103] = "Host-Uniq",
[0x0104] = "AC-Cookie",
},
Header = {
-- Creates a new instance of the PPPoE header class
-- @param code number containing the PPPoE code
-- @param session number containing the PPPoE session
-- @return o instance of Header
-- @return o instance of Header
new = function(self, code, session)
local o = {
version = 1,
@@ -388,7 +388,7 @@ PPPoE = {
self.__index = self
return o
end,
-- Parses a byte stream and builds a new instance of the class
-- @param data string containing raw bytes to parse
-- @return o instance of Header
@@ -397,56 +397,56 @@ PPPoE = {
local header = PPPoE.Header:new()
pos, vertyp, header.code, header.session, header.length = bin.unpack(">CCSS", data)
header.version = bit.rshift(vertyp,4)
header.type = bit.band(vertyp, 0x0F)
header.type = bit.band(vertyp, 0x0F)
return header
end,
-- Converts the instance to string
-- @return string containing the raw config option
__tostring = function(self)
local vertype = bit.lshift(self.version, 4) + self.type
return bin.pack(">CCSS", vertype, self.code, self.session, self.length)
end,
},
-- The TAG NVP Class
Tag = {
Tag = {
-- Creates a new instance of the Tag class
-- @param tag number containing the tag type
-- @param value string/number containing the tag value
-- @return o instance of Tag
-- @return o instance of Tag
new = function(self, tag, value)
local o = { tag = tag, value = value or "" }
setmetatable(o, self)
self.__index = self
return o
end,
-- Converts the instance to string
-- @return string containing the raw config option
__tostring = function(self)
return bin.pack(">SSA", self.tag, #self.value, self.value)
end,
},
PADI = {
-- Creates a new instance of the PADI class
-- @param tags table of <code>PPPoE.Tag</code> instances
-- @param value string/number containing the tag value
-- @return o instance of ConfigNak
-- @return o instance of ConfigNak
new = function(self, tags)
local c = ""
for i=1, 4 do
c = c .. math.random(255)
end
local o = {
header = PPPoE.Header:new(PPPoE.Code.PADI),
tags = tags or {
tags = tags or {
PPPoE.Tag:new(PPPoE.TagType.SERVICE_NAME),
PPPoE.Tag:new(PPPoE.TagType.HOST_UNIQUE, bin.pack("A", c))
}
@@ -455,7 +455,7 @@ PPPoE = {
self.__index = self
return o
end,
-- Converts the instance to string
-- @return string containing the raw config option
__tostring = function(self)
@@ -466,20 +466,20 @@ PPPoE = {
self.header.length = #tags
return tostring(self.header) .. tags
end,
},
PADO = {
-- Creates a new instance of the PADO class
-- @return o instance of PADO
-- @return o instance of PADO
new = function(self)
local o = { tags = {} }
setmetatable(o, self)
self.__index = self
return o
end,
-- Parses a byte stream and builds a new instance of the class
-- @param data string containing raw bytes to parse
-- @return o instance of PADO
@@ -488,7 +488,7 @@ PPPoE = {
pado.header = PPPoE.Header.parse(data)
local pos = #tostring(pado.header) + 1
pado.data = data:sub(pos)
repeat
local tag, len, decoded, raw
pos, tag, len = bin.unpack(">SS", data, pos)
@@ -503,18 +503,18 @@ PPPoE = {
t.decoded = decoded
table.insert(pado.tags, t)
until( pos >= #data )
return pado
end,
},
PADR = {
-- Creates a new instance of the PADR class
-- @param tags table of <code>PPPoE.Tag</code> instances
-- @return o instance of PADR
-- @return o instance of PADR
new = function(self, tags)
local o = {
local o = {
tags = tags or {},
header = PPPoE.Header:new(PPPoE.Code.PADR)
}
@@ -522,7 +522,7 @@ PPPoE = {
self.__index = self
return o
end,
-- Converts the instance to string
-- @return string containing the raw config option
__tostring = function(self)
@@ -533,20 +533,20 @@ PPPoE = {
self.header.length = #tags
return tostring(self.header) .. tags
end,
},
PADS = {
-- Creates a new instance of the PADS class
-- @return o instance of PADS
-- @return o instance of PADS
new = function(self)
local o = { tags = {} }
setmetatable(o, self)
self.__index = self
return o
end,
-- Parses a byte stream and builds a new instance of the class
-- @param data string containing raw bytes to parse
-- @return o instance of PADS
@@ -559,12 +559,12 @@ PPPoE = {
end,
},
PADT = {
-- Creates a new instance of the PADT class
-- @param session number containing the PPPoE session
-- @return o instance of PADT
-- @return o instance of PADT
new = function(self, session)
local o = { header = PPPoE.Header:new(PPPoE.Code.PADT) }
setmetatable(o, self)
@@ -572,7 +572,7 @@ PPPoE = {
self.__index = self
return o
end,
-- Parses a byte stream and builds a new instance of the class
-- @param data string containing raw bytes to parse
-- @return o instance of PADI
@@ -581,22 +581,22 @@ PPPoE = {
padt.header = PPPoE.Header.parse(data)
return padt
end,
-- Converts the instance to string
-- @return string containing the raw config option
__tostring = function(self)
return tostring(self.header)
end,
},
SessionData = {
-- Creates a new instance of the SessionData class
-- @param session number containing the PPPoE session
-- @param data string containing the LCP data to send
-- @return o instance of ConfigNak
-- @return o instance of ConfigNak
new = function(self, session, data)
local o = {
local o = {
data = data or "",
header = PPPoE.Header:new(PPPoE.Code.SESSION_DATA)
}
@@ -605,7 +605,7 @@ PPPoE = {
self.__index = self
return o
end,
-- Parses a byte stream and builds a new instance of the class
-- @param data string containing raw bytes to parse
-- @return o instance of SessionData
@@ -616,7 +616,7 @@ PPPoE = {
sess.data = data:sub(pos)
return sess
end,
-- Converts the instance to string
-- @return string containing the raw config option
__tostring = function(self)
@@ -624,24 +624,24 @@ PPPoE = {
self.header.length = 2 + 4 + #self.data
return tostring(self.header) .. bin.pack(">S", 0xC021) .. self.data
end,
}
}
-- A bunch of tag decoders
PPPoE.TagDecoder = {}
PPPoE.TagDecoder.decodeHex = function(data, pos, len) return pos + len, stdnse.tohex(data:sub(pos, pos+len)) end
PPPoE.TagDecoder.decodeStr = function(data, pos, len) return pos + len, data:sub(pos, pos + len - 1) end
PPPoE.TagDecoder[PPPoE.TagType.SERVICE_NAME]= PPPoE.TagDecoder.decodeStr
PPPoE.TagDecoder[PPPoE.TagType.SERVICE_NAME]= PPPoE.TagDecoder.decodeStr
PPPoE.TagDecoder[PPPoE.TagType.AC_NAME] = PPPoE.TagDecoder.decodeStr
PPPoE.TagDecoder[PPPoE.TagType.AC_COOKIE] = PPPoE.TagDecoder.decodeHex
PPPoE.TagDecoder[PPPoE.TagType.HOST_UNIQUE] = PPPoE.TagDecoder.decodeHex
-- The Comm class responsible for communication with the PPPoE server
Comm = {
-- Creates a new instance of the Comm class
-- @param iface string containing the interface name
-- @param src_mac string containing the source MAC address
@@ -657,24 +657,24 @@ Comm = {
self.__index = self
return o
end,
-- Sets up the pcap receiving socket
-- @return status true on success
connect = function(self)
self.socket = nmap.new_socket()
self.socket:set_timeout(10000)
-- there's probably a more elegant way of doing this
local mac = {}
for i=1, #self.src_mac do table.insert(mac, select(2,bin.unpack("H", self.src_mac, i))) end
mac = stdnse.strjoin(":", mac)
-- let's set a filter on PPPoE we can then check what packet is ours,
-- let's set a filter on PPPoE we can then check what packet is ours,
-- based on the HOST_UNIQUE tag, if we need to
self.socket:pcap_open(self.iface, 1500, false, "ether[0x0c:2] == 0x8863 or ether[0x0c:2] == 0x8864 and ether dst " .. mac)
self.socket:pcap_open(self.iface, 1500, false, "ether[0x0c:2] == 0x8863 or ether[0x0c:2] == 0x8864 and ether dst " .. mac)
return true
end,
-- Sends a packet
-- @param data class containing the request to send
-- @return status true on success, false on failure
@@ -682,12 +682,12 @@ Comm = {
local eth_type = ( data.header.code == PPPoE.Code.SESSION_DATA ) and 0x8864 or 0x8863
local ether = bin.pack(">AAS", self.dst_mac, self.src_mac, eth_type)
local p = packet.Frame:new(ether .. tostring(data))
local sock = nmap.new_dnet()
if ( not(sock) ) then
return false, "Failed to create raw socket"
end
local status = sock:ethernet_open(self.iface)
-- we don't actually need to do this as the script simply crashes
-- if we don't have the right permissions at this point
@@ -700,9 +700,9 @@ Comm = {
return false, "Failed to send data"
end
sock:ethernet_close()
return true
return true
end,
-- Receive a response from the server
-- @return status true on success, false on failure
-- @return response class containing the response or
@@ -714,10 +714,10 @@ Comm = {
if ( not(status) ) then
return false
end
local header = PPPoE.Header.parse(l3)
local p = packet.Frame:new(l2..l3)
-- there's probably a more elegant way of doing this
if ( EtherType.PPPOE_DISCOVERY == p.ether_type ) then
if ( header.code == PPPoE.Code.PADO ) then
@@ -736,19 +736,19 @@ Comm = {
end
return false, ("Received unsupported response, can't decode code (%d)"):format(header.code)
end,
-- Does an "exchange", ie, sends a request and waits for a response
-- @param data class containing the request to send
-- @return status true on success, false on failure
-- @return response class containing the response or
-- err string on error
exch = function(self, data)
exch = function(self, data)
local status, err = self:send(data)
if ( not(status) ) then
return false, err
end
local retries, resp = 3, nil
repeat
status, resp = self:recv()
if ( data.header and 0 == data.header.session ) then
@@ -758,15 +758,15 @@ Comm = {
end
retries = retries - 1
until(retries == 0)
return false, "Failed to retrieve proper PPPoE response"
end,
}
-- The Helper class is the main script interface
Helper = {
-- Creates a new instance of Helper
-- @param iface string containing the name of the interface to use
-- @return o new instance on success, nil on failure
@@ -779,11 +779,11 @@ Helper = {
}
setmetatable(o, self)
self.__index = self
if ( not(nmap.is_privileged()) ) then
return nil, "The PPPoE library requires Nmap to be run in privileged mode"
end
-- get src_mac
local info = nmap.get_interface_info(iface)
if ( not(info) or not(info.mac) ) then
@@ -792,14 +792,14 @@ Helper = {
o.comm = Comm:new(iface, info.mac)
return o
end,
-- Sets up the pcap socket for listening and does some other preparations
-- @return status true on success, false on failure
connect = function(self)
return self.comm:connect()
end,
-- Performs a PPPoE discovery initiation by sending a PADI request to the
-- ethernet broadcast address
-- @return status true on success, false on failure
@@ -813,12 +813,12 @@ Helper = {
end
-- wait for a pado
local pado, retries = nil, 3
repeat
status, pado = self.comm:recv()
if ( not(status) ) then
return status, pado
end
end
retries = retries - 1
until( pado.tags or retries == 0 )
if ( not(pado.tags) ) then
@@ -831,7 +831,7 @@ Helper = {
pado_host_unique = tag.raw
end
end
-- store the tags for later use
self.tags = pado.tags
self.comm.dst_mac = pado.mac_srv
@@ -846,13 +846,13 @@ Helper = {
return true, pado
end,
-- Performs a Discovery Request by sending PADR to the PPPoE ethernet
-- address
-- @return status true on success, false on failure
-- @return pads instance of PADS on success
discoverRequest = function(self)
-- remove the AC-Name tag if there is one
local function getTag(tag)
for _, t in ipairs(self.tags) do
@@ -861,20 +861,20 @@ Helper = {
end
end
end
local taglist = {
local taglist = {
PPPoE.TagType.SERVICE_NAME,
PPPoE.TagType.HOST_UNIQUE,
PPPoE.TagType.AC_COOKIE
}
local tags = {}
for _, t in ipairs(taglist) do
if ( getTag(t) ) then
table.insert(tags, getTag(t))
end
end
local padr = PPPoE.PADR:new(tags)
local status, pads = self.comm:exch(padr)
@@ -910,7 +910,7 @@ Helper = {
end
end
end
AuthMethod.byValue = function(value)
for _, m in ipairs(AuthMethod.methods) do
if ( m.value == value ) then
@@ -918,49 +918,49 @@ Helper = {
end
end
end
local auth_data = ( AuthMethod.byName(method) and AuthMethod.byName(method).value )
if ( not(auth_data) ) then
return false, ("Unsupported authentication mode (%s)"):format(method)
end
self.identifier = self.identifier + 1
-- First do a Configuration Request
local options = { LCP.ConfigOption:new(LCP.ConfigOption.MRU, 1492) }
local lcp_req = LCP.ConfigRequest:new(self.identifier, options)
local sess_req = PPPoE.SessionData:new(self.session, tostring(lcp_req))
local status, resp = self.comm:exch(sess_req)
if ( not(status) or PPPoE.Code.SESSION_DATA ~= resp.header.code ) then
return false, "Unexpected packet type was received"
end
-- Make sure we got a Configuration Request in return
local lcp_header = LCP.Header.parse(resp.data)
local lcp_header = LCP.Header.parse(resp.data)
if ( LCP.Code.CONFIG_REQUEST ~= lcp_header.code ) then
return false, ("Unexpected packet type was received (%d)"):format(lcp_header.code)
end
local config_req = LCP.ConfigRequest.parse(resp.data)
if ( not(config_req.options) ) then
return false, "Failed to retrieve any options from response"
end
local auth_proposed = config_req.options:getById(LCP.ConfigOption.AUTH_PROTO)
if ( auth_proposed.raw ~= auth_data ) then
local options = { LCP.ConfigOption:new(LCP.ConfigOption.AUTH_PROTO, nil, bin.pack("A", auth_data)) }
local lcp_req = LCP.ConfigNak:new(self.identifier, options)
local sess_req = PPPoE.SessionData:new(self.session, tostring(lcp_req))
local status, resp = self.comm:exch(sess_req)
if ( not(status) or PPPoE.Code.SESSION_DATA ~= resp.header.code ) then
return false, "Unexpected packet type was received"
end
-- Make sure we got a Configuration Request in return
local lcp_header = LCP.Header.parse(resp.data)
local lcp_header = LCP.Header.parse(resp.data)
if ( LCP.Code.CONFIG_REQUEST ~= lcp_header.code ) then
return false, ("Unexpected packet type was received (%d)"):format(lcp_header.code)
end
@@ -972,26 +972,26 @@ Helper = {
-- The ACK is essential the Config Request, only with a different code
-- Do a dirty attempt to just replace the code and send the request back as an ack
self.identifier = self.identifier + 1
local lcp_req = LCP.ConfigAck:new(config_req.header.identifier, config_req.options:getTable())
local sess_req = PPPoE.SessionData:new(self.session, tostring(lcp_req))
local status, resp = self.comm:send(sess_req)
return true
end
return false, "Authentication method was not accepted"
end
return false, "Failed to negotiate authentication mechanism"
end,
-- Sends a LCP Terminate Request and waits for an ACK
-- Attempts to do so 10 times before aborting
-- @return status true on success false on failure
close = function(self)
local tries = 10
local tries = 10
repeat
if ( 0 == self.session ) then
break
@@ -1001,20 +1001,20 @@ Helper = {
local status, resp = self.comm:exch(sess_req)
if ( status and resp.header and resp.header.code ) then
if ( PPPoE.Code.SESSION_DATA == resp.header.code ) then
local lcp_header = LCP.Header.parse(resp.data)
local lcp_header = LCP.Header.parse(resp.data)
if ( LCP.Code.TERMINATE_ACK == lcp_header.code ) then
break
end
end
end
tries = tries - 1
until( tries == 0 )
until( tries == 0 )
self.comm:exch(PPPoE.PADT:new(self.session))
return true
end,
}
return _ENV;

View File

@@ -59,7 +59,7 @@ local function check(result, pattern)
return s_code, s_pattern
end
--- Performs a request to the web server and calls check to check if
--- Performs a request to the web server and calls check to check if
-- the response is a valid result
--
--@param socket The socket to send the request through
@@ -151,7 +151,7 @@ end
function return_args()
local url = false
local pattern = false
if nmap.registry.args['proxy.url']
if nmap.registry.args['proxy.url']
then url = nmap.registry.args['proxy.url']
elseif nmap.registry.args.proxy and nmap.registry.args.proxy.url
then url = nmap.registry.args.proxy.url
@@ -197,7 +197,7 @@ function socksHandshake(socket, version, hostname)
end
if version == 4 then
paystring = '04 01 00 50 ' .. sip .. ' 6e 6d 61 70 00'
payload = bin.pack("H",paystring)
payload = bin.pack("H",paystring)
try(socket:send(payload))
local response = try(socket:receive())
local request_status = string.byte(response, 2)
@@ -205,11 +205,11 @@ function socksHandshake(socket, version, hostname)
stdnse.print_debug("Socks4: Received \"Request Granted\" from proxy server\n")
return socket
end
if(request_status == 0x5b) then
if(request_status == 0x5b) then
stdnse.print_debug("Socks4: Received \"Request rejected or failed\" from proxy server")
elseif (request_status == 0x5c) then
elseif (request_status == 0x5c) then
stdnse.print_debug("Socks4: Received \"request failed because client is not running identd\" from proxy server")
elseif (request_status == 0x5d) then
elseif (request_status == 0x5d) then
stdnse.print_debug("Socks4: Received \"request failed because client's identd could not confirm" ..
"\nthe user ID string in the request from proxy server")
end
@@ -220,33 +220,33 @@ function socksHandshake(socket, version, hostname)
try(socket:send(payload))
local auth = try(socket:receive())
local r2 = string.byte(auth,2)
-- If Auth is required, proxy is closed, skip next test
if(r2 ~= 0x00) then
if(r2 ~= 0x00) then
stdnse.print_debug("Socks5: Authentication required")
else
-- If no Auth is required, try to estabilish connection
stdnse.print_debug("Socks5: No authentication required")
-- Socks5 second payload: Version, Command, Null, Address type, Ip-Address, Port number
-- Socks5 second payload: Version, Command, Null, Address type, Ip-Address, Port number
paystring = '05 01 00 01 ' .. sip .. '00 50'
payload = bin.pack("H",paystring)
payload = bin.pack("H",paystring)
try(socket:send(payload))
local z = try(socket:receive())
local z = try(socket:receive())
local request_status = string.byte(z, 2)
if (request_status == 0x00) then
stdnse.print_debug("Socks5: Received \"Request Granted\" from proxy server\n")
return socket
elseif(request_status == 0x01) then
elseif(request_status == 0x01) then
stdnse.print_debug("Socks5: Received \"General failure\" from proxy server")
elseif (request_status == 0x02) then
elseif (request_status == 0x02) then
stdnse.print_debug("Socks5: Received \"Connection not allowed by ruleset\" from proxy server")
elseif (request_status == 0x03) then
elseif (request_status == 0x03) then
stdnse.print_debug("Socks5: Received \"Network unreachable\" from proxy server")
elseif (request_status == 0x04) then
elseif (request_status == 0x04) then
stdnse.print_debug("Socks5: Received \"Host unreachable\" from proxy server")
elseif (request_status == 0x05) then
elseif (request_status == 0x05) then
stdnse.print_debug("Socks5: Received \"Connection refused by destination host\" from proxy server")
elseif (request_status == 0x06) then
elseif (request_status == 0x06) then
stdnse.print_debug("Socks5: Received \"TTL Expired\" from proxy server")
elseif (request_status == 0x07) then
stdnse.print_debug("Socks5: Received \"command not supported / protocol error\" from proxy server")
@@ -255,7 +255,7 @@ function socksHandshake(socket, version, hostname)
end
end
return false
end
end
stdnse.print_debug("Unrecognized proxy type");
return false
end

View File

@@ -1,7 +1,7 @@
---
-- A minimal RDP (Remote Desktop Protocol) library. Currently has functionality to determine encryption
-- and cipher support.
--
--
--
-- @author "Patrik Karlsson <patrik@cqure.net>"
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
@@ -13,7 +13,7 @@ local stdnse = require("stdnse")
_ENV = stdnse.module("rdp", stdnse.seeall)
Packet = {
TPKT = {
new = function(self, data)
@@ -31,7 +31,7 @@ Packet = {
self.data
)
end,
parse = function(data)
local tpkt = Packet.TPKT:new()
local pos
@@ -41,66 +41,66 @@ Packet = {
return tpkt
end
},
ITUT = {
new = function(self, code, data)
local o = { data = tostring(data), code = code }
setmetatable(o, self)
self.__index = self
return o
end,
parse = function(data)
local itut = Packet.ITUT:new()
local pos
pos, itut.length, itut.code = bin.unpack("CC", data)
if ( itut.code == 0xF0 ) then
pos, itut.eot = bin.unpack("C", data, pos)
elseif ( itut.code == 0xD0 ) then
pos, itut.dstref, itut.srcref, itut.class = bin.unpack(">SSC", data, pos)
end
pos, itut.data = bin.unpack("A" .. (#data - pos), data, pos)
return itut
end,
__tostring = function(self)
local len = (self.code ~= 0xF0 and #self.data + 1 or 2)
local data = bin.pack("CC",
len,
self.code or 0
)
if ( self.code == 0xF0 ) then
data = data .. bin.pack("C", 0x80) -- EOT
end
return data .. self.data
end,
},
}
Request = {
ConnectionRequest = {
new = function(self, proto)
local o = { proto = proto }
setmetatable(o, self)
self.__index = self
return o
end,
__tostring = function(self)
local cookie = "mstshash=nmap"
local itpkt_len = 21 + #cookie
local itut_len = 16 + #cookie
local data = bin.pack(">SSCA",
0x0000, -- dst reference
0x0000, -- src reference
@@ -116,18 +116,18 @@ Request = {
return tostring(Packet.TPKT:new(Packet.ITUT:new(0xE0, data)))
end
},
MCSConnectInitial = {
new = function(self, cipher)
local o = { cipher = cipher }
setmetatable(o, self)
self.__index = self
return o
end,
__tostring = function(self)
local data = bin.pack("<HIH",
"7f 65" .. -- BER: Application-Defined Type = APPLICATION 101,
"82 01 90" .. -- BER: Type Length = 404 bytes
@@ -164,7 +164,7 @@ Request = {
"04 82 01 2f" .. -- Connect-Initial::userData (307 bytes)
"00 05" .. -- object length = 5 bytes
"00 14 7c 00 01" .. -- object
"81 26" .. -- ConnectData::connectPDU length = 298 bytes
"81 26" .. -- ConnectData::connectPDU length = 298 bytes
"00 08 00 10 00 01 c0 00 44 75 63 61 81 18" .. -- PER encoded (ALIGNED variant of BASIC-PER) GCC Conference Create Request PDU
"01 c0 d4 00" .. -- TS_UD_HEADER::type = CS_CORE (0xc001), length = 216 bytes
"04 00 08 00" .. -- TS_UD_CS_CORE::version = 0x0008004
@@ -173,12 +173,12 @@ Request = {
"01 ca" .. -- TS_UD_CS_CORE::colorDepth = RNS_UD_COLOR_8BPP (0xca01)
"03 aa" .. -- TS_UD_CS_CORE::SASSequence
"09 08 00 00" .. -- TS_UD_CS_CORE::keyboardLayout = 0x409 = 1033 = English (US)
"28 0a 00 00" .. -- TS_UD_CS_CORE::clientBuild = 3790
"28 0a 00 00" .. -- TS_UD_CS_CORE::clientBuild = 3790
"45 00 4d 00 50 00 2d 00 4c 00 41 00 50 00 2d 00 30 00 30 00 31 00 34 00 00 00 00 00 00 00 00 00" .. -- TS_UD_CS_CORE::clientName = ELTONS-TEST2
"04 00 00 00" .. -- TS_UD_CS_CORE::keyboardType
"00 00 00 00" .. -- TS_UD_CS_CORE::keyboardSubtype
"0c 00 00 00" .. -- TS_UD_CS_CORE::keyboardFunctionKey
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " ..
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " ..
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " ..
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " ..
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " .. -- TS_UD_CS_CORE::imeFileName = ""
@@ -208,40 +208,40 @@ Request = {
"00 00 80 80" .. -- CHANNEL_DEF::options = 0x80800000
"63 6c 69 70 72 64 72 00" .. -- CHANNEL_DEF::name = "cliprdr"
"00 00 a0 c0" .. -- CHANNEL_DEF::options = 0xc0a00000
"72 64 70 73 6e 64 00 00" .. -- CHANNEL_DEF::name = "rdpsnd"
"72 64 70 73 6e 64 00 00" .. -- CHANNEL_DEF::name = "rdpsnd"
"00 00 00 c0" -- CHANNEL_DEF::options = 0xc0000000
)
return tostring(Packet.TPKT:new(Packet.ITUT:new(0xF0, data)))
end
}
}
Response = {
ConnectionConfirm = {
new = function(self)
local o = { }
setmetatable(o, self)
self.__index = self
return o
end,
parse = function(data)
local cc = Response.ConnectionConfirm:new()
local pos, _
cc.tpkt = Packet.TPKT.parse(data)
cc.itut = Packet.ITUT.parse(cc.tpkt.data)
cc.itut = Packet.ITUT.parse(cc.tpkt.data)
return cc
end,
},
MCSConnectResponse = {
new = function(self)
local o = { }
@@ -249,20 +249,20 @@ Response = {
self.__index = self
return o
end,
parse = function(data)
local cr = Response.MCSConnectResponse:new()
cr.tpkt = Packet.TPKT.parse(data)
cr.itut = Packet.ITUT.parse(cr.tpkt.data)
return cr
end
}
}
Comm = {
-- Creates a new Comm instance
-- @param host table
-- @param port table
@@ -273,7 +273,7 @@ Comm = {
self.__index = self
return o
end,
-- Connect to the server
-- @return status true on success, false on failure
-- @return err string containing error message, if status is false
@@ -285,13 +285,13 @@ Comm = {
end
return true
end,
-- Close the connection to the server
-- @return status true on success, false on failure
close = function(self)
return self.socket:close()
end,
-- Sends a message to the server
-- @param pkt an instance of Request.*
-- @return status true on success, false on failure
@@ -306,7 +306,7 @@ Comm = {
recv = function(self)
return self.socket:receive()
end,
-- Sends a message to the server and receives the response
-- @param pkt an instance of Request.*
-- @return status true on success, false on failure
@@ -330,7 +330,7 @@ Comm = {
return true, Response.ConnectionConfirm.parse(data)
elseif ( itut_code == 0xF0 ) then
return true, Response.MCSConnectResponse.parse(data)
end
end
return false, "Received unhandled packet"
end,
}

View File

@@ -16,23 +16,23 @@ Request = {
self.__index = self
return o
end,
__tostring = function(self)
local output = ("*%s\r\n$%d\r\n%s\r\n"):format(#self.args + 1, #self.cmd, self.cmd)
for _, arg in ipairs(self.args) do
arg = tostring(arg)
output = output .. ("$%s\r\n%s\r\n"):format(#arg, arg)
end
return output
end
}
Response = {
Type = {
STATUS = 0,
ERROR = 1,
@@ -40,21 +40,21 @@ Response = {
BULK = 3,
MULTIBULK = 4,
},
new = function(self, socket)
local o = { socket = socket }
setmetatable (o,self)
self.__index = self
return o
end,
receive = function(self)
local status, data = self.socket:receive_buf("\r\n", false)
if ( not(status) ) then
return false, "Failed to receive data from server"
end
-- if we have a status, integer or error message
-- if we have a status, integer or error message
if ( data:match("^[%-%+%:]") ) then
local response = { data = data }
local t = data:match("^([-+:])")
@@ -65,32 +65,32 @@ Response = {
elseif ( t == ":" ) then
response.type = Response.Type.INTEGER
end
return true, response
end
-- process bulk reply
if ( data:match("^%$") ) then
-- non existing key
if ( data == "$-1" ) then
return true, nil
end
local len = tonumber(data:match("^%$(%d*)"))
-- we should only have a single line, so we can just peel of the length
-- we should only have a single line, so we can just peel of the length
status, data = self.socket:receive_buf(match.numbytes(len), false)
if( not(status) ) then
return false, "Failed to receive data from server"
end
return true, { data = data, type = Response.Type.BULK }
end
-- process multi-bulk reply
if ( data:match("^%*%d*") ) then
local count = data:match("^%*(%d*)")
local results = {}
for i=1, count do
-- peel of the length
local status = self.socket:receive_buf("\r\n", false)
@@ -106,28 +106,28 @@ Response = {
end
return true, { data = results, type = Response.Type.MULTIBULK }
end
return false, "Unsupported response"
end,
}
Helper = {
new = function(self, host, port)
local o = { host = host, port = port }
setmetatable (o,self)
self.__index = self
return o
end,
connect = function(self)
self.socket = nmap.new_socket()
return self.socket:connect(self.host, self.port)
end,
reqCmd = function(self, cmd, ...)
local req = Request:new(cmd, ...)
local status, err = self.socket:send(tostring(req))
@@ -136,11 +136,11 @@ Helper = {
end
return Response:new(self.socket):receive()
end,
close = function(self)
return self.socket:close()
end
}
return _ENV;

File diff suppressed because it is too large Load Diff

View File

@@ -87,11 +87,11 @@ _ENV = stdnse.module("rpc", stdnse.seeall)
-- Version 0.3
--
-- Created 01/24/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Created 01/24/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 02/22/2010 - v0.2 - cleanup, revised the way TCP/UDP are handled fo
-- encoding an decoding
-- Revised 03/13/2010 - v0.3 - re-worked library to be OO
-- Revised 04/18/2010 - v0.4 - Applied patch from Djalal Harouni with improved
-- Revised 04/18/2010 - v0.4 - Applied patch from Djalal Harouni with improved
-- error checking and re-designed Comm class. see:
-- http://seclists.org/nmap-dev/2010/q2/232
-- Revised 06/02/2010 - v0.5 - added code to the Util class to check for file
@@ -110,7 +110,7 @@ RPC_args = {
-- Defines the order in which to try to connect to the RPC programs
-- TCP appears to be more stable than UDP in most cases, so try it first
local RPC_PROTOCOLS = (nmap.registry.args and nmap.registry.args[RPC_args['rpcbind'].proto] and
local RPC_PROTOCOLS = (nmap.registry.args and nmap.registry.args[RPC_args['rpcbind'].proto] and
type(nmap.registry.args[RPC_args['rpcbind'].proto]) == 'table') and
nmap.registry.args[RPC_args['rpcbind'].proto] or { "tcp", "udp" }
@@ -169,7 +169,7 @@ Comm = {
local resvport = math.random(1, 1024)
socket = nmap.new_socket()
status, err = socket:bind(nil, resvport)
if status then
if status then
status, err = socket:connect(host, port)
if status or err == "TIMEOUT" then break end
socket:close()
@@ -255,7 +255,7 @@ Comm = {
-- @return status boolean true
SetVersion = function(self, version)
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
self.version = tonumber(nmap.registry.args[RPC_args[self.program].ver])
elseif (not(self.version) and version) then
@@ -271,7 +271,7 @@ Comm = {
-- before trying to connecting.
-- @param check boolean to enable or disable checking of program and version support.
SetCheckProgVer = function(self, check)
self.checkprogver = check
self.checkprogver = check
end,
--- Sets the RPC program ID to use.
@@ -379,7 +379,7 @@ Comm = {
end
pos, header.verifier.flavor = bin.unpack(">I", data, pos)
pos, header.verifier.length = bin.unpack(">I", data, pos)
pos, header.verifier.length = bin.unpack(">I", data, pos)
if header.verifier.length - 8 > 0 then
status, data = self:GetAdditionalBytes( data, pos, header.verifier.length - 8 )
@@ -407,7 +407,7 @@ Comm = {
-- as the packet contains no length field. It's up to each decoding function
-- to do appropriate checks
return self.socket:receive_bytes(1)
else
else
local tmp, lastfragment, length
local data, pos = "", 1
@@ -439,7 +439,7 @@ Comm = {
-- When multiple packets are received they look like this
-- H = Header data
-- D = Data
--
--
-- We don't want the Header
--
-- HHHHDDDDDDDDDDDDDDHHHHDDDDDDDDDDD
@@ -448,7 +448,7 @@ Comm = {
--
-- eg. we want
-- data:sub(5, 18) and data:sub(22)
--
--
local bufcopy = data:sub(pos)
@@ -483,17 +483,17 @@ Comm = {
if ( not(status) ) then
return
end
packet = packet .. ( data or "" )
if ( self.proto == "udp") then
return packet
else
-- set the high bit as this is our last fragment
len = 0x80000000 + packet:len()
return bin.pack(">I", len) .. packet
return bin.pack(">I", len) .. packet
end
end,
SendPacket = function( self, packet )
if ( self.host and self.port ) then
return self.socket:sendto(self.host, self.port, packet)
@@ -509,11 +509,11 @@ Comm = {
}
--- Portmap (rpcbind) class
Portmap =
Portmap =
{
PROTOCOLS = {
['tcp'] = 6,
['udp'] = 17,
PROTOCOLS = {
['tcp'] = 6,
['udp'] = 17,
},
-- TODO: add more Authentication Protocols
@@ -556,7 +556,7 @@ Portmap =
Procedure =
{
[2] =
[2] =
{
GETPORT = 3,
DUMP = 4,
@@ -564,13 +564,13 @@ Portmap =
},
},
State =
{
MSG_ACCEPTED = 0,
MSG_DENIED = 1,
},
AcceptState =
{
SUCCESS = 0,
@@ -594,7 +594,7 @@ Portmap =
RejectState =
{
RPC_MISMATCH = 0,
AUTH_ERROR = 1,
AUTH_ERROR = 1,
},
RejectMsg =
@@ -686,7 +686,7 @@ Portmap =
if ( vfollows == 0 ) then
break
end
pos, program, version, protocol, port = bin.unpack(">IIII", data, pos)
if ( protocol == Portmap.PROTOCOLS.tcp ) then
protocol = "tcp"
@@ -721,15 +721,15 @@ Portmap =
if ( not( Portmap.PROTOCOLS[protocol] ) ) then
return false, ("Portmap.Callit: Protocol %s not supported"):format(protocol)
end
if ( Util.ProgNameToNumber(program) == nil ) then
return false, ("Portmap.Callit: Unknown program name: %s"):format(program)
end
local data = bin.pack(">IIII", Util.ProgNameToNumber(program), version, 0, 0 )
local packet = comm:EncodePacket(nil, Portmap.Procedure[comm.version].CALLIT,
{ type=Portmap.AuthType.NULL }, data )
if (not(comm:SendPacket(packet))) then
return false, "Portmap.Callit: Failed to send data"
end
@@ -753,7 +753,7 @@ Portmap =
end,
--- Queries the portmapper for the port of the selected program,
--- Queries the portmapper for the port of the selected program,
-- protocol and version
--
-- @param comm object handles rpc program information and
@@ -765,20 +765,20 @@ Portmap =
GetPort = function( self, comm, program, protocol, version )
local status, data, response, header, pos, packet
local xid
if ( not( Portmap.PROTOCOLS[protocol] ) ) then
return false, ("Portmap.GetPort: Protocol %s not supported"):format(protocol)
end
if ( Util.ProgNameToNumber(program) == nil ) then
return false, ("Portmap.GetPort: Unknown program name: %s"):format(program)
end
data = bin.pack(">I>I>I>I", Util.ProgNameToNumber(program), version,
Portmap.PROTOCOLS[protocol], 0 )
packet = comm:EncodePacket(xid, Portmap.Procedure[comm.version].GETPORT,
{ type=Portmap.AuthType.NULL }, data )
if (not(comm:SendPacket(packet))) then
return false, "Portmap.GetPort: Failed to send data"
end
@@ -790,7 +790,7 @@ Portmap =
end
pos, header = comm:DecodeHeader( data, 1 )
if ( not(header) ) then
return false, "Portmap.GetPort: Failed to decode RPC header"
end
@@ -862,7 +862,7 @@ Mount = {
MNTERR_SERVERFAULT = 10006,
},
Procedure =
Procedure =
{
MOUNT = 1,
DUMP = 2,
@@ -991,7 +991,7 @@ Mount = {
-- decode groups
while true do
local group
local group
status, data = comm:GetAdditionalBytes( data, pos, 4 )
if (not(status)) then
@@ -1288,7 +1288,7 @@ NFS = {
},
-- Unfortunately the NFS procedure numbers differ in between versions
Procedure =
Procedure =
{
-- NFS Version 1
[1] =
@@ -1302,7 +1302,7 @@ NFS = {
},
-- NFS Version 2
[2] =
[2] =
{
GETATTR = 1,
ROOT = 3,
@@ -1313,7 +1313,7 @@ NFS = {
},
-- NFS Version 3
[3] =
[3] =
{
GETATTR = 1,
SETATTR = 2,
@@ -1365,7 +1365,7 @@ NFS = {
if (status ~= NFS.StatCode[version].NFS_OK) then
if (NFS.StatMsg[status]) then
stdnse.print_debug(4,
string.format("%s failed: %s", procedurename, NFS.StatMsg[status]))
string.format("%s failed: %s", procedurename, NFS.StatMsg[status]))
else
stdnse.print_debug(4,
string.format("%s failed: code %d", procedurename, status))
@@ -1440,7 +1440,7 @@ NFS = {
stdnse.print_debug(4, "NFS.ReadDirDecode: Failed to call GetAdditionalBytes")
return -1, nil
end
pos, status = Util.unmarshall_uint32(data, pos)
if (not self:CheckStat("READDIR", comm.version, status)) then
return -1, nil
@@ -1483,7 +1483,7 @@ NFS = {
stdnse.print_debug(4, "NFS.ReadDirDecode: Failed to call GetAdditionalBytes")
return -1, nil
end
pos, value_follows = Util.unmarshall_uint32(data, pos)
if ( value_follows == 0 ) then
break
@@ -1510,7 +1510,7 @@ NFS = {
stdnse.print_debug(4, "NFS.ReadDirDecode: Failed to call GetAdditionalBytes")
return -1, nil
end
pos, entry.length = Util.unmarshall_uint32(data, pos)
status, data = comm:GetAdditionalBytes( data, pos, entry.length )
if (not(status)) then
@@ -1597,7 +1597,7 @@ NFS = {
if (not self:CheckStat("LOOKUP", comm.version, status)) then
return -1, nil
end
if (comm.version == 3) then
status, data = comm:GetAdditionalBytes( data, pos, 4)
if (not(status)) then
@@ -1718,7 +1718,7 @@ NFS = {
if (not self:CheckStat("READDIRPLUS", comm.version, status)) then
return -1, nil
end
status, data = comm:GetAdditionalBytes(data, pos, 4)
if not status then
stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes")
@@ -1755,7 +1755,7 @@ NFS = {
stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes")
return -1, nil
end
pos, value_follows = bin.unpack(">I", data, pos)
if (value_follows == 0) then
@@ -1781,7 +1781,7 @@ NFS = {
stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes")
return -1, nil
end
pos, entry.name = Util.unmarshall_vopaque(entry.length, data, pos)
status, data = comm:GetAdditionalBytes(data, pos, 8)
if not status then
@@ -1823,7 +1823,7 @@ NFS = {
stdnse.print_debug(4, "NFS.ReadDirPlusDecode: Failed to call GetAdditionalBytes")
return -1, nil
end
_, len = bin.unpack(">I", data, pos)
status, data = comm:GetAdditionalBytes(data, pos, len + 4)
if not status then
@@ -1834,7 +1834,7 @@ NFS = {
else
stdnse.print_debug(4, "NFS.ReadDirPlusDecode: %s handle follow failed",
entry.name)
end
end
table.insert(response.entries, entry)
end
@@ -1854,7 +1854,7 @@ NFS = {
if not file_handle then
return false, "ReadDirPlus: No filehandle received"
end
end
data = bin.pack("A>L>L>I>I", file_handle, cookie,
opaque_data, dircount, maxcount)
@@ -1994,7 +1994,7 @@ NFS = {
stdnse.print_debug(4, "NFS.FsStatDecode: Failed to call GetAdditionalBytes")
return -1, nil
end
pos, fsinfo.rtmax, fsinfo.rtpref, fsinfo.rtmult,
fsinfo.wtmax, fsinfo.wtpref, fsinfo.wtmult,
fsinfo.dtpref = Util.unmarshall_uint32(data, pos, 7)
@@ -2207,7 +2207,7 @@ NFS = {
-- low-level packet manipulation
-- @param file_handle string containing the filehandle to query
-- @return status true on success, false on failure
-- @return statfs table with the fields <code>transfer_size</code>, <code>block_size</code>,
-- @return statfs table with the fields <code>transfer_size</code>, <code>block_size</code>,
-- <code>total_blocks</code>, <code>free_blocks</code> and <code>available_blocks</code>
-- @return errormsg if status is false
StatFs = function( self, comm, file_handle )
@@ -2256,7 +2256,7 @@ NFS = {
-- @param data string containing the full statfs reply
-- @param pos number pointing to the statfs section of the reply
-- @return pos number containing the offset after decoding
-- @return statfs table with the following fields: <code>type</code>, <code>mode</code>,
-- @return statfs table with the following fields: <code>type</code>, <code>mode</code>,
-- <code>nlink</code>, <code>uid</code>, <code>gid</code>, <code>size</code>,
-- <code>blocksize</code>, <code>rdev</code>, <code>blocks</code>, <code>fsid</code>,
-- <code>fileid</code>, <code>atime</code>, <code>mtime</code> and <code>ctime</code>
@@ -2296,7 +2296,7 @@ NFS = {
-- low-level packet manipulation
-- @param file_handle string containing the filehandle to query
-- @return status true on success, false on failure
-- @return attribs table with the fields <code>type</code>, <code>mode</code>,
-- @return attribs table with the fields <code>type</code>, <code>mode</code>,
-- <code>nlink</code>, <code>uid</code>, <code>gid</code>, <code>size</code>,
-- <code>blocksize</code>, <code>rdev</code>, <code>blocks</code>, <code>fsid</code>,
-- <code>fileid</code>, <code>atime</code>, <code>mtime</code> and <code>ctime</code>
@@ -2335,7 +2335,7 @@ NFS = {
-- @param data string containing the full statfs reply
-- @param pos number pointing to the statfs section of the reply
-- @return pos number containing the offset after decoding
-- @return statfs table with the following fields: <code>transfer_size</code>, <code>block_size</code>,
-- @return statfs table with the following fields: <code>transfer_size</code>, <code>block_size</code>,
-- <code>total_blocks</code>, <code>free_blocks</code> and <code>available_blocks</code>
StatFsDecode = function( self, comm, data, pos )
local status
@@ -2357,8 +2357,8 @@ NFS = {
stdnse.print_debug(4, "StatFsDecode: Failed to call GetAdditionalBytes")
return -1, nil
end
pos, statfs.transfer_size, statfs.block_size,
statfs.total_blocks, statfs.free_blocks,
pos, statfs.transfer_size, statfs.block_size,
statfs.total_blocks, statfs.free_blocks,
statfs.available_blocks = Util.unmarshall_uint32(data, pos, 5)
return pos, statfs
end,
@@ -2375,7 +2375,7 @@ Helper = {
-- @return result table of string entries or error message on failure
ShowMounts = function( host, port )
local status, result, mounts
local status, result, mounts
local mountd, mnt_comm
local mnt = Mount:new()
local portmap = Portmap:new()
@@ -2520,7 +2520,7 @@ Helper = {
-- @param port table
-- @param path string containing the nfs export path
-- @return status true on success, false on failure
-- @return statfs table with the fields <code>transfer_size</code>, <code>block_size</code>,
-- @return statfs table with the fields <code>transfer_size</code>, <code>block_size</code>,
-- <code>total_blocks</code>, <code>free_blocks</code> and <code>available_blocks</code>
ExportStats = function( host, port, path )
local fhandle
@@ -2528,7 +2528,7 @@ Helper = {
local mnt_comm, nfs_comm
local mountd, nfsd = {}, {}
local mnt, nfs = Mount:new(), NFS:new()
status, mountd = Helper.GetProgramInfo( host, port, "mountd", 2)
if ( not(status) ) then
stdnse.print_debug(4, "rpc.Helper.ExportStats: GetProgramInfo failed")
@@ -2576,7 +2576,7 @@ Helper = {
stdnse.print_debug(4, "rpc.Helper.ExportStats: %s", stats)
return status, stats
end
status, fhandle = mnt:Unmount(mnt_comm, path)
mnt_comm:Disconnect()
nfs_comm:Disconnect()
@@ -2651,7 +2651,7 @@ Helper = {
stdnse.print_debug(4, "rpc.Helper.Dir: %s", dirs)
return status, dirs
end
status, fhandle = mnt:Unmount(mnt_comm, path)
mnt_comm:Disconnect()
nfs_comm:Disconnect()
@@ -2668,7 +2668,7 @@ Helper = {
-- @param port table
-- @param path string containing the nfs export path
-- @return status true on success, false on failure
-- @return statfs table with the fields <code>transfer_size</code>, <code>block_size</code>,
-- @return statfs table with the fields <code>transfer_size</code>, <code>block_size</code>,
-- <code>total_blocks</code>, <code>free_blocks</code> and <code>available_blocks</code>
GetAttributes = function( host, port, path )
local fhandle
@@ -2688,7 +2688,7 @@ Helper = {
stdnse.print_debug(4, "rpc.Helper.GetAttributes: GetProgramInfo failed")
return status, "rpc.Helper.GetAttributes: GetProgramInfo failed"
end
mnt_comm, result = Comm:new('mountd', mountd.version)
nfs_comm, result = Comm:new('nfs', nfsd.version)
@@ -2730,7 +2730,7 @@ Helper = {
end
status, fhandle = mnt:Unmount(mnt_comm, path)
mnt_comm:Disconnect()
nfs_comm:Disconnect()
if ( not(status) ) then
@@ -2740,13 +2740,13 @@ Helper = {
return true, attribs
end,
--- Queries the portmapper for a list of programs
--
-- @param host table
-- @param port table
-- @return status true on success, false on failure
-- @return table containing the portmapper information as returned by
-- @return table containing the portmapper information as returned by
-- <code>Portmap.Dump</code>
RpcInfo = function( host, port )
local status, result
@@ -2754,7 +2754,7 @@ Helper = {
local comm = Comm:new('rpcbind', 2)
mutex "lock"
if nmap.registry[host.ip] == nil then
nmap.registry[host.ip] = {}
end
@@ -2790,13 +2790,13 @@ Helper = {
-- @param program string containing the RPC program name
-- @param protocol string containing either "tcp" or "udp"
-- @return status true on success, false on failure
-- @return table containing the portmapper information as returned by
-- @return table containing the portmapper information as returned by
-- <code>Portmap.Dump</code>
GetPortForProgram = function( host, port, program, protocol )
local status, result
local portmap = Portmap:new()
local comm = Comm:new('rpcbind', 2)
status, result = comm:Connect(host, port)
if (not(status)) then
stdnse.print_debug(4, "rpc.Helper.GetPortForProgram: %s", result)
@@ -2808,10 +2808,10 @@ Helper = {
if (not(status)) then
stdnse.print_debug(4, "rpc.Helper.GetPortForProgram: %s", result)
end
return status, result
end,
--- Get RPC program information
--
-- @param host table
@@ -2882,7 +2882,7 @@ Util =
-- S_IWUSR
[0x00000080] = { idx = 2, char = "w" },
-- S_IXUSR
[0x00000040] = { idx = 3, char = "x" },
[0x00000040] = { idx = 3, char = "x" },
-- S_ISUID
[0x00000800] = { idx = 3, char = "S" },
},
@@ -3238,7 +3238,7 @@ Util =
end
return string.format("%.1f%s", size, unit[idx])
end,
format_access = function(mask, version)
local ret, nfsobj = "", NFS:new()
@@ -3285,7 +3285,7 @@ Util =
--
-- @param pconf table returned by the NFSv3 PATHCONF call
-- @param nfsversion the version of the remote NFS server
-- @return fs table that contains the remote filesystem
-- @return fs table that contains the remote filesystem
-- pathconf information.
calc_pathconf_table = function(pconf, nfsversion)
local fs = {}
@@ -3301,7 +3301,7 @@ Util =
else
fs.chown_restricted = "False"
end
return fs, nil
end,
@@ -3309,9 +3309,9 @@ Util =
--
-- @param fsinfo table returned by the NFSv3 FSINFO call
-- @param nfsversion the version of the remote NFS server
-- @param human if set show the size in the human
-- @param human if set show the size in the human
-- readable format.
-- @return fs table that contains the remote filesystem
-- @return fs table that contains the remote filesystem
-- information.
calc_fsinfo_table = function(fsinfo, nfsversion, human)
local fs = {}
@@ -3339,15 +3339,15 @@ Util =
--- Calculate and return the fsstat filesystem table
--
-- @param stats table returned by the NFSv3 FSSTAT or
-- @param stats table returned by the NFSv3 FSSTAT or
-- NFSv2 STATFS calls
-- @param nfsversion the version of the remote NFS server
-- @param human if set show the size in the human
-- @param human if set show the size in the human
-- readable format.
-- @return df table that contains the remote filesystem
-- @return df table that contains the remote filesystem
-- attributes.
calc_fsstat_table = function(stats, nfsversion, human)
local df, base = {}, 1024
local df, base = {}, 1024
local size, free, total, avail, used, use
if (nfsversion == 3) then
free = stats.fbytes
@@ -3392,7 +3392,7 @@ Util =
-- @return num number containing the program ID
ProgNameToNumber = function(prog_name)
local status
if not( RPC_PROGRAMS ) then
status, RPC_PROGRAMS = datafiles.parse_rpc()
if ( not(status) ) then
@@ -3404,17 +3404,17 @@ Util =
return num
end
end
return
end,
--- Converts the RPC program number to it's equivalent name
--
-- @param num number containing the RPC program identifier
-- @return string containing the RPC program name
ProgNumberToName = function( num )
local status
if not( RPC_PROGRAMS ) then
status, RPC_PROGRAMS = datafiles.parse_rpc()
if ( not(status) ) then
@@ -3423,7 +3423,7 @@ Util =
end
return RPC_PROGRAMS[num]
end,
--
-- Calculates the number of fill bytes needed
-- @param length contains the length of the string

View File

@@ -34,20 +34,20 @@ local table = require "table"
_ENV = stdnse.module("rpcap", stdnse.seeall)
RPCAP = {
MessageType = {
ERROR = 1,
FIND_ALL_INTERFACES = 2,
AUTH_REQUEST = 8,
},
-- Holds the two supported authentication mechanisms PWD and NULL
Authentication = {
PWD = {
new = function(self, username, password)
local o = {
local o = {
type = 1,
username = username,
password = password,
@@ -56,37 +56,37 @@ RPCAP = {
self.__index = self
return o
end,
__tostring = function(self)
local DUMMY = 0
return bin.pack(">SSSSAA", self.type, DUMMY, #self.username, #self.password, self.username, self.password)
end,
},
NULL = {
new = function(self)
local o = {
local o = {
type = 0,
}
setmetatable(o, self)
self.__index = self
return o
end,
__tostring = function(self)
local DUMMY = 0
return bin.pack(">SSSS", self.type, DUMMY, 0, 0)
end,
}
}
},
-- The common request and response header
Header = {
size = 8,
size = 8,
new = function(self, type, value, length)
local o = {
version = 0,
@@ -98,25 +98,25 @@ RPCAP = {
self.__index = self
return o
end,
parse = function(data)
local header = RPCAP.Header:new()
local pos
pos, header.version, header.type, header.value, header.length = bin.unpack(">CCSI", data)
return header
end,
__tostring = function(self)
return bin.pack(">CCSI", self.version, self.type, self.value, self.length)
end,
},
-- The implemented request types are kept here
-- The implemented request types are kept here
Request = {
Authentication = {
new = function(self, data)
local o = {
header = RPCAP.Header:new(RPCAP.MessageType.AUTH_REQUEST, nil, #data),
@@ -126,15 +126,15 @@ RPCAP = {
self.__index = self
return o
end,
__tostring = function(self)
return tostring(self.header) .. tostring(self.data)
end,
},
FindAllInterfaces = {
new = function(self)
local o = {
header = RPCAP.Header:new(RPCAP.MessageType.FIND_ALL_INTERFACES)
@@ -143,27 +143,27 @@ RPCAP = {
self.__index = self
return o
end,
__tostring = function(self)
return tostring(self.header)
end,
}
},
},
-- Parsers for responses are kept here
Response = {
Authentication = {
Authentication = {
new = function(self)
local o = { }
setmetatable(o, self)
self.__index = self
return o
end,
parse = function(data)
local resp = RPCAP.Response.Authentication:new()
local pos = RPCAP.Header.size + 1
@@ -171,7 +171,7 @@ RPCAP = {
return resp
end
},
Error = {
new = function(self)
local o = { }
@@ -187,9 +187,9 @@ RPCAP = {
pos, err.error = bin.unpack("A" .. err.header.length, data, pos)
return err
end
},
FindAllInterfaces = {
new = function(self)
local o = { }
@@ -197,7 +197,7 @@ RPCAP = {
self.__index = self
return o
end,
parse = function(data)
-- Each address is made up of 4 128 byte fields, this function
@@ -208,11 +208,11 @@ RPCAP = {
local offset = pos
local family, port
pos, family, port = bin.unpack(">SS", data, pos)
if ( family == 0x0017 ) then
-- not sure why...
pos = pos + 4
local ipv6
pos, ipv6 = bin.unpack("B16", data, pos)
return offset + 128, ipOps.bin_to_ip(ipv6)
@@ -221,27 +221,27 @@ RPCAP = {
pos, ipv4 = bin.unpack("B4", data, pos)
return offset + 128, ipOps.bin_to_ip(ipv4)
end
return offset + 128, nil
end
-- Parses one of X addresses returned for an interface
local function parseAddress(data, pos)
local fields = {"ip", "netmask", "bcast", "p2p"}
local addr = {}
for _, f in ipairs(fields) do
pos, addr[f] = parseField(data, pos)
end
return pos, addr
end
local resp = RPCAP.Response.FindAllInterfaces:new()
local pos = RPCAP.Header.size + 1
resp.header = RPCAP.Header.parse(data)
resp.ifaces = {}
for i=1, resp.header.value do
local name_len, desc_len, iface_flags, addr_count, dummy
pos, name_len, desc_len, iface_flags, addr_count, dummy = bin.unpack(">SSISS", data, pos)
@@ -268,10 +268,10 @@ RPCAP = {
return resp
end,
}
}
}
-- Maps packet types to classes
@@ -284,7 +284,7 @@ RPCAP.TypeToClass = {
-- The communication class
Comm = {
-- Creates a new instance of the Comm class
-- @param host table
-- @param port table
@@ -295,12 +295,12 @@ Comm = {
self.__index = self
return o
end,
-- Connects the socket to the server
connect = function(self)
return self.socket:connect(self.host, self.port)
end,
-- Sends an instance of the request class to the server
-- @param req class instance
-- @return status true on success, false on failure
@@ -313,7 +313,7 @@ Comm = {
-- in RPCAP.TypeToClass
-- @return status true on success, false on failure
-- @return resp instance of a Response class or
-- err string containing the error message
-- err string containing the error message
recv = function(self)
local status, hdr_data = self.socket:receive_buf(match.numbytes(RPCAP.Header.size), true)
if ( not(status) ) then
@@ -324,7 +324,7 @@ Comm = {
if ( not(header) ) then
return false, "rpcap: Failed to parse header"
end
local status, data = self.socket:receive_buf(match.numbytes(header.length), true)
if ( not(status) ) then
return false, "rpcap: Failed to read packet data"
@@ -336,10 +336,10 @@ Comm = {
return true, resp
end
end
return false, "Failed to receive response from server"
end,
-- Sends and request and receives the response
-- @param req the instance of the Request class to send
-- @return status true on success, false on failure
@@ -352,23 +352,23 @@ Comm = {
end
return self:recv()
end,
-- closes the socket
close = function(self)
return self.socket:close()
end,
}
Helper = {
-- Creates a new instance of the Helper class
-- @param host table
-- @param port table
-- @return o instance of Helper
new = function(self, host, port)
local o = {
local o = {
host = host,
port = port,
comm = Comm:new(host, port)
@@ -382,7 +382,7 @@ Helper = {
connect = function(self)
return self.comm:connect(self.host, self.port)
end,
-- Authenticates to the service, in case no username or password is given
-- NULL authentication is assumed.
-- @param username [optional]
@@ -391,20 +391,20 @@ Helper = {
-- @return err string containing error mesage on failure
login = function(self, username, password)
local auth
if ( username and password ) then
auth = RPCAP.Authentication.PWD:new(username, password)
else
auth = RPCAP.Authentication.NULL:new()
end
local req = RPCAP.Request.Authentication:new(tostring(auth))
local status, resp = self.comm:exch(req)
if ( not(status) ) then
return false, resp
end
if ( status and resp.error ) then
return false, resp.error
end
@@ -416,11 +416,11 @@ Helper = {
findAllInterfaces = function(self)
local req = RPCAP.Request.FindAllInterfaces:new()
local status, resp = self.comm:exch(req)
if ( not(status) ) then
return false, resp
end
local results = {}
for _, iface in ipairs(resp.ifaces) do
local entry = {}
@@ -431,7 +431,7 @@ Helper = {
end
return true, results
end,
-- Closes the connection to the server
close = function(self)
return self.comm:close()

View File

@@ -15,7 +15,7 @@ _ENV = stdnse.module("rsync", stdnse.seeall)
-- The Helper class serves as the main interface for script writers
Helper = {
-- Creates a new instance of the Helper class
-- @param host table as received by the action function
-- @param port table as received by the action function
@@ -28,7 +28,7 @@ Helper = {
self.__index = self
return o
end,
-- Handles send and receive of control messages
-- @param data string containing the command to send
-- @return status true on succes, false on failure
@@ -45,7 +45,7 @@ Helper = {
end
return true, data
end,
-- Connects to the rsync server
-- @return status, true on success, false on failure
-- @return err string containing an error message if status is false
@@ -56,7 +56,7 @@ Helper = {
if ( not(status) ) then
return false, err
end
local data
status, data = self:ctrl_exch("@RSYNCD: 29")
if ( not(status) ) then
@@ -67,7 +67,7 @@ Helper = {
end
return true
end,
-- Authenticates against the rsync module. If no username is given, assume
-- no authentication is required.
-- @param username [optional] string containing the username
@@ -78,7 +78,7 @@ Helper = {
if (not(status)) then
return false, data
end
local chall
if ( data:match("@RSYNCD: OK") ) then
return true, "No authentication was required"
@@ -94,7 +94,7 @@ Helper = {
if ( chall and not(username) ) then
return false, "Authentication required"
end
local md4 = openssl.md4("\0\0\0\0" .. password .. chall)
local resp = base64.enc(md4):sub(1,-3)
status, data = self:ctrl_exch(username .. " " .. resp)
@@ -105,9 +105,9 @@ Helper = {
if ( data == "@RSYNCD: OK" ) then
return true, "Authentication successfull"
end
return false, "Authentication failed"
return false, "Authentication failed"
end,
-- Lists accessible modules from the rsync server
-- @return status true on success, false on failure
-- @return modules table containing a list of modules
@@ -116,7 +116,7 @@ Helper = {
if (not(status)) then
return false, data
end
local modules = {}
while(true) do
status, data = self.socket:receive_buf("\n", false)
@@ -131,7 +131,7 @@ Helper = {
end
return true, modules
end,
-- Lists the files available for the directory/module
-- TODO: Add support for parsing results, seemed straight forward at
-- first, but wasn't.
@@ -146,7 +146,7 @@ Helper = {
if ( not(status) ) then
return false, data
end
status, data = self.socket:send("\0\0\0\0")
if ( not(status) ) then
return false, data
@@ -156,7 +156,7 @@ Helper = {
if ( not(status) ) then
return false, data
end
local pos, len = bin.unpack("<S", data)
status, data = self.socket:receive_buf(match.numbytes(len), false)
if ( not(status) ) then
@@ -165,11 +165,11 @@ Helper = {
-- Parsing goes here
end,
-- Disconnects from the rsync server
-- @return status true on success, false on failure
disconnect = function(self) return self.socket:close() end,
}
return _ENV;

View File

@@ -41,7 +41,7 @@ _ENV = stdnse.module("rtsp", stdnse.seeall)
-- The RTSP Request object
Request = {
--- Creates a new Request instance
-- @return o instance of Request
new = function(self, url, headers)
@@ -50,53 +50,53 @@ Request = {
self.__index = self
return o
end,
--- Sets the RTSP Request method
-- @param method string containing the RTSP method
setMethod = function(self, method)
self.method = method
end,
--- Sets the RTSP sequence number
-- @param cseq number containing the sequence number
setCSeq = function(self, cseq)
self.cseq = cseq
end,
--- Adds an optional header to the RTSP request
-- @param header string containing the header name
-- @param value string containing the header value
addHeader = function(self, header, value)
table.insert( self.headers, { header = value } )
end,
--- Converts the Request to a string
--
-- @return req string containing the request as a string
__tostring = function(self)
assert(self.cseq, "Request is missing required header CSeq")
assert(self.url, "Request is missing URL")
local req = stdnse.strjoin("\r\n", {
("%s %s RTSP/1.0"):format(self.method, self.url),
local req = stdnse.strjoin("\r\n", {
("%s %s RTSP/1.0"):format(self.method, self.url),
("CSeq: %d"):format(self.cseq)
} ) .. "\r\n"
if ( #self.headers > 0 ) then
req = req .. stdnse.strjoin("\r\n", self.headers) .. "\r\n"
end
return req .. "\r\n"
end,
end,
}
-- The RTSP response instance
Response = {
--- Creates a new Response instance
-- @param data string containing the unparsed data
-- @param data string containing the unparsed data
new = function(self, data)
assert(data, "No data was supplied")
local o = {
local o = {
raw = data,
status = tonumber(data:match("^RTSP%/1%.0 (%d*) "))
}
@@ -104,7 +104,7 @@ Response = {
-- Split the response into a temporary array
local tmp = stdnse.strsplit("\r\n", data)
if ( not(tmp) ) then return nil end
-- we should have atleas one entry
if ( #tmp > 1 ) then
o.headers = {}
@@ -121,19 +121,19 @@ Response = {
self.__index = self
return o
end,
}
-- RTSP Client class
Client = {
-- Creates a new Client instance
-- @param host table as received by the action method
-- @param port table as received by the action method
-- @return o instance of Client
new = function(self, host, port)
local o = {
local o = {
host = host,
port = port,
cseq = 0,
@@ -145,22 +145,22 @@ Client = {
self.__index = self
return o
end,
--- Sets the number of retries for socket reads
-- @param retries number containing the number of retries
setRetries = function(self, retries) self.retries = retries end,
--- Sets the socket connection timeout in ms
-- @param timeout number containing the timeout in ms
setTimeout = function(self, timeout) self.timeout = timeout end,
--- Adds a RTSP header to the request
-- @param header string containing the header name
-- @param value string containing the header value
addHeader = function(self, header, value)
table.insert(self.headers, { ("%s: %s"):format(header,value) } )
end,
--- Connects to the RTSP server
-- @return status true on success, false on failure
-- @return err string containing the error message on failure
@@ -173,8 +173,8 @@ Client = {
return false, ("Failed to connect to the server: %s"):format(self.host.ip)
end
return true
end,
end,
--- Sends a DESCRIBE request to the server and receives the response
-- @param url string containing the RTSP URL
-- @return status true on success, false on failure
@@ -185,15 +185,15 @@ Client = {
req:setMethod("DESCRIBE")
return self:exch(req)
end,
options = function(self, url)
local req = Request:new(url, self.headers)
req:setMethod("OPTIONS")
return self:exch(req)
end,
--- Sends a request to the server and receives the response and attempts
-- to retry if either send or receive fails.
-- to retry if either send or receive fails.
-- @param request instance of Request
-- @return status true on success, false on failure
-- @return response Response instance on success
@@ -203,7 +203,7 @@ Client = {
local status, data
self.cseq = self.cseq + 1
req:setCSeq( self.cseq )
repeat
local err
status, err = self.socket:send( tostring(req) )
@@ -217,7 +217,7 @@ Client = {
status, data = self.socket:receive()
-- if we got the response allright, break out of retry loop
if ( status ) then break end
end
end
-- if either send or receive fails, re-connect the socket
if ( not(status) ) then
self:close()
@@ -227,7 +227,7 @@ Client = {
stdnse.print_debug(2, "Failed to reconnect socket to server (%s)", err)
return false, ("Failed to reconnect socket to server (%s)"):format(err)
end
end
end
retries = retries - 1
until( status or retries == 0 )
@@ -235,20 +235,20 @@ Client = {
stdnse.print_debug(2, "Failed to receive response from server (%s)", data)
return false, ("Failed to receive response from server (%s)"):format(data)
end
return true, Response:new(data)
end,
--- Closes the RTSP socket with the server
close = function(self)
return self.socket:close()
end,
}
-- The Helper class is the main script interface
Helper = {
-- Creates a new Helper instance
-- @param host table as received by the action method
-- @param port table as received by the action method
@@ -259,19 +259,19 @@ Helper = {
self.__index = self
return o
end,
-- Connects to the RTSP server
-- @return status true on success, false on failure
-- @return err string containing the error message on failure
connect = function(self)
return self.client:connect()
end,
-- Closes the RTSP socket with the server
close = function(self)
return self.client:close()
end,
-- Sends a DESCRIBE request to the server and receives the response
--
-- @param url string containing the RTSP URL
@@ -281,11 +281,11 @@ Helper = {
describe = function(self, url)
return self.client:describe(url)
end,
options = function(self, url)
return self.client:options(url)
end,
}
return _ENV;

View File

@@ -11,7 +11,7 @@
-- local dmd5 = DigestMD5:new(chall, user, pass, "AUTHENTICATE", nil, "imap")
-- local digest = dmd5:calcDigest()
-- </code>
--
--
-- The <code>NTLM</code> class contains all code necessary to calculate a
-- NTLM response based on the servers challenge and the other necessary
-- arguments (@see NTLM.new). It can be called through the SASL helper or
@@ -55,7 +55,7 @@ if ( not(HAVE_SSL) ) then
end
local MECHANISMS = { }
if HAVE_SSL then
if HAVE_SSL then
-- Calculates a DIGEST MD5 response
DigestMD5 = {
@@ -64,8 +64,8 @@ if HAVE_SSL then
-- @param chall string containing the base64 decoded challenge
-- @return a new instance of DigestMD5
new = function(self, chall, username, password, method, uri, service, realm)
local o = { nc = 0,
chall = chall,
local o = { nc = 0,
chall = chall,
challnvs = {},
username = username,
password = password,
@@ -150,7 +150,7 @@ if HAVE_SSL then
response = response .. (",%s=\"%s\""):format("digest-uri", uri)
response = response .. (",%s=%s"):format("response", digest)
response = response .. (",%s=%s"):format("charset", "utf-8")
-- response_table is used in http library because the request should
-- be a little bit different then the string generated above
local response_table = {
@@ -164,7 +164,7 @@ if HAVE_SSL then
algorithm = self.challnvs.algorithm,
response = digest_http
}
return response, response_table
end,
@@ -180,8 +180,8 @@ if HAVE_SSL then
-- @param password string containing the password
-- @return new instance of NTML
new = function(self, chall, username, password)
local o = { nc = 0,
chall = chall,
local o = { nc = 0,
chall = chall,
username = username,
password = password}
setmetatable(o, self)
@@ -207,8 +207,8 @@ if HAVE_SSL then
local NTLM_NegotiateExtendedSecurity = 0x00080000
local pos, _, message_type
pos, _, message_type, _, _,
_, self.flags, self.chall, _,
pos, _, message_type, _, _,
_, self.flags, self.chall, _,
_, _, _ = bin.unpack("<A8ISSIIA8LSSI", self.chall)
if ( message_type ~= 0x02 ) then
@@ -225,7 +225,7 @@ if HAVE_SSL then
self.workstation = self.to_unicode(self.workstation)
self.username = self.to_unicode(self.username)
self.domain = self.to_unicode(self.domain)
end
end
end,
--- Calculates the response
@@ -277,7 +277,7 @@ if HAVE_SSL then
end
}
--- Encodes the parameters using the <code>CRAM-MD5</code> mechanism.
--
-- @param username string.
@@ -303,11 +303,11 @@ if HAVE_SSL then
-- @return string The encoded string on success, or nil if Nmap was
-- compiled without OpenSSL.
function digest_md5_enc(username, password, challenge, service, uri)
return DigestMD5:new(challenge,
username,
password,
"AUTHENTICATE",
uri,
return DigestMD5:new(challenge,
username,
password,
"AUTHENTICATE",
uri,
service):calcDigest()
end
@@ -448,7 +448,7 @@ Helper = {
end,
--- Returns the current authentication mechanism.
--
--
-- @return mechanism on success, or nil on failures.
get_mechanism = function(self)
return self.mechanism

View File

@@ -73,7 +73,7 @@ end
-- <code>"smtp"</code>, or <code>"ftp"</code>. These service names are
-- determined by Nmap's version scan or (if no version scan information is
-- available) the service assigned to the port in <code>nmap-services</code>
-- (e.g. <code>"http"</code> for TCP port 80).
-- (e.g. <code>"http"</code> for TCP port 80).
-- @param services Service name or a list of names to run against.
-- @param protos The protocol or list of protocols to match against, default
-- <code>"tcp"</code>.
@@ -110,7 +110,7 @@ end
-- a list of values as in those functions. This function exists because many
-- scripts explicitly try to run against the well-known ports, but want also to
-- run against any other port which was discovered to run the named service.
-- @usage portrule = shortport.port_or_service(22,"ssh").
-- @usage portrule = shortport.port_or_service(22,"ssh").
-- @param ports A single port number or a list of port numbers.
-- @param services Service name or a list of names to run against.
-- @param protos The protocol or list of protocols to match against, default

View File

@@ -6,7 +6,7 @@
-- Overview
-- --------
-- The library consists of the following classes:
--
--
-- o SessionData
-- - Holds session data for the SIP session
--
@@ -31,7 +31,7 @@
--
-- o Helper
-- - A class containing code used as a primary interface by scripts
--
--
--
-- @author "Patrik Karlsson <patrik@cqure.net>"
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
@@ -75,7 +75,7 @@ Error = {
-- The SessionData class
SessionData = {
--- Creates a new instance of sessiondata
-- @return o an instance of SessionData
new = function(self, o)
@@ -85,7 +85,7 @@ SessionData = {
o.user = "user"
return o
end,
--- Sets the session username
-- @param user string containing the username
setUsername = function(self, user) self.user = user end,
@@ -111,19 +111,19 @@ SessionData = {
--- Sets the SIP users Full Name
-- @param name string containing the full name of the user
setName = function(self, name) self.name = name end,
--- Retrieves the username
-- @return user string containing the sessions username
getUsername = function(self) return self.user end,
--- Retrieves the session password
-- @return pass string containing the session password
getPassword = function(self) return self.pass end,
--- Retrieves the SIP domain
-- @return domain string containing the SIP domain
getDomain = function(self) return self.domain end,
--- Retrieves the client IP and port
-- @return host string containing the client IP
-- @return port number containing the client port
@@ -158,13 +158,13 @@ Session = {
o.expires = (options and options.expires) or 300
o.conn = Connection:new(host,port)
o.cseq = (options and options.cseq) or 1234
local timeout = ( ( options and options.timeout ) and
local timeout = ( ( options and options.timeout ) and
options.timeout * 1000 ) or 5000
o.conn.socket:set_timeout( timeout )
o.sessdata = sessdata or SessionData:new()
return o
end,
--- Connect the session
-- @return true on success, false on failure
-- @return err string containing error message
@@ -181,12 +181,12 @@ Session = {
self.sessdata:setServer(rhost, rport)
return true
end,
--- Closes the session
-- TODO: We should probably send some "closing" packets here
-- @return true on success, false on failure
close = function(self) return self.conn:close() end,
--- Sends and SIP invite
-- @param uri
invite = function(self, uri)
@@ -194,10 +194,10 @@ Session = {
local lhost, _ = self.sessdata:getClient()
local tm = os.time()
local uri = (uri and uri:match("^sip:.*@.*")) or
local uri = (uri and uri:match("^sip:.*@.*")) or
("sip:%s@%s"):format(uri, self.sessdata:getDomain())
request:setUri(uri)
request:setSessionData(self.sessdata)
@@ -212,13 +212,13 @@ Session = {
request:setContent(stdnse.strjoin("\r\n", data))
request:setContentType("application/sdp")
local status, response = self:exch(request)
if ( not(status) ) then return false, response end
local errcode = response:getErrorCode()
if ( Error.PROXY_AUTH_REQUIRED == errcode or
if ( Error.PROXY_AUTH_REQUIRED == errcode or
Error.UNAUTHORIZED == errcode ) then
-- Send an ACK to the server
@@ -232,19 +232,19 @@ Session = {
status, data = self:authenticate(request, response)
if ( not(status) ) then return false, "SIP Authentication failed" end
response = Response:new(data)
-- read a bunch of 180 Ringing and 100 Trying requests, until we get a 200 OK
while ( response:getErrorCode() ~= Error.OK ) do
status, data = self.conn:recv()
if ( not(status) ) then return status, "ERROR: Failed to receive response" end
response = Response:new(data)
end
end
return true
end,
--- Prepares and sends the challenge response authentication to the server
-- @param request instance of the request object requiring authentication
-- @param authdata string containing authentication data
@@ -252,7 +252,7 @@ Session = {
-- @return err string containing an error message if status is false
authenticate = function(self, request, response)
local rhost, _ = self.sessdata:getServer()
local auth_header, auth_data = response:getAuthData()
local auth_header, auth_data = response:getAuthData()
local auth = SipAuth:new(auth_data)
auth:setUsername(self.sessdata:getUsername())
auth:setPassword(self.sessdata:getPassword())
@@ -276,7 +276,7 @@ Session = {
end
return status, data
end,
--- Sends a SIP Request and receives the Response
-- @param request instance of Request
-- @return status true on success, false on failure
@@ -284,31 +284,31 @@ Session = {
-- err containing error message if status is false
exch = function(self, request)
request:setCseq(self.cseq)
local status, err = self.conn:send( tostring(request) )
if ( not(status) ) then return status, "ERROR: Failed to send request" end
local status, data = self.conn:recv()
if ( not(status) ) then return status, "ERROR: Failed to receive response" end
return true, Response:new(data)
end,
--- Sends a register request to the server
-- @return status true on success, false on failure
-- @return msg string containing the error message (if status is false)
register = function(self)
local request = Request:new(Method.REGISTER, self.protocol)
request:setUri("sip:" .. self.sessdata:getServer())
request:setSessionData(self.sessdata)
request:setExpires(self.expires)
local status, response = self:exch(request)
if (not(status)) then return false, response end
local errcode = response:getErrorCode()
if ( status and errcode == Error.OK ) then
return true, response
elseif ( Error.PROXY_AUTH_REQUIRED == errcode or Error.UNAUTHORIZED == errcode ) then
@@ -316,7 +316,7 @@ Session = {
self.cseq = self.cseq + 1
status, data = self:authenticate(request, response)
response = Response:new(data)
errcode = response:getErrorCode()
errcode = response:getErrorCode()
if ( not(status) or ( errcode and errcode ~= Error.OK ) ) then
return false, "ERROR: Failed to authenticate"
end
@@ -327,7 +327,7 @@ Session = {
end
return true
end,
--- Sends an option request to the server and handles the response
-- @return status true on success, false on failure
-- @return response if status is true, nil else.
@@ -348,7 +348,7 @@ Session = {
-- The connection class contains basic communication code
Connection = {
--- Creates a new SIP Connection
-- @param host table containing the host to connect to
-- @param port table containing the port to connect to
@@ -362,7 +362,7 @@ Connection = {
o.socket = nmap.new_socket()
return o
end,
--- Connects to the server
-- @return status containing true on success and false on failure
-- @return err containing the error message (if status is false)
@@ -377,7 +377,7 @@ Connection = {
end
return status, err
end,
--- Sends the data over the socket
-- @return status true on success, false on failure
send = function(self, data)
@@ -395,7 +395,7 @@ Connection = {
close = function(self)
return self.socket:close()
end,
--- Retrieves the client ip and port
-- @return lhost string containing the local ip
-- @return lport number containing the local port
@@ -405,13 +405,13 @@ Connection = {
-- @return rhost string containing the server ip
-- @return rport number containing the server port
getServer = function(self) return ( self.host.ip or self.host ), ( self.port.number or self.port ) end,
}
-- The response class holds the necessary methods and parameters to parse a response
Response = {
--- Creates a new Response instance
-- @param str containing the data as received over the socket
-- @return o table containing a new Response instance
@@ -422,7 +422,7 @@ Response = {
o.tbl = stdnse.strsplit("\r\n", str)
return o
end,
--- Retrieves a given header value from the response
-- @param name string containing the name of the header
-- @return value string containing the header value
@@ -430,40 +430,40 @@ Response = {
for _, line in ipairs(self.tbl) do
local header, value = line:match("^(.-): (.*)$")
if ( header and header:lower() == name:lower() ) then
return value
return value
end
end
end,
--- Returns the error code from the SIP response
-- @return err number containing the error code
getErrorCode = function(self)
return tonumber(self.tbl[1]:match("SIP/%d%.%d (%d+)"))
end,
--- Returns the error message returned by the server
-- @return errmsg string containing the error message
getErrorMessage = function(self)
return self.tbl[1]:match("^SIP/%d%.%d %d+ (.+)$")
end,
--- Returns the message method
-- @return method string containing the method
getMethod = function(self)
return self.tbl[1]:match("^(.-)%s.*SIP/2%.0$")
end,
--- Returns the authentication data from the SIP response
-- @return auth string containing the raw authentication data
getAuthData = function(self)
local auth = self:getHeader("WWW-Authenticate") or self:getHeader("Proxy-Authenticate")
if ( auth ) then
return ( self:getHeader("WWW-Authenticate") and
"WWW-Authenticate" or
return ( self:getHeader("WWW-Authenticate") and
"WWW-Authenticate" or
"Proxy-Authenticate"), auth
end
end,
--- Retrieves the current sequence number
-- @return cseq number containing the current sequence number
getCSeq = function(self)
@@ -471,12 +471,12 @@ Response = {
cseq = (cseq and cseq:match("^(%d+)"))
return (cseq and tonumber(cseq))
end,
}
-- The request class holds the necessary functions and parameters for a basic SIP request
Request = {
--- Creates a new Request instance
-- @param method string containing the request method to use
-- @param proto Used protocol, could be "UDP" or "TCP"
@@ -485,7 +485,7 @@ Request = {
local o = {}
setmetatable(o, self)
self.__index = self
o.ua = "Nmap NSE"
o.protocol = proto or "UDP"
o.expires = 0
@@ -498,11 +498,11 @@ Request = {
o.cid = Util.get_random_string(60)
return o
end,
--- Sets the sessiondata so that session information may be fetched
-- @param data instance of SessionData
setSessionData = function(self, data) self.sessdata = data end,
--- Adds a custom header to the request
-- @param name string containing the header name
-- @param value string containing the header value
@@ -510,28 +510,28 @@ Request = {
self.headers = self.headers or {}
table.insert(self.headers, ("%s: %s"):format(name, value))
end,
--- Sets the SIP uri
-- @param uri string containing the SIP uri
setUri = function(self, uri) self.uri = uri end,
--- Sets an error
-- @param code number containing the error code
-- @param msg string containing the error message
setError = function(self, code, msg) self.error = { code = code, msg = msg } end,
--- Sets the request method
-- @param method string containing a valid SIP method (@see Method constant)
setMethod = function(self, method) self.method = method end,
--- Sets the sequence number
-- @param seq number containing the sequence number to set
setCseq = function(self, seq) self.cseq = seq end,
--- Sets the allow header
-- @param allow table containing all of the allowed SIP methods
setAllow = function(self, allow) self.allow = stdnse.strjoin(", ", allow) end,
--- Sets the request content data
-- @param string containing the content data
setContent = function(self, content) self.content = content end,
@@ -543,15 +543,15 @@ Request = {
--- Sets the supported SIP methods
-- @param supported string containing the supported methods
setSupported = function(self, supported) self.supported = supported end,
--- Sets the content-length of the SIP request
-- @param len number containing the length of the actual request
setContentLength = function(self, len) self.length = len end,
--- Sets the expires header of the SIP request
-- @param expires number containing the expire value
setExpires = function(self, expires) self.expires = expires end,
--- Sets the User Agent being used to connect to the SIP server
-- @param ua string containing the User-Agent name (defaults to Nmap NSE)
setUA = function(self, ua) self.ua = ua end,
@@ -559,19 +559,19 @@ Request = {
--- Sets the caller ID information of the SIP request
-- @param cid string containing the callers id
setCallId = function(self, cid) self.cid = cid end,
--- Sets the maximum forwards allowed of this request
-- @param maxfwd number containing the maximum allowed forwards
setForwards = function(self, maxfwd) self.maxfwd = maxfwd end,
--- Sets the proxy authentication data
-- @param auth string containing properly formatted proxy authentication data
setProxyAuth = function(self, auth) self.proxyauth = auth end,
--- Sets the www authentication data
-- @param auth string containing properly formatted proxy authentication data
setWWWAuth = function(self, auth) self.wwwauth = auth end,
--- Specifies the network protocol being used
-- @param proto should be either "UDP" or "TCP"
setProtocol = function(self, proto)
@@ -579,7 +579,7 @@ Request = {
self.protocol = proto
end,
--- Converts the request to a String suitable to be sent over the socket
-- @return ret string containing the complete request for sending over the socket
__tostring = function(self)
@@ -590,15 +590,15 @@ Request = {
local sessdata = self.sessdata
local lhost, lport = sessdata:getClient()
local rhost, rport = sessdata:getServer()
local name, user, domain = sessdata:getName(), sessdata:getUsername(), sessdata:getDomain()
assert(self.method, "No method specified")
assert(self.maxfwd, "Max forward not set")
-- if no domain was specified use the remote host instead
domain = domain or rhost
if ( self.error ) then
table.insert(data, ("SIP/2.0 %s %d"):format(self.error.msg, self.error.code))
else
@@ -611,15 +611,15 @@ Request = {
table.insert(data, ("Via: SIP/2.0/%s %s:%d;rport;branch=%s"):format(self.protocol, lhost, lport, branch))
table.insert(data, ("Max-Forwards: %d"):format(self.maxfwd))
table.insert(data, ("From: \"%s\" <sip:%s@%s>;tag=%s"):format(name, user, domain, self.from_tag))
if ( self.method == Method.INVITE ) then
table.insert(data, ("To: <sip:%s@%s>"):format(user, domain))
else
table.insert(data, ("To: \"%s\" <sip:%s@%s>"):format(name, user, domain))
end
table.insert(data, ("Call-ID: %s"):format(self.cid))
if ( self.error and self.error.code == Error.OK ) then
table.insert(data, ("CSeq: %d OPTIONS"):format(self.cseq))
else
@@ -638,9 +638,9 @@ Request = {
if ( self.supported ) then
table.insert(data, ("Supported: %s"):format(self.supported))
end
if ( not(self.error) ) then
if ( self.proxyauth ) then
if ( self.proxyauth ) then
table.insert(data, ("Proxy-Authorization: %s"):format(self.proxyauth))
end
if ( self.wwwauth ) then
@@ -664,22 +664,22 @@ Request = {
table.insert(data, "")
else
self.length = (self.content and #self.content +2 or 0)
table.insert(data, ("Content-Length: %d"):format(self.length))
table.insert(data, "")
end
return stdnse.strjoin("\r\n", data)
end,
}
-- A minimal Util class with supporting functions
Util = {
--- Generates a random string of the requested length.
-- @param length (optional) The length of the string to return. Default: 8.
-- @param set (optional) The set of letters to choose from. Default: upper, lower, numbers, and underscore.
-- @return The random string.
--- Generates a random string of the requested length.
-- @param length (optional) The length of the string to return. Default: 8.
-- @param set (optional) The set of letters to choose from. Default: upper, lower, numbers, and underscore.
-- @return The random string.
get_random_string = function(length, set)
if(length == nil) then
length = 8
@@ -698,12 +698,12 @@ Util = {
return str
end
}
-- The SIP authentication class, supporting MD5 digest authentication
SipAuth = {
--- Creates a new SipAuth instance
-- @param auth string containing the auth data as received from the server
new = function(self, auth)
@@ -713,46 +713,46 @@ SipAuth = {
o.auth = auth
return o
end,
--- Sets the username used for authentication
-- @param username string containing the name of the user
setUsername = function(self, username) self.username = username end,
--- Sets the password used for authentication
-- @param password string containing the password of the user
setPassword = function(self, password) self.password = password end,
--- Sets the method used for authentication
-- @param method string containing the method (Usually REGISTER)
setMethod = function(self, method) self.method = method end,
--- Sets the uri used for authentication
-- @param uri string containing the uri (Usually sip:<ip>)
setUri = function(self, uri) self.uri = uri end,
--- Processes and parses a challenge as received from the server
parseChallenge = function(self)
if ( not(self.auth) ) then return end
self.nonce = self.auth:match("nonce=[\"]([^,]-)[\"]")
self.algorithm = self.auth:match("algorithm=[\"]*(.-)[\"]*,")
self.realm = self.auth:match("realm=[\"]([^,]-)[\"]")
assert(self.algorithm:upper() == "MD5",
assert(self.algorithm:upper() == "MD5",
("Unsupported algorithm detected in authentication challenge (%s)"):format(self.algorithm:upper()))
end,
--- Calculates the authentication response
-- @return reponse string containing the authentication response
calculateResponse = function(self)
if ( not(self.nonce) or not(self.algorithm) or not(self.realm) ) then
self:parseChallenge()
end
assert(self.username, "SipAuth: No username specified")
assert(self.password, "SipAuth: No password specified")
assert(self.method, "SipAuth: No method specified")
assert(self.uri, "SipAuth: No uri specified")
local result
if ( self.algorithm == "MD5" ) then
local HA1 = select(2, bin.unpack("H16", openssl.md5(self.username .. ":" .. self.realm .. ":" .. self.password)))
@@ -761,7 +761,7 @@ SipAuth = {
end
return select(2, bin.unpack("H16", result)):lower()
end,
--- Creates the complete authentication response
-- @return auth string containing the complete authentication digest
createResponse = function(self)
@@ -770,12 +770,12 @@ SipAuth = {
" uri=\"%s\", response=\"%s\", algorithm=%s"):format(self.username, self.realm,
self.nonce, self.uri, response, self.algorithm)
end,
}
-- The Helper class used as main script interface
Helper = {
--- Creates a new instance of the Helper class
-- @param host table containing the remote host
-- @param port table containing the remote port
@@ -789,7 +789,7 @@ Helper = {
local timeout = stdnse.get_script_args("sip.timeout")
if ( timeout ) then options.timeout = timeout end
o.sessdata = SessionData:new()
o.session = Session:new(host, port, o.sessdata, options)
o.session = Session:new(host, port, o.sessdata, options)
return o
end,
@@ -797,7 +797,7 @@ Helper = {
connect = function(self) return self.session:connect() end,
--- Disconnects and closes the helper instance
close = function(self) return self.session:close() end,
close = function(self) return self.session:close() end,
--- Sets the credentials used when performing authentication
-- @param username string containing the username to use for authentication
@@ -812,7 +812,7 @@ Helper = {
setDomain = function(self, domain) self.sessdata:setDomain(domain) end,
--- Register the UAC with the server
-- @param options table containing zero or more options
-- @param options table containing zero or more options
-- (@see Session:register for more details)
-- @return status true on success, false on failure
-- @return msg containing the error message if status is false
@@ -823,14 +823,14 @@ Helper = {
end,
options = function(self) return self.session:options() end,
--- Attempts to INVITE the user at uri to a call
-- @param uri string containing the sip uri
-- @return status true on success, false on failure
invite = function(self, uri)
return self.session:invite(uri)
end,
}
return _ENV;

File diff suppressed because it is too large Load Diff

View File

@@ -1,54 +1,54 @@
---
-- This module takes care of the authentication used in SMB (LM, NTLM, LMv2, NTLMv2).
-- This module takes care of the authentication used in SMB (LM, NTLM, LMv2, NTLMv2).
--
-- There is a lot to this functionality, so if you're interested in how it works, read
-- on.
-- on.
-- In SMB authentication, there are two distinct concepts. Each will be dealt with
-- separately. There are:
-- * Stored hashes
-- * Authentication
--
-- What's confusing is that the same names are used for each of those.
-- What's confusing is that the same names are used for each of those.
--
-- Stored Hashes:
-- Windows stores two types of hashes: Lanman and NT Lanman (or NTLM). Vista and later
-- store NTLM only. Lanman passwords are divided into two 7-character passwords and
-- used as a key in DES, while NTLM is converted to unicode and MD4ed.
-- store NTLM only. Lanman passwords are divided into two 7-character passwords and
-- used as a key in DES, while NTLM is converted to unicode and MD4ed.
--
-- The stored hashes can be dumped in a variety of ways (pwdump6, fgdump, Metasploit's
-- <code>priv</code> module, <code>smb-psexec.nse</code>, etc). Generally, two hashes are dumped together
-- <code>priv</code> module, <code>smb-psexec.nse</code>, etc). Generally, two hashes are dumped together
-- (generally, Lanman:NTLM). Sometimes, Lanman is empty and only NTLM is given. Lanman
-- is never required.
-- is never required.
--
-- The password hashes can be given instead of passwords when supplying credentials;
-- The password hashes can be given instead of passwords when supplying credentials;
-- this is done by using the <code>smbhash</code> argument. Either a pair of hashes
-- can be passed, in the form of Lanman:NTLM, or a single hash, which is assumed to
-- be NTLM.
-- be NTLM.
--
-- Authentication:
-- There are four types of authentication. Confusingly, these have the same names as
-- stored hashes, but only slight relationships. The four types are Lanmanv1, NTLMv1,
-- Lanmanv2, and NTLMv2. By default, Lanmanv1 and NTLMv1 are used together in most
-- applications. These Nmap scripts default to NTLMv1 alone, except in special cases,
-- but it can be overridden by the user.
-- stored hashes, but only slight relationships. The four types are Lanmanv1, NTLMv1,
-- Lanmanv2, and NTLMv2. By default, Lanmanv1 and NTLMv1 are used together in most
-- applications. These Nmap scripts default to NTLMv1 alone, except in special cases,
-- but it can be overridden by the user.
--
-- Lanmanv1 and NTLMv1 both use DES for their response. The DES mixes a server challenge
-- with the hash (Lanman hash for Lanmanv1 response and NTLMv1 hash for NTLM response).
-- The way the challenge is DESed with the hashes is identical for Lanmanv1 and NTLMv1,
-- the only difference is the starting hash (Lanman vs NTLM).
-- with the hash (Lanman hash for Lanmanv1 response and NTLMv1 hash for NTLM response).
-- The way the challenge is DESed with the hashes is identical for Lanmanv1 and NTLMv1,
-- the only difference is the starting hash (Lanman vs NTLM).
--
-- Lanmanv2 and NTLMv2 both use HMAC-MD5 for their response. The HMAC-MD5 mixes a
-- server challenge and a client challenge with the NTLM hash, in both cases. The
-- Lanmanv2 and NTLMv2 both use HMAC-MD5 for their response. The HMAC-MD5 mixes a
-- server challenge and a client challenge with the NTLM hash, in both cases. The
-- difference between Lanmanv2 and NTLMv2 is the length of the client challenge;
-- Lanmanv2 has a maximum client challenge of 8 bytes, whereas NTLMv2 doesn't limit
-- the length of the client challenge.
-- the length of the client challenge.
--
-- The primary advantage to the 'v2' protocols is the client challenge -- by
-- The primary advantage to the 'v2' protocols is the client challenge -- by
-- incorporating a client challenge, a malicious server can't use a precomputation
-- attack.
-- attack.
--
-- In addition to hashing the passwords, messages are also signed, by default, if a
-- v1 protocol is being used (I (Ron Bowes) couldn't get signatures to work on v2
-- In addition to hashing the passwords, messages are also signed, by default, if a
-- v1 protocol is being used (I (Ron Bowes) couldn't get signatures to work on v2
-- protocols; if anybody knows how I'd love to implement it).
--
--@args smbusername The SMB username to log in with. The forms "DOMAIN\username" and "username@DOMAIN"
@@ -59,7 +59,7 @@
-- accounts if the incorrect password is given. Although it's rare that the
-- Administrator account can be locked out, in the off chance that it can, you could
-- get yourself in trouble. To use a blank password, leave this parameter off
-- altogether.
-- altogether.
--@args smbhash A password hash to use when logging in. This is given as a single hex string (32
-- characters) or a pair of hex strings (both 32 characters, optionally separated by a
-- single character). These hashes are the LanMan or NTLM hash of the user's password,
@@ -71,14 +71,14 @@
-- * <code>NTLMv1</code>: Sends NTLMv1 only (default).
-- * <code>v2</code>: Sends LMv2 and NTLMv2.
-- * <code>LMv2</code>: Sends LMv2 only.
-- * <code>NTLMv2</code>: Doesn't exist; the protocol doesn't support NTLMv2 alone.
-- The default, <code>NTLMv1</code>, is a pretty decent compromise between security and
-- compatibility. If you are paranoid, you might want to use <code>v2</code> or
-- <code>lmv2</code> for this. (Actually, if you're paranoid, you should be avoiding this
-- protocol altogether!). If you're using an extremely old system, you might need to set
-- this to <code>v1</code> or <code>lm</code>, which are less secure but more compatible.
-- For information, see <code>smbauth.lua</code>.
--@args smbnoguest Use to disable usage of the 'guest' account.
-- * <code>NTLMv2</code>: Doesn't exist; the protocol doesn't support NTLMv2 alone.
-- The default, <code>NTLMv1</code>, is a pretty decent compromise between security and
-- compatibility. If you are paranoid, you might want to use <code>v2</code> or
-- <code>lmv2</code> for this. (Actually, if you're paranoid, you should be avoiding this
-- protocol altogether!). If you're using an extremely old system, you might need to set
-- this to <code>v1</code> or <code>lm</code>, which are less secure but more compatible.
-- For information, see <code>smbauth.lua</code>.
--@args smbnoguest Use to disable usage of the 'guest' account.
local bin = require "bin"
local nmap = require "nmap"
@@ -136,17 +136,17 @@ end
-- * registry[ip]['smbaccounts'] => array of table containing 'username', 'password', and 'is_admin'
--
-- The final place, 'smbaccount', is reserved for the "best" account. This is an administrator
-- account, if one's found; otherwise, it's the first account discovered that isn't <code>guest</code>.
-- account, if one's found; otherwise, it's the first account discovered that isn't <code>guest</code>.
--
-- This has to be called while no SMB connections are made, since it potentially makes its own connection.
--
--@param host The host object.
--@param username The username to add.
--@param domain The domain to add.
--@param password The password to add.
--@param password_hash The password hash to add.
--@param host The host object.
--@param username The username to add.
--@param domain The domain to add.
--@param password The password to add.
--@param password_hash The password hash to add.
--@param hash_type The hash type to use.
--@param is_admin [optional] Set to 'true' the account is known to be an administrator.
--@param is_admin [optional] Set to 'true' the account is known to be an administrator.
function add_account(host, username, domain, password, password_hash, hash_type, is_admin)
-- Save the username in a global list -- TODO: restore this
-- if(nmap.registry.usernames == nil) then
@@ -216,11 +216,11 @@ function add_account(host, username, domain, password, password_hash, hash_type,
end
---Retrieve the current set of credentials set in the registry. If these fail, <code>next_credentials</code> should be
-- called.
-- called.
--
--@param host The host object.
--@param host The host object.
--@return (result, username, domain, password, password_hash, hash_type) If result is false, username is an error message. Otherwise, username and password are
-- the current username and password that should be used.
-- the current username and password that should be used.
function get_account(host)
if(host.registry['smbindex'] == nil) then
host.registry['smbindex'] = 1
@@ -237,9 +237,9 @@ function get_account(host)
end
---Create the account table with the anonymous and guest users, as well as the user given in the script's
-- arguments, if there is one.
-- arguments, if there is one.
--
--@param host The host object.
--@param host The host object.
function init_account(host)
-- Don't run this more than once for each host
if(host.registry['smbaccounts'] ~= nil) then
@@ -327,8 +327,8 @@ end
---Generate the Lanman v1 hash (LMv1). The generated hash is incredibly easy to reverse, because the input
-- is padded or truncated to 14 characters, then split into two 7-character strings. Each of these strings
-- are used as a key to encrypt the string, "KGS!@#$%" in DES. Because the keys are no longer than
-- 7-characters long, it's pretty trivial to bruteforce them.
-- are used as a key to encrypt the string, "KGS!@#$%" in DES. Because the keys are no longer than
-- 7-characters long, it's pretty trivial to bruteforce them.
--
--@param password the password to hash
--@return (status, hash) If status is true, the hash is returned; otherwise, an error message is returned.
@@ -364,7 +364,7 @@ local function lm_create_hash(password)
end
---Generate the NTLMv1 hash. This hash is quite a bit better than LMv1, and is far easier to generate. Basically,
-- it's the MD4 of the Unicode password.
-- it's the MD4 of the Unicode password.
--
--@param password the password to hash
--@return (status, hash) If status is true, the hash is returned; otherwise, an error message is returned.
@@ -376,12 +376,12 @@ function ntlm_create_hash(password)
return true, openssl.md4(to_unicode(password))
end
---Create the Lanman response to send back to the server. To do this, the Lanman password is padded to 21
---Create the Lanman response to send back to the server. To do this, the Lanman password is padded to 21
-- characters and split into three 7-character strings. Each of those strings is used as a key to encrypt
-- the server challenge. The three encrypted strings are concatenated and returned.
-- the server challenge. The three encrypted strings are concatenated and returned.
--
--@param lanman The LMv1 hash
--@param challenge The server's challenge.
--@param challenge The server's challenge.
--@return (status, response) If status is true, the response is returned; otherwise, an error message is returned.
function lm_create_response(lanman, challenge)
if(have_ssl ~= true) then
@@ -406,7 +406,7 @@ function lm_create_response(lanman, challenge)
key3 = openssl.DES_string_to_key(str3)
-- Print a warning message if a blank challenge is received, and create a phony challenge. A blank challenge is
-- invalid in the protocol, and causes some versions of OpenSSL to abort with no possible error handling.
-- invalid in the protocol, and causes some versions of OpenSSL to abort with no possible error handling.
if(challenge == "") then
stdnse.print_debug(1, "SMB: ERROR: Server returned invalid (blank) challenge value (should be 8 bytes); failing login to avoid OpenSSL crash.")
challenge = "AAAAAAAA"
@@ -419,10 +419,10 @@ function lm_create_response(lanman, challenge)
end
---Create the NTLM response to send back to the server. This is actually done the exact same way as the Lanman hash,
-- so I call the <code>Lanman</code> function.
-- so I call the <code>Lanman</code> function.
--
--@param ntlm The NTLMv1 hash
--@param challenge The server's challenge.
--@param challenge The server's challenge.
--@return (status, response) If status is true, the response is returned; otherwise, an error message is returned.
function ntlm_create_response(ntlm, challenge)
if(have_ssl ~= true) then
@@ -432,12 +432,12 @@ function ntlm_create_response(ntlm, challenge)
return lm_create_response(ntlm, challenge)
end
---Create the NTLM mac key, which is used for message signing. For basic authentication, this is the md4 of the
---Create the NTLM mac key, which is used for message signing. For basic authentication, this is the md4 of the
-- NTLM hash, concatenated with the response hash; for extended authentication, this is just the md4 of the NTLM
-- hash.
--@param ntlm_hash The NTLM hash.
--@param ntlm_response The NTLM response.
--@param is_extended Should be set if extended security negotiations are being used.
-- hash.
--@param ntlm_hash The NTLM hash.
--@param ntlm_response The NTLM response.
--@param is_extended Should be set if extended security negotiations are being used.
function ntlm_create_mac_key(ntlm_hash, ntlm_response, is_extended)
if(have_ssl ~= true) then
return false, "SMB: OpenSSL not present"
@@ -449,12 +449,12 @@ function ntlm_create_mac_key(ntlm_hash, ntlm_response, is_extended)
end
end
---Create the LM mac key, which is used for message signing. For basic authentication, it's the first 8 bytes
-- of the lanman hash, followed by 8 null bytes, followed by the lanman response; for extended authentication,
-- this is just the first 8 bytes of the lanman hash followed by 8 null bytes.
--@param lm_hash The NTLM hash.
--@param lm_response The NTLM response.
--@param is_extended Should be set if extended security negotiations are being used.
---Create the LM mac key, which is used for message signing. For basic authentication, it's the first 8 bytes
-- of the lanman hash, followed by 8 null bytes, followed by the lanman response; for extended authentication,
-- this is just the first 8 bytes of the lanman hash followed by 8 null bytes.
--@param lm_hash The NTLM hash.
--@param lm_response The NTLM response.
--@param is_extended Should be set if extended security negotiations are being used.
function lm_create_mac_key(lm_hash, lm_response, is_extended)
if(have_ssl ~= true) then
return false, "SMB: OpenSSL not present"
@@ -467,13 +467,13 @@ function lm_create_mac_key(lm_hash, lm_response, is_extended)
end
end
---Create the NTLMv2 hash, which is based on the NTLMv1 hash (for easy upgrading), the username, and the domain.
-- Essentially, the NTLM hash is used as a HMAC-MD5 key, which is used to hash the unicode domain concatenated
-- with the unicode username.
---Create the NTLMv2 hash, which is based on the NTLMv1 hash (for easy upgrading), the username, and the domain.
-- Essentially, the NTLM hash is used as a HMAC-MD5 key, which is used to hash the unicode domain concatenated
-- with the unicode username.
--
--@param ntlm The NTLMv1 hash.
--@param username The username we're using.
--@param domain The domain.
--@param ntlm The NTLMv1 hash.
--@param username The username we're using.
--@param domain The domain.
--@return (status, response) If status is true, the response is returned; otherwise, an error message is returned.
function ntlmv2_create_hash(ntlm, username, domain)
if(have_ssl ~= true) then
@@ -488,8 +488,8 @@ function ntlmv2_create_hash(ntlm, username, domain)
return true, openssl.hmac("MD5", ntlm, username .. domain)
end
---Create the LMv2 response, which can be sent back to the server. This is identical to the <code>NTLMv2</code> function,
-- except that it uses an 8-byte client challenge.
---Create the LMv2 response, which can be sent back to the server. This is identical to the <code>NTLMv2</code> function,
-- except that it uses an 8-byte client challenge.
--
-- The reason for LMv2 is a long and twisted story. Well, not really. The reason is basically that the v1 hashes
-- are always 24-bytes, and some servers expect 24 bytes, but the NTLMv2 hash is more than 24 bytes. So, the only
@@ -498,9 +498,9 @@ end
-- learned something
--
--@param ntlm The NVLMv1 hash.
--@param username The username we're using.
--@param domain The domain.
--@param challenge The server challenge.
--@param username The username we're using.
--@param domain The domain.
--@param challenge The server challenge.
--@return (status, response) If status is true, the response is returned; otherwise, an error message is returned.
function lmv2_create_response(ntlm, username, domain, challenge)
if(have_ssl ~= true) then
@@ -511,14 +511,14 @@ function lmv2_create_response(ntlm, username, domain, challenge)
end
---Create the NTLMv2 response, which can be sent back to the server. This is done by using the HMAC-MD5 algorithm
-- with the NTLMv2 hash as a key, and the server challenge concatenated with the client challenge for the data.
-- with the NTLMv2 hash as a key, and the server challenge concatenated with the client challenge for the data.
-- The resulting hash is concatenated with the client challenge and returned.
--
-- The "proper" implementation for this uses a certain structure for the client challenge, involving the time
-- and computer name and stuff (if you don't do this, Wireshark tells you it's a malformed packet). In my tests,
-- and computer name and stuff (if you don't do this, Wireshark tells you it's a malformed packet). In my tests,
-- however, I couldn't get Vista to recognize a client challenge longer than 24 bytes, and this structure was
-- guaranteed to be much longer than 24 bytes. So, I just use a random string generated by OpenSSL. I've tested
-- it on every Windows system from Windows 2000 to Windows Vista, and it has always worked.
-- it on every Windows system from Windows 2000 to Windows Vista, and it has always worked.
function ntlmv2_create_response(ntlm, username, domain, challenge, client_challenge_length)
if(have_ssl ~= true) then
return false, "SMB: OpenSSL not present"
@@ -533,21 +533,21 @@ end
---Generate the Lanman and NTLM password hashes. The password itself is taken from the function parameters,
-- the nmap arguments, and the registry (in that order). If no password is set, then the password hash
-- is used (which is read from all the usual places). If neither is set, then a blank password is used.
-- is used (which is read from all the usual places). If neither is set, then a blank password is used.
--
-- The output passwords are hashed based on the hash type.
-- The output passwords are hashed based on the hash type.
--
--@param ip The ip address of the host, used for registry lookups.
--@param username The username, which is used for v2 passwords.
--@param domain The username, which is used for v2 passwords.
--@param password [optional] The overriding password.
--@param password_hash [optional] The overriding password hash. Shouldn't be set if password is set.
--@param ip The ip address of the host, used for registry lookups.
--@param username The username, which is used for v2 passwords.
--@param domain The username, which is used for v2 passwords.
--@param password [optional] The overriding password.
--@param password_hash [optional] The overriding password hash. Shouldn't be set if password is set.
--@param challenge The server challenge.
--@param hash_type The way in which to hash the password.
--@param hash_type The way in which to hash the password.
--@param is_extended Set to 'true' if extended security negotiations are being used (this has to be known for the
-- message-signing key to be generated properly).
--@return (lm_response, ntlm_response, mac_key) The two strings that can be sent directly back to the server,
-- and the mac_key, which is used for message signing.
-- message-signing key to be generated properly).
--@return (lm_response, ntlm_response, mac_key) The two strings that can be sent directly back to the server,
-- and the mac_key, which is used for message signing.
function get_password_response(ip, username, domain, password, password_hash, hash_type, challenge, is_extended)
local status
local lm_hash = nil
@@ -601,7 +601,7 @@ function get_password_response(ip, username, domain, password, password_hash, ha
-- Output what we've got so far
stdnse.print_debug(2, "SMB: Lanman hash: %s", stdnse.tohex(lm_hash))
stdnse.print_debug(2, "SMB: NTLM hash: %s", stdnse.tohex(ntlm_hash))
-- Hash the password the way the user wants
if(hash_type == "v1") then
-- LM and NTLM are hashed with their respective algorithms
@@ -646,7 +646,7 @@ function get_password_response(ip, username, domain, password, password_hash, ha
else
stdnse.print_debug(1, "SMB: No login type specified, using default (NTLM)")
end
status, lm_response = ntlm_create_response(ntlm_hash, challenge)
status, ntlm_response = ntlm_create_response(ntlm_hash, challenge)
@@ -665,10 +665,10 @@ function get_security_blob(security_blob, ip, username, domain, password, passwo
if(security_blob == nil) then
-- If security_blob is nil, this is the initial packet
new_blob = bin.pack("<zIILL",
new_blob = bin.pack("<zIILL",
"NTLMSSP", -- Identifier
NTLMSSP_NEGOTIATE, -- Type
flags, -- Flags
flags, -- Flags
0, -- Calling workstation domain
0 -- Calling workstation name
)
@@ -721,7 +721,7 @@ function get_security_blob(security_blob, ip, username, domain, password, passwo
lanman,
ntlm,
session_key)
return true, new_blob, mac_key
end
@@ -731,7 +731,7 @@ function get_host_info_from_security_blob(security_blob)
local ntlm_challenge = {}
--local pos, identifier, message_type, domain_length, domain_max, domain_offset, server_flags, challenge, reserved, target_info_length, target_info_max, target_info_offset = bin.unpack("<A8ISSIILLSSI", security_blob)
local pos, identifier, message_type, domain_length, domain_max, domain_offset, server_flags, challenge, reserved, target_info_length, target_info_max, target_info_offset = bin.unpack("<A8ISSIILLSSI", security_blob)
-- Do some validation on the NTLMSSP message
if ( identifier ~= "NTLMSSP\0" ) then
stdnse.print_debug( 1, "SMB: Invalid NTLM challenge message: unexpected signature." )
@@ -741,7 +741,7 @@ function get_host_info_from_security_blob(security_blob)
stdnse.print_debug( 1, "SMB: Invalid NTLM challenge message: unexpected message type: %d.", message_type )
return false, "Invalid message type in NTLM challenge message"
end
-- Parse the TargetName data (i.e. the server authentication realm)
if ( domain_length > 0 ) then
local length = domain_length
@@ -750,10 +750,10 @@ function get_host_info_from_security_blob(security_blob)
pos, target_realm = bin.unpack( string.format( "A%d", length ), security_blob, pos )
ntlm_challenge[ "target_realm" ] = from_unicode( target_realm )
end
-- Parse the TargetInfo data (Wireshark calls this the "Address List")
if ( target_info_length > 0 ) then
-- Definition of AvId values (IDs for AV_PAIR (attribute-value pair) structures),
-- as definied by the NTLM Authentication Protocol specification [MS-NLMP].
local NTLM_AV_ID_VALUES = {
@@ -779,20 +779,20 @@ function get_host_info_from_security_blob(security_blob)
[NTLM_AV_ID_VALUES.MsvAvDnsTreeName] = "dns_forest_name",
[NTLM_AV_ID_VALUES.MsvAvTimestamp] = "timestamp",
}
local length = target_info_length
local pos = target_info_offset + 1 -- +1 to convert to Lua's 1-based indexes
local target_info
pos, target_info = bin.unpack( string.format( "A%d", length ), security_blob, pos )
pos = 1 -- reset pos to 1, since we'll be working out of just the target_info
repeat
local value, av_id, av_len
pos, av_id, av_len = bin.unpack( "<SS", target_info, pos )
pos, value = bin.unpack( string.format( "A%d", av_len ), target_info, pos )
local friendly_name = NTLM_AV_ID_NAMES[ av_id ]
if ( av_id == NTLM_AV_ID_VALUES.MsvAvEOL ) then
break
elseif ( av_id == NTLM_AV_ID_VALUES.MsvAvTimestamp ) then
@@ -803,16 +803,16 @@ function get_host_info_from_security_blob(security_blob)
end
until ( pos >= #target_info )
end
return ntlm_challenge
end
---Create an 8-byte message signature that's sent with all SMB packets.
---Create an 8-byte message signature that's sent with all SMB packets.
--
--@param mac_key The key used for authentication. It's the concatination of the session key and the
-- response hash.
-- response hash.
--@param data The packet to generate the signature for. This should be the packet that's about to be
-- sent, except with the signature slot replaced with the sequence number.
-- sent, except with the signature slot replaced with the sequence number.
--@return The 8-byte signature. The signature is equal to the first eight bytes of md5(mac_key .. smb_data)
function calculate_signature(mac_key, data)
if(have_ssl) then

View File

@@ -162,7 +162,7 @@ local SMTP_CMD = {
-- Returns a domain to be used in the SMTP commands that need it. If the
-- user specified one through the script argument <code>smtp.domain</code>
-- this function will return it. Otherwise it will try to find the domain
-- from the typed hostname and from the rDNS name. If it still can't find
-- from the typed hostname and from the rDNS name. If it still can't find
-- one it will return the nmap.scanme.org by default.
--
-- @param host The host table
@@ -290,7 +290,7 @@ connect = function(host, port, opts)
if opts.ssl then
local socket, _, _, ret = comm.tryssl(host, port, '', opts)
if not socket then
return socket, (ERROR_MESSAGES[ret] or 'unspecified error')
return socket, (ERROR_MESSAGES[ret] or 'unspecified error')
end
return socket, ret
else
@@ -324,7 +324,7 @@ end
--- Switches the plain text connection to be protected by the TLS protocol
-- by using the SMTP STARTTLS command.
--
--
-- The socket will be reconnected by using SSL. On network errors or if the
-- SMTP command fails, the connection will be closed and the socket cleared.
--
@@ -334,7 +334,7 @@ end
-- to the client's STARTTLS command, or an error message on failures.
starttls = function(socket)
local st, reply, ret
st, reply = query(socket, "STARTTLS")
if not st then
return st, reply
@@ -356,7 +356,7 @@ starttls = function(socket)
end
--- Sends the EHLO command to the SMTP server.
--
--
-- On network errors or if the SMTP command fails, the connection
-- will be closed and the socket cleared.
--
@@ -382,7 +382,7 @@ ehlo = function(socket, domain)
end
--- Sends the HELP command to the SMTP server.
--
--
-- On network errors or if the SMTP command fails, the connection
-- will be closed and the socket cleared.
--
@@ -565,7 +565,7 @@ end
verify = function(socket, mailbox)
local st, ret, response
st, response = query(socket, "VRFY", mailbox)
st, ret = check_reply("VRFY", response)
if not st then
quit(socket)
@@ -596,7 +596,7 @@ end
-- error message on failures.
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",
("Unsupported authentication mechanism (%s)"):format(mech or "nil"))
local status, response = query(socket, "AUTH", mech)
@@ -634,16 +634,16 @@ login = function(socket, username, password, mech)
end
return false, response
end
if ( mech == "NTLM" ) then
-- sniffed of the wire, seems to always be the same
-- decodes to some NTLMSSP blob greatness
status, response = query(socket, "TlRMTVNTUAABAAAAB7IIogYABgA3AAAADwAPACgAAAAFASgKAAAAD0FCVVNFLUFJUi5MT0NBTERPTUFJTg==")
if ( not(status) ) then return false, "ERROR: Failed to receieve NTLM challenge" end
if ( not(status) ) then return false, "ERROR: Failed to receieve NTLM challenge" end
end
local chall = response:match("^334 (.*)")
chall = (chall and base64.dec(chall))
if (not(chall)) then return false, "ERROR: Failed to retrieve challenge" end
@@ -653,12 +653,12 @@ login = function(socket, username, password, mech)
local mech_params = { username, password, chall, "smtp" }
local auth_data = sasl.Helper:new(mech):encode(table.unpack(mech_params))
auth_data = base64.enc(auth_data)
status, response = query(socket, auth_data)
if ( not(status) ) then
return false, ("ERROR: Failed to authenticate using SASL %s"):format(mech)
end
if ( mech == "DIGEST-MD5" ) then
local rspauth = response:match("^334 (.*)")
if ( rspauth ) then
@@ -666,9 +666,9 @@ login = function(socket, username, password, mech)
status, response = query(socket,"")
end
end
if ( response:match("^235") ) then return true, "Login success" end
return false, response
end

View File

@@ -29,26 +29,26 @@ tagEncoder['table'] = function(self, val)
local oidStr = string.char(val[1]*40 + val[2])
for i = 3, #val do
oidStr = oidStr .. self.encode_oid_component(val[i])
end
return bin.pack("HAA", '06', self.encodeLength(#oidStr), oidStr)
end
return bin.pack("HAA", '06', self.encodeLength(#oidStr), oidStr)
elseif (val._snmp == '40') then -- ipAddress
return bin.pack("HC4", '40 04', table.unpack(val))
-- counter or gauge or timeticks or opaque
elseif (val._snmp == '41' or val._snmp == '42' or val._snmp == '43' or val._snmp == '44') then
local val = self:encodeInt(val[1])
return bin.pack("HAA", val._snmp, self.encodeLength(#val), val)
end
local encVal = ""
for _, v in ipairs(val) do
encVal = encVal .. self:encode(v) -- todo: buffer?
end
local tableType = bin.pack("H", "30")
if (val["_snmp"]) then
tableType = bin.pack("H", val["_snmp"])
if (val["_snmp"]) then
tableType = bin.pack("H", val["_snmp"])
end
return bin.pack('AAA', tableType, self.encodeLength(#encVal), encVal)
end
@@ -62,14 +62,14 @@ function encode(val)
local vtype = type(val)
local encoder = asn1.ASN1Encoder:new()
encoder:registerTagEncoders( tagEncoder )
local encVal = encoder:encode(val)
if encVal then
return encVal
end
return ''
end
@@ -84,7 +84,7 @@ local tagDecoder = {}
-- TOOD: Figure out how to remove these dependancies
tagDecoder["A2"] = function( self, encStr, elen, pos )
local seq = {}
pos, seq = self:decodeSeq(encStr, elen, pos)
seq._snmp = "A2"
return pos, seq
@@ -106,7 +106,7 @@ end
-- @return The decoded value(s).
function decode(encStr, pos)
local decoder = asn1.ASN1Decoder:new()
if ( #tagDecoder == 0 ) then
decoder:registerBaseDecoders()
-- Application specific tags
@@ -129,8 +129,8 @@ function decode(encStr, pos)
tagDecoder["A6"] = decoder.decoder["30"] -- InformRequest-PDU (not implemented here yet)
tagDecoder["A7"] = decoder.decoder["30"] -- SNMPv2-Trap-PDU (not implemented here yet)
end
decoder:registerTagDecoders( tagDecoder )
return decoder:decode( encStr, pos )
@@ -170,7 +170,7 @@ function buildPacket(PDU, version, commStr)
end
---
---
-- Create an SNMP Get Request PDU.
-- @param options A table containing the following fields:
-- * <code>"reqId"</code>: Request ID.
@@ -190,7 +190,7 @@ function buildGetRequest(options, ...)
req[1] = options.reqId
req[2] = options.err
req[3] = options.errIdx
local payload = {}
for i=1, select('#', ...) do
payload[i] = {}
@@ -205,7 +205,7 @@ function buildGetRequest(options, ...)
end
---
---
-- Create an SNMP Get Next Request PDU.
-- @param options A table containing the following fields:
-- * <code>"reqId"</code>: Request ID.
@@ -225,7 +225,7 @@ function buildGetNextRequest(options, ...)
req[1] = options.reqId
req[2] = options.err
req[3] = options.errIdx
local payload = {}
for i=1, select('#', ...) do
payload[i] = {}
@@ -239,7 +239,7 @@ function buildGetNextRequest(options, ...)
return req
end
---
---
-- Create an SNMP Set Request PDU.
--
-- Takes one OID/value pair or an already prepared table.
@@ -266,7 +266,7 @@ function buildSetRequest(options, oid, value)
if (type(value) == "table") then
req[4] = value
else
else
local payload = {}
if (type(oid) == "string") then
payload[1] = str2oid(oid)
@@ -280,13 +280,13 @@ function buildSetRequest(options, oid, value)
return req
end
---
---
-- Create an SNMP Trap PDU.
-- @return Table representing PDU
function buildTrap(enterpriseOid, agentIp, genTrap, specTrap, timeStamp)
local req = {}
req._snmp = 'A4'
if (type(enterpriseOid) == "string") then
if (type(enterpriseOid) == "string") then
req[1] = str2oid(enterpriseOid)
else
req[1] = enterpriseOid
@@ -308,7 +308,7 @@ function buildTrap(enterpriseOid, agentIp, genTrap, specTrap, timeStamp)
return req
end
---
---
-- Create an SNMP Get Response PDU.
--
-- Takes one OID/value pair or an already prepared table.
@@ -319,7 +319,7 @@ end
-- @param oid Object identifiers of object to be sent back.
-- @param value If given a table, use the table instead of OID/value pair.
-- @return Table representing PDU.
function buildGetResponse(options, oid, value)
function buildGetResponse(options, oid, value)
if not options then options = {} end
-- if really a response, should use reqId of request!
@@ -335,7 +335,7 @@ function buildGetResponse(options, oid, value)
if (type(value) == "table") then
resp[4] = value
else
else
local payload = {}
if (type(oid) == "string") then
@@ -350,7 +350,7 @@ function buildGetResponse(options, oid, value)
return resp
end
---
---
-- Transforms a string into an object identifier table.
-- @param oidStr Object identifier as string, for example
-- <code>"1.3.6.1.2.1.1.1.0"</code>.
@@ -407,7 +407,7 @@ function fetchResponseValues(resp)
_, resp = decode(resp)
end
if (type(resp) ~= "table") then
if (type(resp) ~= "table") then
return {}
end
@@ -452,7 +452,7 @@ function fetchFirst(response)
if type(result) == "table" and result[1] and result[1][1] then
return result[1][1]
else
else
return nil
end
end
@@ -465,13 +465,13 @@ end
-- @return status true on success, false on failure
-- @return table containing <code>oid</code> and <code>value</code>
function snmpWalk( socket, base_oid )
local snmp_table = {}
local oid = base_oid
local status, err, payload
while ( true ) do
local value, response, snmpdata, options, item = nil, nil, nil, {}, {}
payload = encode( buildPacket( buildGetNextRequest(options, oid) ) )
@@ -480,8 +480,8 @@ function snmpWalk( socket, base_oid )
stdnse.print_debug("snmp.snmpWalk: Send failed")
return false, err
end
status, response = socket:receive_bytes(1)
status, response = socket:receive_bytes(1)
if ( not( status ) ) then
-- Unless we don't have a usefull error message, don't report it
if ( response ~= "ERROR" ) then
@@ -490,27 +490,27 @@ function snmpWalk( socket, base_oid )
end
return false, nil
end
snmpdata = fetchResponseValues( response )
value = snmpdata[1][1]
oid = snmpdata[1][2]
if not oid:match( base_oid ) or base_oid == oid then
break
end
item.oid = oid
item.value = value
table.insert( snmp_table, item )
end
snmp_table.baseoid = base_oid
return true, snmp_table
end
return _ENV;

View File

@@ -18,15 +18,15 @@ AuthMethod = {
}
Request = {
-- Class that handles the connection request to the server
Connect = {
-- Creates a new instance of the class
-- @param auth_method table of requested authentication methods
-- @return o instance on success, nil on failure
new = function(self, auth_method)
local o = {
local o = {
version = 5,
auth_method = ( "table" ~= type(auth_method) and { auth_method } or auth_method )
}
@@ -34,7 +34,7 @@ Request = {
self.__index = self
return o
end,
-- Converts the instance to string, so that it can be sent to the
-- server.
-- @return string containing the raw request
@@ -42,15 +42,15 @@ Request = {
local methods = ""
for _, m in ipairs(self.auth_method) do
methods = methods .. string.char(m)
end
end
return bin.pack("Cp", self.version, methods)
end,
end,
},
-- Class that handles the authentication request to the server
Authenticate = {
-- Creates a new instance of the class
-- @param auth_method number with the requested authentication method
-- @param creds method specific table of credentials
@@ -59,7 +59,7 @@ Request = {
-- <code>username</code> and <code>password</code>
-- @return o instance on success, nil on failure
new = function(self, auth_method, creds)
local o = {
local o = {
auth_method = auth_method,
creds = creds
}
@@ -69,7 +69,7 @@ Request = {
return o
end
end,
-- Converts the instance to string, so that it can be sent to the
-- server.
-- @return string containing the raw request
@@ -87,16 +87,16 @@ Request = {
return bin.pack("Cpp", version, username, password)
end
end,
}
}
Response = {
-- Class that handles the connection response
Connect = {
-- Creates a new instance of the class
-- @param data string containing the data as received over the socket
-- @return o instance on success, nil on failure
@@ -108,7 +108,7 @@ Response = {
return o
end
end,
-- Parses the received data and populates member variables
-- @return true on success, false on failure
parse = function(self)
@@ -116,21 +116,21 @@ Response = {
return
end
local pos
pos, self.version, self.method = bin.unpack("CC", self.data)
pos, self.version, self.method = bin.unpack("CC", self.data)
return true
end
},
-- Class that handles the authentication response
Authenticate = {
Status = {
SUCCESS = 0,
-- could be anything but zero
FAIL = 1,
},
-- Creates a new instance of the class
-- @param data string containing the data as received over the socket
-- @return o instance on success, nil on failure
@@ -142,7 +142,7 @@ Response = {
return o
end
end,
-- Parses the received data and populates member variables
-- @return true on success, false on failure
parse = function(self)
@@ -150,25 +150,25 @@ Response = {
return
end
local pos
pos, self.version, self.status = bin.unpack("CC", self.data)
pos, self.version, self.status = bin.unpack("CC", self.data)
return true
end,
-- checks if the authentication was successful or not
-- @return true on success, false on failure
isSuccess = function(self)
return ( self.status == self.Status.SUCCESS )
end,
end,
}
}
-- A buffered socket implementation
Socket =
{
{
retries = 3,
-- Creates a new socket instance
-- @param host table containing the host table
-- @param port table containing the port table
@@ -176,8 +176,8 @@ Socket =
-- <code>timeout</code> - socket timeout in ms
-- @return o new instance of Socket
new = function(self, host, port, options)
local o = {
host = host,
local o = {
host = host,
port = port,
options = options or {}
}
@@ -187,7 +187,7 @@ Socket =
o.Buffer = nil
return o
end,
-- Connects the socket to the server
-- @return status true on success false on failure
-- @return err string containing error message on failure
@@ -195,7 +195,7 @@ Socket =
self.Socket:set_timeout(self.options.timeout or 10000)
return self.Socket:connect( self.host, self.port )
end,
-- Closes an open connection.
--
-- @return Status (true or false).
@@ -203,7 +203,7 @@ Socket =
close = function( self )
return self.Socket:close()
end,
-- Opposed to the <code>socket:receive_bytes</code> function, that returns
-- at least x bytes, this function returns the amount of bytes requested.
--
@@ -213,9 +213,9 @@ Socket =
-- err containing error message if status is false
recv = function( self, count )
local status, data
self.Buffer = self.Buffer or ""
if ( #self.Buffer < count ) then
status, data = self.Socket:receive_bytes( count - #self.Buffer )
if ( not(status) or #data < count - #self.Buffer ) then
@@ -223,13 +223,13 @@ Socket =
end
self.Buffer = self.Buffer .. data
end
data = self.Buffer:sub( 1, count )
self.Buffer = self.Buffer:sub( count + 1)
return true, data
return true, data
end,
-- Sends data over the socket
--
-- @return Status (true or false).
@@ -242,7 +242,7 @@ Socket =
-- The main script interface
Helper = {
-- Create a new instance of the class
-- @param host table containing the host table
-- @param port table containing the port table
@@ -255,7 +255,7 @@ Helper = {
self.__index = self
return o
end,
-- Get the authentication method name by number
-- @param method number containing the authentication method
-- @return string containing the method name or Unknown
@@ -267,31 +267,31 @@ Helper = {
}
return methods[method] or ("Unknown method (%d)"):format(method)
end,
-- Connects to the SOCKS server
-- @param auth_method table containing the auth. methods to request
-- @return status true on success, false on failure
-- @return response table containing the respons or err string on failure
connect = function(self, auth_method)
self.socket = Socket:new(self.host, self.port, self.options)
self.socket = Socket:new(self.host, self.port, self.options)
local status, err = self.socket:connect()
if ( not(status) ) then
return status, err
end
auth_method = auth_method or {AuthMethod.NONE, AuthMethod.GSSAPI, AuthMethod.USERPASS}
status = self.socket:send( tostring(Request.Connect:new(auth_method)) )
if ( not(status) ) then
self.socket:close()
return false, "Failed to send connection request to server"
end
local status, data = self.socket:recv(2)
if ( not(status) ) then
self.socket:close()
return false, "Failed to receive connection response from server"
end
local response = Response.Connect:new(data)
if ( not(response) ) then
return false, "Failed to parse response from server"
@@ -303,12 +303,12 @@ Helper = {
if ( response.method == 0xFF ) then
return false, "No acceptable authentication methods"
end
-- store the method so authenticate knows what to use
self.auth_method = response.method
return true, response
end,
-- Authenticates to the SOCKS server
-- @param creds table containing authentication method specific fields
-- currently only authentication method 2 (username and pass) is
@@ -325,20 +325,20 @@ Helper = {
if ( not(req) ) then
return false, "Failed to create authentication request"
end
local status = self.socket:send(tostring(req))
if ( not(status) ) then
return false, "Failed to send authentication request"
end
if ( 2 == self.auth_method ) then
local status, data = self.socket:recv(2)
local auth = Response.Authenticate:new(data)
if ( not(auth) ) then
return false, "Failed to parse authentication response"
end
if ( auth:isSuccess() ) then
return true, "Authentication was successfull"
else
@@ -353,7 +353,7 @@ Helper = {
close = function(self)
return self.socket:close()
end,
}
return _ENV;

View File

@@ -5,7 +5,7 @@
-- The implementation is based on the following classes:
-- * Request.Service
-- - Contains necessary code to produce a service request
--
--
-- * Request.Attributes
-- - Contains necessary code to produce a attribute request
--
@@ -58,17 +58,17 @@ Reply = {
o:parse(data)
return o
end,
--- Parses the service reply raw packet data
-- @param data string containing the raw reply as read from the socket
parse = function(self, data)
local pos
local len_hi, len_lo
pos, self.version, self.func, len_hi, len_lo = bin.unpack(">CCCS", data)
self.len = bit.lshift(len_hi, 16) + len_lo
pos, self.flags = bin.unpack(">S", data, pos)
local neo_hi, neo_lo
pos, neo_hi, neo_lo = bin.unpack(">CS", data, pos)
self.next_extension_offset = bit.lshift(neo_hi, 16) + neo_lo
@@ -76,10 +76,10 @@ Reply = {
local lang_tag_len
pos, self.xid, lang_tag_len = bin.unpack(">SS", data, pos)
pos, self.lang_tag = bin.unpack("A" .. lang_tag_len, data, pos)
local no_urls, reserved, url_len
pos, self.error_code, no_urls = bin.unpack(">SS", data, pos)
if ( no_urls > 0 ) then
pos, reserved, self.url_lifetime, url_len = bin.unpack(">CSS", data, pos)
@@ -87,7 +87,7 @@ Reply = {
pos, self.url, num_auths = bin.unpack("A" .. url_len .. "C", data, pos)
end
end,
--- Attempts to create an instance by reading data off the socket
-- @param socket socket conected to the SRVLOC service
-- @return new instance of the Reply.Service class
@@ -96,7 +96,7 @@ Reply = {
if ( not(status) ) then return end
return Reply.Service:new(data)
end,
--- Gets the url value from the reply
-- @return uri string containing the reply url
getUrl = function(self) return self.url end,
@@ -152,21 +152,21 @@ Reply = {
end,
--- Gets the attribute list
-- @return attrib_list
-- @return attrib_list
getAttribList = function(self) return self.attrib_list end,
}
}
Request = {
-- The attribute request
Attribute = {
--- Creates a new instance of the Attribue request
-- @return o instance of Attribute
new = function(self)
local o = {
local o = {
lang_tag = "en", version = 2, service_type = "",
scope = "", next_extension_offset = 0,
prev_resp_list_len = 0, slp_spi_len = 0 }
@@ -186,7 +186,7 @@ Request = {
--- Sets the request flags
-- @param flags number containing the numeric flag representation
setFlags = function(self, flags) self.flags = flags end,
--- Sets the request XID
-- @param xid number containing the request XID
setXID = function(self, xid) self.xid = xid end,
@@ -194,11 +194,11 @@ Request = {
--- Sets the request function
-- @param func number containing the request function number
setFunction = function(self, func) self.func = func end,
--- Sets the request taglist
-- @param tl string containing the taglist
setTagList = function(self, tl) self.tag_list = tl end,
--- Sets the request url
-- @param u string containing the url
setUrl = function(self, u) self.url = u end,
@@ -208,17 +208,17 @@ Request = {
__tostring = function(self)
assert(self.func, "Packet function was not specified")
assert(self.scope, "Packet scope was not specified")
local BASE_LEN = 24
local len = BASE_LEN + #self.lang_tag + self.prev_resp_list_len +
self.slp_spi_len + #self.service_type + #self.url +
self.slp_spi_len + #self.service_type + #self.url +
#self.tag_list + #self.scope
local len_hi = bit.band(bit.rshift(len, 16), 0x00FF)
local len_lo = bit.band(len, 0xFFFF)
local neo_hi = bit.band(bit.rshift(self.next_extension_offset, 16),
0x00FF)
local neo_lo = bit.band(self.next_extension_offset, 0xFFFF)
local data = bin.pack(">CCCSSCSSSASSASASAS", self.version, self.func,
len_hi, len_lo, self.flags, neo_hi, neo_lo, self.xid, #self.lang_tag, self.lang_tag,
self.prev_resp_list_len, #self.url, self.url, #self.scope, self.scope,
@@ -227,14 +227,14 @@ Request = {
return data
end
},
-- The Service request
Service = {
--- Creates a new instance of the Service request
-- @return o instance of Service
new = function(self)
local o = {
local o = {
lang_tag = "en", version = 2, service_type = "",
scope = "", next_extension_offset = 0,
prev_resp_list_len = 0, predicate_len = 0, slp_spi_len = 0 }
@@ -246,7 +246,7 @@ Request = {
--- Sets the service type of the request
-- @param t string containing the type of the request
setServiceType = function(self, t) self.service_type = t end,
--- Sets the request scope
-- @param scope string containing the request scope
setScope = function(self, scope) self.scope = scope end,
@@ -258,7 +258,7 @@ Request = {
--- Sets the request flags
-- @param flags number containing the numeric flag representation
setFlags = function(self, flags) self.flags = flags end,
--- Sets the request XID
-- @param xid number containing the request XID
setXID = function(self, xid) self.xid = xid end,
@@ -291,13 +291,13 @@ Request = {
return data
end
}
}
-- The Helper class serves as primary interface for scripts using the libraryy
Helper = {
new = function(self, host, port)
local o = { xid = 1, socket = nmap.new_socket("udp") }
setmetatable(o, self)
@@ -326,7 +326,7 @@ Helper = {
self.socket:set_timeout(5000)
self.socket:sendto( self.host, self.port, tostring(sr) )
local result = {}
repeat
local r = Reply.Service.fromSocket(self.socket)
@@ -335,13 +335,13 @@ Helper = {
end
self.xid = self.xid + 1
until(not(r))
if ( #result == 0 ) then
return false, "ERROR: Helper.Locate no response received"
end
return true, result
end,
--- Requests an attribute from the server
-- @param url as retrieved by the Service request
-- @param scope string containing the request scope
@@ -360,16 +360,16 @@ Helper = {
self.socket:set_timeout(5000)
self.socket:sendto( self.host, self.port, tostring(ar) )
local r = Reply.Attribute.fromSocket(self.socket)
self.xid = self.xid + 1
if ( not(r) ) then
return false, "ERROR: Helper.Locate no response received"
end
return true, r:getAttribList()
end,
close = function(self)
return self.socket:close()
end,

View File

@@ -20,7 +20,7 @@ _ENV = stdnse.module("ssh1", stdnse.seeall)
--- Retrieve the size of the packet that is being received
-- and checks if it is fully received
--
--
-- This function is very similar to the function generated
-- with match.numbytes(num) function, except that this one
-- will check for the number of bytes on-the-fly, based on
@@ -179,10 +179,10 @@ fingerprint_visual = function( fingerprint, algorithm, bits )
local x, y = math.ceil(fieldsize_x/2), math.ceil(fieldsize_y/2)
field[x][y] = #characters - 1;
-- iterate over fingerprint
-- iterate over fingerprint
for i=1,#fingerprint do
input = fingerprint:byte(i)
-- each byte conveys four 2-bit move commands
-- each byte conveys four 2-bit move commands
for j=1,4 do
if bit.band( input, 1) == 1 then x = x + 1 else x = x - 1 end
if bit.band( input, 2) == 2 then y = y + 1 else y = y - 1 end

View File

@@ -20,7 +20,7 @@ local SSH2
--- Retrieve the size of the packet that is being received
-- and checks if it is fully received
--
--
-- This function is very similar to the function generated
-- with match.numbytes(num) function, except that this one
-- will check for the number of bytes on-the-fly, based on
@@ -122,7 +122,7 @@ end
--- Parse a <code>kexinit</code> package.
--
-- Returns an empty table in case of an error
transport.parse_kex_init = function( payload )
transport.parse_kex_init = function( payload )
local _, offset, msg_code, parsed, fields, fieldname
parsed = {}

View File

@@ -15,7 +15,7 @@ local xmpp = require "xmpp"
_ENV = stdnse.module("sslcert", stdnse.seeall)
StartTLS = {
ftp_prepare_tls_without_reconnect = function(host, port)
local s = nmap.new_socket()
-- Attempt to negotiate TLS over FTP for services that support it
@@ -56,7 +56,7 @@ StartTLS = {
-- Should have a solid TLS over FTP session now...
return true, s
end,
ftp_prepare_tls = function(host, port)
local err
local status, s = StartTLS.ftp_prepare_tls_without_reconnect(host, port)
@@ -66,7 +66,7 @@ StartTLS = {
stdnse.print_debug("1","Could not establish SSL session after STARTTLS command.")
s:close()
return false, "Failed to connect to SMTP server"
else
else
return true,s
end
end
@@ -79,11 +79,11 @@ StartTLS = {
-- Works for SMTP (25) and SMTP Submission (587)
-- Open a standard TCP socket
local status, error = s:connect(host, port, "tcp")
local status, error = s:connect(host, port, "tcp")
if not status then
if not status then
return nil
else
else
local resultEHLO
-- Loop until the service presents a banner to deal with server
-- load and timing issues. There may be a better way to handle this.
@@ -108,7 +108,7 @@ StartTLS = {
resultEHLO = ""
-- Send STARTTLS command ask the service to start encryption
-- Send STARTTLS command ask the service to start encryption
local query = "STARTTLS\r\n"
status = s:send(query)
status, resultEHLO = s:receive_lines(1)
@@ -119,16 +119,16 @@ StartTLS = {
-- Send QUIT to clean up server side connection
local query = "QUIT\r\n"
status = s:send(query)
status = s:send(query)
resultEHLO = ""
return false, "Failed to connect to SMTP server"
end
end
end
-- Should have a solid TLS over SMTP session now...
return true, s
end,
smtp_prepare_tls = function(host, port)
local err
local status,s = StartTLS.smtp_prepare_tls_without_reconnect(host, port)
@@ -138,7 +138,7 @@ StartTLS = {
stdnse.print_debug("1","Could not establish SSL session after STARTTLS command.")
s:close()
return false, "Failed to connect to SMTP server"
else
else
return true,s
end
end
@@ -156,7 +156,7 @@ StartTLS = {
sock:close()
stdnse.print_debug("Can't send: %s", err)
return false, "Failed to connect to XMPP server"
end
end
status, err = sock:send(xmppStreamStart)
if not status then
stdnse.print_debug("Couldn't send: %s", err)
@@ -168,7 +168,7 @@ StartTLS = {
stdnse.print_debug("Couldn't receive: %s", err)
sock:close()
return false, "Failed to connect to XMPP server"
end
end
status, err = sock:send(xmppStartTLS)
if not status then
stdnse.print_debug("Couldn't send: %s", err)
@@ -180,24 +180,24 @@ StartTLS = {
stdnse.print_debug("Couldn't receive: %s", err)
sock:close()
return false, "Failed to connect to XMPP server"
end
end
if string.find(result,"proceed") then
return true,sock
end
end
status, result = sock:receive() -- might not be in the first reply
if not status then
stdnse.print_debug("Couldn't receive: %s", err)
sock:close()
return false, "Failed to connect to XMPP server"
end
end
if string.find(result,"proceed") then
return true,sock
else
else
return false, "Failed to connect to XMPP server"
end
end
end,
xmpp_prepare_tls = function(host, port)
local ls = xmpp.XMPP:new(host, port, { starttls = true } )
ls.socket = nmap.new_socket()
@@ -213,7 +213,7 @@ StartTLS = {
return false, "Failed to connected"
end
return true, ls.socket
end
end
}
-- A table mapping port numbers to specialized SSL negotiation functions.
@@ -251,14 +251,14 @@ end
function getCertificate(host, port)
local mutex = nmap.mutex("sslcert-cache-mutex")
mutex "lock"
if ( host.registry["ssl-cert"] and
host.registry["ssl-cert"][port.number] ) then
stdnse.print_debug(2, "sslcert: Returning cached SSL certificate")
mutex "done"
return true, host.registry["ssl-cert"][port.number]
end
-- Is there a specialized function for this port?
local specialized = SPECIALIZED_PREPARE_TLS[port.number]
local status
@@ -276,12 +276,12 @@ function getCertificate(host, port)
mutex "done"
return false, "Failed to connect to server"
end
end
end
local cert = socket:get_ssl_certificate()
if ( cert == nil ) then
return false, "Unable to get cert"
end
host.registry["ssl-cert"] = host.registry["ssl-cert"] or {}
host.registry["ssl-cert"][port.number] = host.registry["ssl-cert"][port.number] or {}
host.registry["ssl-cert"][port.number] = cert

View File

@@ -60,7 +60,7 @@ _ENV.sleep = nmap.socket.sleep;
---
-- Prints a formatted debug message if the current debugging level is greater
-- than or equal to a given level.
--
--
-- This is a convenience wrapper around
-- <code>nmap.log_write</code>. The first optional numeric
-- argument, <code>level</code>, is used as the debugging level necessary
@@ -81,7 +81,7 @@ end
---
-- Prints a formatted verbosity message if the current verbosity level is greater
-- than or equal to a given level.
--
--
-- This is a convenience wrapper around
-- <code>nmap.log_write</code>. The first optional numeric
-- argument, <code>level</code>, is used as the verbosity level necessary
@@ -101,7 +101,7 @@ end
--- Join a list of strings with a separator string.
--
--
-- This is Lua's <code>table.concat</code> function with the parameters
-- swapped for coherence.
-- @usage
@@ -112,7 +112,7 @@ end
-- @return Concatenated string.
function strjoin(delimiter, list)
assert(type(delimiter) == "string" or type(delimiter) == nil, "delimiter is of the wrong type! (did you get the parameters backward?)")
return concat(list, delimiter);
end
@@ -167,7 +167,7 @@ end
--- Return a wrapper closure around a socket that buffers socket reads into
-- chunks separated by a pattern.
--
--
-- This function operates on a socket attempting to read data. It separates the
-- data by <code>sep</code> and, for each invocation, returns a piece of the
-- separated data. Typically this is used to iterate over the lines of data
@@ -274,7 +274,7 @@ end
-- @param s String or number to be encoded.
-- @param options Table specifiying formatting options.
-- @return String in hexadecimal format.
function tohex( s, options )
function tohex( s, options )
options = options or EMPTY
local separator = options.separator
local hex
@@ -539,7 +539,7 @@ function clock_us()
return nmap.clock() * 1000000
end
---Get the indentation symbols at a given level.
---Get the indentation symbols at a given level.
local function format_get_indent(indent, at_end)
local str = ""
local had_continue = false
@@ -642,7 +642,7 @@ local function format_output_sub(status, data, indent)
end
insert(output, format_output_sub(status, value, new_indent))
elseif(type(value) == 'string') then
local lines = splitlines(value)
@@ -657,30 +657,30 @@ local function format_output_sub(status, data, indent)
return concat(output)
end
---Takes a table of output on the commandline and formats it for display to the
-- user. This is basically done by converting an array of nested tables into a
-- string. In addition to numbered array elements, each table can have a 'name'
-- and a 'warning' value. The 'name' will be displayed above the table, and
---Takes a table of output on the commandline and formats it for display to the
-- user. This is basically done by converting an array of nested tables into a
-- string. In addition to numbered array elements, each table can have a 'name'
-- and a 'warning' value. The 'name' will be displayed above the table, and
-- 'warning' will be displayed, with a 'WARNING' tag, if and only if debugging
-- is enabled.
--
-- is enabled.
--
-- Here's an example of a table:
-- <code>
-- local domains = {}
-- domains['name'] = "DOMAINS"
-- table.insert(domains, 'Domain 1')
-- table.insert(domains, 'Domain 2')
--
--
-- local names = {}
-- names['name'] = "NAMES"
-- names['warning'] = "Not all names could be determined!"
-- table.insert(names, "Name 1")
--
--
-- local response = {}
-- table.insert(response, "Apple pie")
-- table.insert(response, domains)
-- table.insert(response, names)
--
--
-- return stdnse.format_output(true, response)
-- </code>
--
@@ -696,13 +696,13 @@ end
-- |_ Name 1
-- </code>
--
--@param status A boolean value dictating whether or not the script succeeded.
--@param status A boolean value dictating whether or not the script succeeded.
-- If status is false, and debugging is enabled, 'ERROR' is prepended
-- to every line. If status is false and debugging is disabled, no output
-- occurs.
--@param data The table of output.
-- occurs.
--@param data The table of output.
--@param indent Used for indentation on recursive calls; should generally be set to
-- nil when callling from a script.
-- nil when callling from a script.
-- @return <code>nil</code>, if <code>data</code> is empty, otherwise a
-- multiline string.
function format_output(status, data, indent)
@@ -772,7 +772,7 @@ end
function get_script_args (...)
local args = {}
for i, set in ipairs({...}) do
for i, set in ipairs({...}) do
if type(set) == "string" then
set = {set}
end
@@ -788,10 +788,10 @@ function get_script_args (...)
return unpack(args, 1, select("#", ...))
end
---Get the best possible hostname for the given host. This can be the target as given on
-- the commandline, the reverse dns name, or simply the ip address.
--@param host The host table (or a string that'll simply be returned).
--@return The best possible hostname, as a string.
---Get the best possible hostname for the given host. This can be the target as given on
-- the commandline, the reverse dns name, or simply the ip address.
--@param host The host table (or a string that'll simply be returned).
--@return The best possible hostname, as a string.
function get_hostname(host)
if type(host) == "table" then
return host.targetname or ( host.name ~= '' and host.name ) or host.ip
@@ -801,7 +801,7 @@ function get_hostname(host)
end
---Retrieve an item from the registry, checking if each sub-key exists. If any key doesn't
-- exist, return nil.
-- exist, return nil.
function registry_get(subkeys)
local registry = nmap.registry
local i = 1
@@ -819,7 +819,7 @@ function registry_get(subkeys)
return registry
end
--Check if the given element exists in the registry. If 'key' is nil, it isn't checked.
--Check if the given element exists in the registry. If 'key' is nil, it isn't checked.
function registry_exists(subkeys, key, value)
local subkey = registry_get(subkeys)
@@ -836,12 +836,12 @@ function registry_exists(subkeys, key, value)
return false
end
---Add an item to an array in the registry, creating all sub-keys if necessary.
---Add an item to an array in the registry, creating all sub-keys if necessary.
-- For example, calling:
-- <code>registry_add_array({'192.168.1.100', 'www', '80', 'pages'}, 'index.html')</code>
-- Will create nmap.registry['192.168.1.100'] as a table, if necessary, then add a table
-- under the 'www' key, and so on. 'pages', finally, is treated as an array and the value
-- given is added to the end.
-- given is added to the end.
function registry_add_array(subkeys, value, allow_duplicates)
local registry = nmap.registry
local i = 1
@@ -871,7 +871,7 @@ function registry_add_array(subkeys, value, allow_duplicates)
end
---Similar to <code>registry_add_array</code>, except instead of adding a value to the
-- end of an array, it adds a key:value pair to the table.
-- end of an array, it adds a key:value pair to the table.
function registry_add_table(subkeys, key, value, allow_duplicates)
local registry = nmap.registry
local i = 1
@@ -1019,39 +1019,39 @@ do end -- no function here, see nse_main.lua
--@param port_range a port range string in Nmap standard format (ex. "T:80,1-30,U:31337,21-25")
--@returns boolean indicating whether the port is in the port range
function in_port_range(port,port_range)
assert(port and type(port.number)=="number" and type(port.protocol)=="string" and
assert(port and type(port.number)=="number" and type(port.protocol)=="string" and
(port.protocol=="udp" or port.protocol=="tcp"),"Port structure missing or invalid: port={ number=<port_number>, protocol=<port_protocol> }")
assert((type(port_range)=="string" or type(port_range)=="number") and port_range~="","Incorrect port range specification.")
-- Proto - true for TCP, false for UDP
local proto
if(port.protocol=="tcp") then proto = true else proto = false end
--TCP flag for iteration - true for TCP, false for UDP, if not specified we presume TCP
local tcp_flag = true
-- in case the port_range is a single number
-- in case the port_range is a single number
if type(port_range)=="number" then
if proto and port_range==port.number then return true
else return false
end
end
--clean the string a bit
port_range=port_range:gsub("%s+","")
-- single_pr - single port range
for i, single_pr in ipairs(strsplit(",",port_range)) do
if single_pr:match("T:") then
tcp_flag = true
single_pr = single_pr:gsub("T:","")
else
if single_pr:match("U:") then
tcp_flag = false
else
if single_pr:match("U:") then
tcp_flag = false
single_pr = single_pr:gsub("U:","")
end
end
-- compare ports only when the port's protocol is the same as
-- the current single port range
if tcp_flag == proto then
@@ -1059,9 +1059,9 @@ function in_port_range(port,port_range)
if pone then
pone = tonumber(pone)
assert(pone>-1 and pone<65536, "Port range number out of range (0-65535).")
if pone == port.number then
return true
if pone == port.number then
return true
end
else
local pstart, pend = single_pr:match("^(%d+)%-(%d+)$")
@@ -1069,7 +1069,7 @@ function in_port_range(port,port_range)
assert(pstart,"Incorrect port range specification.")
assert(pstart<=pend,"Incorrect port range specification, the starting port should have a smaller value than the ending port.")
assert(pstart>-1 and pstart<65536 and pend>-1 and pend<65536, "Port range number out of range (0-65535).")
if port.number >=pstart and port.number <= pend then
return true
end

View File

@@ -51,7 +51,7 @@ local concat = table.concat;
_ENV = stdnse.module("strbuf", stdnse.seeall)
-- String buffer functions. Concatenation is not efficient in
-- String buffer functions. Concatenation is not efficient in
-- lua as strings are immutable. If a large amount of '..' sequential
-- operations are needed a string buffer should be used instead
-- e.g. for i = 1, 10 do s = s..i end

View File

@@ -51,9 +51,9 @@ end
local function strict (env)
local mt = getmetatable(env) or setmetatable(env, {}) and getmetatable(env);
local _newindex, _index = mt.__newindex, mt.__index;
mt.__declared = {};
function mt.__newindex (t, n, v)
if type(_newindex) == "function" then
_newindex(t, n, v); -- hook it
@@ -67,7 +67,7 @@ local function strict (env)
end
rawset(t, n, v);
end
function mt.__index (t, n)
if type(_index) == "function" then
local v = _index(t, n); -- hook it

View File

@@ -22,13 +22,13 @@ MessageType = {
BINDING_REQUEST = 0x0001,
BINDING_RESPONSE = 0x0101,
}
-- The header used in both request and responses
Header = {
-- the header size in bytes
-- the header size in bytes
size = 20,
-- creates a new instance of Header
-- @param type number the request/response type
-- @param trans_id string the 128-bit transaction id
@@ -39,9 +39,9 @@ Header = {
self.__index = self
return o
end,
-- parses an opaque string and creates a new Header instance
-- @param data opaque string
-- @param data opaque string
-- @return header new instance of Header
parse = function(data)
local header = Header:new()
@@ -49,24 +49,24 @@ Header = {
pos, header.type, header.length, header.trans_id = bin.unpack(">SSA16", data)
return header
end,
-- converts the header to an opaque string
-- @return string containing the header instance
__tostring = function(self)
return bin.pack(">SSA", self.type, self.length, self.trans_id)
end,
end,
}
Request = {
-- The binding request
Bind = {
-- Creates a new Bind request
-- @param trans_id string containing the 128 bit transaction ID
-- @return o new instance of the Bind request
new = function(self, trans_id)
local o = {
local o = {
header = Header:new(MessageType.BINDING_REQUEST, trans_id),
attributes = {}
}
@@ -74,7 +74,7 @@ Request = {
self.__index = self
return o
end,
-- converts the instance to an opaque string
-- @return string containing the Bind request as string
__tostring = function(self)
@@ -83,10 +83,10 @@ Request = {
data = data .. tostring(attrib)
end
self.header.length = #data
return tostring(self.header) .. data
end,
return tostring(self.header) .. data
end,
}
}
-- The attribute class
@@ -104,7 +104,7 @@ Attribute = {
UNKNOWN_ATTRIBUTES = 0x000a,
REFLECTED_FROM = 0x000b,
SERVER = 0x8022,
-- creates a new attribute instance
-- @param type number containing the attribute type
-- @param data string containing the attribute value
@@ -119,16 +119,16 @@ Attribute = {
self.__index = self
return o
end,
-- parses a string and creates an Attribute instance
-- @param data string containing the raw attribute
-- @return o new attribute instance
parse = function(data)
local attr = Attribute:new()
local pos = 1
pos, attr.type, attr.length = bin.unpack(">SS", data, pos)
local function parseAddress(data, pos)
local _, addr = nil, {}
pos, _, addr.family, addr.port, addr.ip = bin.unpack("<CCSI", data, pos)
@@ -137,7 +137,7 @@ Attribute = {
end
return addr
end
if ( ( attr.type == Attribute.MAPPED_ADDRESS ) or
( attr.type == Attribute.RESPONSE_ADDRESS ) or
( attr.type == Attribute.SOURCE_ADDRESS ) or
@@ -149,24 +149,24 @@ Attribute = {
elseif( attr.type == Attribute.SERVER ) then
pos, attr.server = bin.unpack("A" .. attr.length-1, data, pos)
end
return attr
end,
-- converts an attribute to string
-- @return string containing the serialized attribute
__tostring = function(self)
return bin.pack(">SSA", self.type, self.length, self.data or "")
end,
}
-- Response class container
Response = {
-- Bind response class
Bind = {
-- creates a new instance of the Bind response
-- @param trans_id string containing the 128 bit transaction id
-- @return o new Bind instance
@@ -183,7 +183,7 @@ Response = {
parse = function(data)
local resp = Response.Bind:new()
local pos = Header.size
resp.header = Header.parse(data)
resp.attributes = {}
@@ -191,7 +191,7 @@ Response = {
local attr = Attribute.parse(data:sub(pos))
table.insert(resp.attributes, attr)
pos = pos + attr.length + 4
end
end
return resp
end
}
@@ -199,16 +199,16 @@ Response = {
-- The communication class
Comm = {
-- creates a new Comm instance
-- @param host table
-- @param port table
-- @param options table, currently supporting:
-- <code>timeout</code> - socket timeout in ms.
-- @param mode containing the mode
-- @param mode containing the mode
-- @return o new instance of Comm
new = function(self, host, port, options, mode)
local o = {
local o = {
host = host,
port = port,
options = options or { timeout = 10000 },
@@ -218,7 +218,7 @@ Comm = {
self.__index = self
return o
end,
-- connects the socket to the server
-- @return status true on success, false on failure
-- @return err string containing an error message, if status is false
@@ -226,7 +226,7 @@ Comm = {
self.socket:set_timeout(self.options.timeout)
return self.socket:connect(self.host, self.port)
end,
-- sends a request to the server
-- @return status true on success, false on failure
-- @return err string containing an error message, if status is false
@@ -238,26 +238,26 @@ Comm = {
-- @return status true on success, false on failure
-- @return response containing a response instance
-- err string containing an error message, if status is false
recv = function(self)
recv = function(self)
local status, hdr_data = self.socket:receive_buf(match.numbytes(Header.size), false)
if ( not(status) ) then
return false, "Failed to receive response from server"
end
local header = Header.parse(hdr_data)
if ( not(header) ) then
return false, "Failed to parse response header"
end
local status, data = self.socket:receive_buf(match.numbytes(header.length), false)
if ( header.type == MessageType.BINDING_RESPONSE ) then
local resp = Response.Bind.parse(hdr_data .. data)
return true, resp
end
return false, "Unknown response message received"
end,
-- sends the request instance to the server and receives the response
-- @param req request class instance
-- @return status true on success, false on failure
@@ -268,9 +268,9 @@ Comm = {
if ( not(status) ) then
return false, "Failed to send request to server"
end
return self:recv()
return self:recv()
end,
-- closes the connection to the server
-- @return status true on success, false on failure
-- @return err string containing an error message, if status is false
@@ -281,7 +281,7 @@ Comm = {
-- The Util class
Util = {
-- creates a random string
-- @param len number containg the length of the generated random string
-- @return str containing the random string
@@ -290,7 +290,7 @@ Util = {
for i=1, len do str = str .. string.char(math.random(255)) end
return str
end
}
-- The Helper class
@@ -305,7 +305,7 @@ Helper = {
-- supported container
-- @return o new instance of Comm
new = function(self, host, port, options, mode)
local o = {
local o = {
mode = mode,
comm = Comm:new(host, port, options, mode),
}
@@ -315,32 +315,32 @@ Helper = {
self.__index = self
return o
end,
-- connects to the server
-- @return status true on success, false on failure
-- @return err string containing an error message, if status is false
connect = function(self)
return self.comm:connect()
end,
-- Get's the external public IP
-- @return status true on success, false on failure
-- @return result containing the IP as tring
getExternalAddress = function(self)
local trans_id
if ( self.mode == "classic" ) then
trans_id = Util.randomString(16)
else
trans_id = bin.pack("HA","2112A442", Util.randomString(12))
end
local req = Request.Bind:new(trans_id)
local status, response = self.comm:exch(req)
if ( not(status) ) then
return false, "Failed to send data to server"
end
local result
for k, attr in pairs(response.attributes) do
if (attr.type == Attribute.MAPPED_ADDRESS ) then
@@ -351,14 +351,14 @@ Helper = {
self.cache.server = attr.server
end
end
if ( not(result) and not(self.cache) ) then
return false, "Server returned no response"
end
return status, result
end,
-- Gets the server version if it was returned by the server
-- @return status true on success, false on failure
-- @return version string containing the server product and version
@@ -374,14 +374,14 @@ Helper = {
end
return true, (self.cache and self.cache.server or "")
end,
-- closes the connection to the server
-- @return status true on success, false on failure
-- @return err string containing an error message, if status is false
close = function(self)
return self.comm:close()
end,
}
return _ENV;

View File

@@ -90,7 +90,7 @@ end
function dump(t)
assert(t)
local column_width = {}
local column_width = {}
local num_columns = {}
local buf = strbuf.new()

View File

@@ -2,7 +2,7 @@
--
-- Currently only write-operations are supported so that script can trigger
-- TFTP transfers and receive the files and return them as result.
--
--
-- The library contains the following classes
-- * <code>Packet</code>
-- ** The <code>Packet</code> classes contain one class for each TFTP operation.
@@ -45,7 +45,7 @@ OpCode = {
WRQ = 2,
DATA = 3,
ACK = 4,
ERROR = 5,
ERROR = 5,
}
@@ -54,10 +54,10 @@ OpCode = {
-- The current code only implements the ACK and ERROR packets
-- As the server is write-only the other packet types are not needed
Packet = {
-- Implements the ACK packet
ACK = {
new = function( self, block )
local o = {}
setmetatable(o, self)
@@ -65,13 +65,13 @@ Packet = {
o.block = block
return o
end,
__tostring = function( self )
return bin.pack(">SS", OpCode.ACK, self.block)
end,
},
-- Implements the error packet
ERROR = {
@@ -83,17 +83,17 @@ Packet = {
o.code = code
return o
end,
__tostring = function( self )
return bin.pack(">SSz", OpCode.ERROR, self.code, self.msg)
end,
}
}
--- The File class holds files received by the TFTP server
File = {
--- Creates a new file object
--
-- @param filename string containing the filename
@@ -114,7 +114,7 @@ File = {
getName = function(self) return self.name end,
setName = function(self, name) self.name = name end,
setSender = function(self, sender) self.sender = sender end,
getSender = function(self) return self.sender end,
}
@@ -124,21 +124,21 @@ File = {
local function dispatcher()
local last = os.time()
local f_condvar = nmap.condvar(infiles)
local f_condvar = nmap.condvar(infiles)
local s_condvar = nmap.condvar(state)
while(true) do
-- check if other scripts are active
local counter = 0
for t in pairs(running) do
counter = counter + 1
end
if ( counter == 0 ) then
if ( counter == 0 ) then
state = "STOPPING"
s_condvar "broadcast"
end
if #threads == 0 then break end
for i, thread in ipairs(threads) do
local status, res = coroutine.resume(thread)
@@ -147,14 +147,14 @@ local function dispatcher()
break
end
end
-- Make sure to process waitFile atleast every 2 seconds
-- in case no files have arrived
if ( os.time() - last >= 2 ) then
last = os.time()
f_condvar "broadcast"
end
end
state = "STOPPED"
s_condvar "broadcast"
@@ -176,7 +176,7 @@ local function processConnection( host, port, data )
if ( not(status) ) then return status, err end
socket:set_timeout(10)
-- If we get anything else than a write request, abort the connection
if ( OpCode.WRQ ~= op ) then
stdnse.print_debug("Unsupported opcode")
@@ -185,10 +185,10 @@ local function processConnection( host, port, data )
local pos, filename, enctype = bin.unpack("zz", data, pos)
status, err = socket:send( tostring( Packet.ACK:new(0) ) )
local blocks = {}
local lastread = os.time()
while( true ) do
local status, pdata = socket:receive()
if ( not(status) ) then
@@ -205,18 +205,18 @@ local function processConnection( host, port, data )
if ( OpCode.DATA ~= op ) then
stdnse.print_debug("Expected a data packet, terminating TFTP transfer")
end
local block, data
pos, block, data = bin.unpack(">SA" .. #pdata - 4, pdata, pos )
blocks[block] = data
-- First block was not 1
if ( #blocks == 0 ) then
socket:send( tostring(Packet.ERROR:new(0, "Did not receive block 1")))
break
end
-- for every fith block check that we've received the preceeding four
if ( ( #blocks % 5 ) == 0 ) then
for b = #blocks - 4, #blocks do
@@ -225,7 +225,7 @@ local function processConnection( host, port, data )
end
end
end
-- Ack the data block
status, err = socket:send( tostring(Packet.ACK:new(block)) )
@@ -233,17 +233,17 @@ local function processConnection( host, port, data )
-- yield every 5th iteration so other threads may work
coroutine.yield(true)
end
-- If the data length was less than 512, this was our last block
-- If the data length was less than 512, this was our last block
if ( #data < 512 ) then
socket:close()
break
end
end
end
local filecontent = ""
-- Make sure we received all the blocks needed to proceed
for i=1, #blocks do
if ( not(blocks[i]) ) then
@@ -252,27 +252,27 @@ local function processConnection( host, port, data )
filecontent = filecontent .. blocks[i]
end
stdnse.print_debug("Finnished receiving file \"%s\"", filename)
-- Add anew file to the global infiles table
table.insert( infiles, File:new(filename, filecontent, host) )
local condvar = nmap.condvar(infiles)
condvar "broadcast"
end
-- Waits for a connection from a client
local function waitForConnection()
local srvsock = nmap.new_socket("udp")
local status = srvsock:bind(nil, 69)
assert(status, "Failed to bind to TFTP server port")
srvsock:set_timeout(0)
while( state == "RUNNING" ) do
local status, data = srvsock:receive()
if ( not(status) ) then
coroutine.yield(true)
if ( not(status) ) then
coroutine.yield(true)
else
local status, _, _, rhost, rport = srvsock:get_info()
local x = coroutine.create( function() processConnection(rhost, rport, data) end )
@@ -293,13 +293,13 @@ function start()
mutex "lock"
if ( state == "STOPPED" ) then
srvthread = coroutine.running()
srvthread = coroutine.running()
table.insert( threads, coroutine.create( waitForConnection ) )
stdnse.new_thread( dispatcher )
state = "RUNNING"
end
mutex "done"
end
local function waitLast()
@@ -328,10 +328,10 @@ function waitFile( filename, timeout )
local t = os.time()
while(os.time() - t < timeout) do
for _, f in ipairs(infiles) do
if (f:getName() == filename) then
if (f:getName() == filename) then
running[coroutine.running()] = nil
waitLast()
return true, f
return true, f
end
end
condvar "wait"

View File

@@ -7,7 +7,7 @@
-- to the Oracle database server. Some preliminary query support has been
-- added, which only works against a few specific versions. The library has
-- been tested against and known to work with Oracle 10g and 11g. Please check
-- the matrix below for tested versions that are known to work.
-- the matrix below for tested versions that are known to work.
--
-- Due to the lack of documentation the library is based mostly on guesswork
-- with a lot of unknowns. Bug reports are therefore both welcome and
@@ -25,10 +25,10 @@
-- contain a function to parse the servers response.
--
-- o Comm
-- - Implements a number of functions to handle communication
-- - Implements a number of functions to handle communication
--
-- o Crypt
-- - Implements encryption algorithms and functions to support
-- - Implements encryption algorithms and functions to support
-- authentication with Oracle 10G and Oracle 11G.
--
-- o Helper
@@ -131,9 +131,9 @@ DataTypes = {
}
-- A class containing some basic authentication options
AuthOptions =
AuthOptions =
{
-- Creates a new AuthOptions instance
-- @return o new instance of AuthOptions
new = function( self )
@@ -147,22 +147,22 @@ AuthOptions =
setmetatable(o, self)
self.__index = self
return o
end,
end,
}
-- Decodes different datatypes from the byte arrays or strings read from the
-- tns data packets
DataTypeDecoders = {
-- Decodes a number
[DataTypes.NUMBER] = function(val)
if ( #val == 0 ) then return "" end
if ( #val == 1 and val == '\128' ) then return 0 end
local bytes = {}
for i=1, #val do bytes[i] = select(2, bin.unpack("C", val, i)) end
local positive = ( bit.band(bytes[1], 0x80) ~= 0 )
local function convert_bytes(bytes, positive)
@@ -176,37 +176,37 @@ DataTypeDecoders = {
ret_bytes[1] = bit.band(bit.bxor(bytes[1], 0xFF), 0x7F) - 65
for i=2, len do ret_bytes[i] = 101 - bytes[i] end
end
return ret_bytes
end
bytes = convert_bytes(bytes, positive)
local k = ( #bytes - 1 > bytes[1] +1 ) and ( bytes[1] + 1 ) or #bytes - 1
local l = 0
for m=1, k do l = l * 100 + bytes[m+1] end
for m=bytes[1]-#bytes - 1, 0, -1 do l = l * 100 end
return (positive and l or -l)
end,
-- Decodes a date
[DataTypes.DATE] = function(val)
local bytes = {}
if (#val == 0) then
return ""
elseif( #val ~= 7 ) then
return "ERROR: Failed to decode date"
end
for i=1, 7 do bytes[i] = select(2, bin.unpack("C", val, i)) end
return ("%d-%02d-%02d"):format( (bytes[1] - 100 ) * 100 + bytes[2] - 100, bytes[3], bytes[4] )
end,
}
-- Packet class table
@@ -216,7 +216,7 @@ DataTypeDecoders = {
-- o toString - A function that serializes the object to string
--
-- Each Packet MAY also optionally implement:
-- o parseResponse
-- o parseResponse
-- x An optional function that parses the servers response
-- x The function should return status and an undefined second return value
--
@@ -231,7 +231,7 @@ Packet.TNS = {
length = 0,
reserved = 0,
Type =
Type =
{
CONNECT = 1,
ACCEPT = 2,
@@ -249,7 +249,7 @@ Packet.TNS = {
self.__index = self
return o
end,
--- Read a TNS packet of the socket
--
-- @return true on success, false on failure
@@ -263,22 +263,22 @@ Packet.TNS = {
local _
_, self.length = bin.unpack(">S", data )
status, data = self.socket:receive_buf( match.numbytes(6), true )
if ( not(status) ) then
return status, data
end
_, self.checksum, self.type, self.reserved, self.hdr_checksum = bin.unpack(">SCCS", data)
status, data = self.socket:receive_buf( match.numbytes(self.length - 8), true )
if ( status ) then
self.data = data
end
return true
end,
parse = function(data)
local tns = Packet.TNS:new()
local pos
@@ -286,7 +286,7 @@ Packet.TNS = {
pos, tns.data = bin.unpack("A" .. ( tns.length - 8 ), data, pos)
return tns
end,
--- Converts the TNS packet to string suitable to be sent over the socket
--
-- @return string containing the TNS packet
@@ -294,17 +294,17 @@ Packet.TNS = {
local data = bin.pack(">SSCCSA", self.length, self.checksum, self.type, self.reserved, self.hdr_checksum, self.data )
return data
end,
}
-- Initiates the connection to the listener
Packet.Connect = {
CONN_STR = [[
(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=%s)(PORT=%d))
(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=%s)(CID=
(PROGRAM=sqlplus)(HOST=%s)(USER=nmap))))]],
version = 314,
version_comp = 300,
svc_options = 0x0c41,
@@ -322,7 +322,7 @@ Packet.Connect = {
trace_cross_2 = 0,
trace_unique_conn = 0,
tns_type = Packet.TNS.Type.CONNECT,
-- Creates a new Connect instance
-- @param rhost string containing host or ip
-- @param rport string containing the port number
@@ -339,14 +339,14 @@ Packet.Connect = {
self.__index = self
return o
end,
setCmd = function( self, cmd )
local tmp = [[
local tmp = [[
(DESCRIPTION=(CONNECT_DATA=(CID=(PROGRAM=)(HOST=%s)(USER=nmap))(COMMAND=%s)(ARGUMENTS=64)(SERVICE=%s:%d)(VERSION=185599488)))
]]
self.conn_data = tmp:format( self.rhost, cmd, self.rhost, self.rport )
end,
--- Parses the server response from the CONNECT
--
-- @param tns Packet.TNS containing the TNS packet received from the
@@ -356,18 +356,18 @@ Packet.Connect = {
-- server or an error message on failure
parseResponse = function( self, tns )
local pos, version
if ( tns.type ~= Packet.TNS.Type.ACCEPT ) then
if ( tns.data:match("ERR=12514") ) then
return false, ("TNS: The listener could not resolve \"%s\""):format(self.dbinstance)
end
return false, tns.data:match("%(ERR=(%d*)%)")
end
pos, version = bin.unpack(">S", tns.data )
return true, version
end,
--- Converts the CONNECT packet to string
--
-- @return string containing the packet
@@ -381,8 +381,8 @@ Packet.Connect = {
self.conn_data_flags_1, self.trace_cross_1, self.trace_cross_2,
self.trace_unique_conn, 0, self.conn_data )
end,
}
-- A TNS data packet, one of the most common packets
@@ -401,7 +401,7 @@ Packet.Data = {
self.__index = self
return o
end,
--- Converts the DATA packet to string
--
-- @return string containing the packet
@@ -410,7 +410,7 @@ Packet.Data = {
self.TNS.length = #data + 8
return tostring(self.TNS) .. data
end,
}
-- Packet received by the server to indicate errors or end of
@@ -430,26 +430,26 @@ Packet.Attention = {
--- Converts the MARKER packet to string
--
-- @return string containing the packet
-- @return string containing the packet
__tostring = function( self )
return bin.pack( ">C", self.att_type ) .. self.data
end,
}
-- Packet initializing challenge response authentication
Packet.PreAuth = {
tns_type = Packet.TNS.Type.DATA,
flags = 0,
param_order = {
flags = 0,
param_order = {
{ ["AUTH_TERMINAL"] = "auth_term" },
{ ["AUTH_PROGRAM_NM"] = "auth_prog" },
{ ["AUTH_MACHINE"] = "auth_machine" },
{ ["AUTH_PID"] = "auth_pid" },
{ ["AUTH_SID"] = "auth_sid" }
},
--- Creates a new PreAuth packet
--
-- @param user string containing the user name
@@ -463,7 +463,7 @@ Packet.PreAuth = {
--- Converts the DATA packet to string
--
-- @return string containing the packet
-- @return string containing the packet
__tostring = function( self )
local packet_type = 0x0376
local UNKNOWN_MAP = {
@@ -481,10 +481,10 @@ Packet.PreAuth = {
data = data .. Marshaller.marshalKvp( k, self.auth_options[v2] )
end
end
return data
end,
--- Parses the PreAuth packet response and extracts data needed to
-- perform authentication
--
@@ -494,7 +494,7 @@ Packet.PreAuth = {
local kvps = {}
local pos, kvp_count = bin.unpack( "C", tns.data, 4 )
pos = 6
for kvp_itr=1, kvp_count do
local key, val, kvp_flags
pos, key, val, kvp_flags = Marshaller.unmarshalKvp( tns.data, pos )
@@ -509,10 +509,10 @@ Packet.PreAuth = {
-- Packet containing authentication data
Packet.Auth = {
tns_type = Packet.TNS.Type.DATA,
flags = 0,
param_order = {
param_order = {
{ ['key'] = "AUTH_RTT", ['def'] = "25456" },
{ ['key'] = "AUTH_CLNT_MEM", ['def'] = "4096" },
{ ['key'] = "AUTH_TERMINAL", ['var'] = "auth_term" },
@@ -546,7 +546,7 @@ Packet.Auth = {
--- Converts the DATA packet to string
--
-- @return string containing the packet
-- @return string containing the packet
__tostring = function( self )
local UNKNOWN_MAP = {
["Linuxi386/Linux-2.0.34-8.1.0"] = bin.pack("HCH","0338be0808", #self.user, "00000001010000cc7dbfbf0d000000747abfbf608abfbf"),
@@ -554,14 +554,14 @@ Packet.Auth = {
["IBMPC/WIN_NT64-9.1.0"] = bin.pack("H","03010400000001010000010d0000000101"),
["x86_64/Linux 2.4.xx"] = bin.pack("H","03010400000001010000010d0000000101")
}
local sess_id = select(2, bin.unpack("H16", openssl.rand_pseudo_bytes(16)))
local unknown = UNKNOWN_MAP[self.version] or ""
local data = bin.pack(">SSA", self.flags, 0x0373, unknown)
data = data .. bin.pack("CA", #self.user, self.user )
data = data .. Marshaller.marshalKvp( "AUTH_SESSKEY", self.auth_sesskey, 1 )
data = data .. Marshaller.marshalKvp( "AUTH_PASSWORD", self.auth_pass )
for k, v in ipairs( self.param_order ) do
if ( v['def'] ) then
data = data .. Marshaller.marshalKvp( v['key'], v['def'] )
@@ -571,9 +571,9 @@ Packet.Auth = {
data = data .. Marshaller.marshalKvp( v['key'], self[ v['var'] ] )
end
end
return data
return data
end,
-- Parses the response of an Auth packet
--
-- @param tns Packet.TNS containing the TNS packet recieved from the server
@@ -582,7 +582,7 @@ Packet.Auth = {
local kvps = {}
local pos, kvp_count = bin.unpack( "C", tns.data, 4 )
pos = 6
for kvp_itr=1, kvp_count do
local key, val, kvp_flags
pos, key, val, kvp_flags = Marshaller.unmarshalKvp( tns.data, pos )
@@ -592,14 +592,14 @@ Packet.Auth = {
return true, kvps
end,
}
Packet.SNS = {
tns_type = Packet.TNS.Type.DATA,
flags = 0,
-- Creates a new SNS instance
--
-- @return o new instance of the SNS packet
@@ -609,21 +609,21 @@ Packet.SNS = {
self.__index = self
return o
end,
--- Converts the DATA packet to string
--
-- @return string containing the packet
-- @return string containing the packet
__tostring = function( self )
return bin.pack("SH", self.flags,
[[
return bin.pack("SH", self.flags,
[[
deadbeef00920b1006000004000004000300000000000400050b10060000080
001000015cb353abecb00120001deadbeef0003000000040004000100010002
0001000300000000000400050b10060000020003e0e100020006fcff0002000
200000000000400050b100600000c0001001106100c0f0a0b08020103000300
0200000000000400050b10060000030001000301
]] )
end,
end,
}
-- Packet containing protocol negotiation
@@ -631,21 +631,21 @@ Packet.ProtoNeg = {
tns_type = Packet.TNS.Type.DATA,
flags = 0,
new = function(self)
local o = {}
setmetatable(o, self)
self.__index = self
return o
end,
--- Converts the DATA packet to string
--
-- @return string containing the packet
-- @return string containing the packet
__tostring = function( self )
local pfx = bin.pack(">SH", self.flags, "0106050403020100")
return pfx .. "Linuxi386/Linux-2.0.34-8.1.0\0"
end,
return pfx .. "Linuxi386/Linux-2.0.34-8.1.0\0"
end,
--- Parses and verifies the server response
--
@@ -655,7 +655,7 @@ Packet.ProtoNeg = {
if ( neg ~= 1 ) then
return false, "Error protocol negotiation failed"
end
if ( ver ~= 6 ) then
return false, ("Error protocol version (%d) not supported"):format(ver)
end
@@ -668,7 +668,7 @@ Packet.Unknown1 = {
tns_type = Packet.TNS.Type.DATA,
flags = 0,
--- Creates a new Packet.Unknown1
--
-- @param version containing the version of the packet to send
@@ -679,10 +679,10 @@ Packet.Unknown1 = {
self.__index = self
return o
end,
--- Converts the DATA packet to string
--
-- @return string containing the packet
-- @return string containing the packet
__tostring = function( self )
if ( self.os:match("IBMPC/WIN_NT[64]*[-]%d%.%d%.%d") ) then
@@ -823,8 +823,8 @@ Packet.Unknown1 = {
return bin.pack(">SH", self.flags, "02b200b2004225060101010d010105010101010101017fff0309030301007f011" ..
"fff010301013f01010500010702010000180001800000003c3c3c80000000d007")
end
end,
end,
}
@@ -833,17 +833,17 @@ Packet.Unknown2 = {
tns_type = Packet.TNS.Type.DATA,
flags = 0,
new = function(self, os)
local o = { os = os }
setmetatable(o, self)
self.__index = self
return o
end,
--- Converts the DATA packet to string
--
-- @return string containing the packet
-- @return string containing the packet
__tostring = function( self )
if ( "x86_64/Linux 2.4.xx" == self.os ) then
return bin.pack(">SH", self.flags, [[
@@ -881,8 +881,8 @@ Packet.Unknown2 = {
00000e900e90001000000f1006d0001000002030203000100000000
]])
end
end,
end,
}
-- Signals that we're about to close the connection
@@ -890,27 +890,27 @@ Packet.EOF = {
tns_type = Packet.TNS.Type.DATA,
flags = 0x0040,
new = function(self)
local o = {}
setmetatable(o, self)
self.__index = self
return o
end,
--- Converts the DATA packet to string
--
-- @return string containing the packet
-- @return string containing the packet
__tostring = function( self )
return bin.pack(">S", self.flags )
end
end
}
Packet.PostLogin = {
tns_type = Packet.TNS.Type.DATA,
flags = 0x0000,
-- Creates a new PostLogin instance
--
-- @param sessid number containing session id
@@ -921,26 +921,26 @@ Packet.PostLogin = {
self.__index = self
return o
end,
--- Converts the DATA packet to string
--
-- @return string containing the packet
-- @return string containing the packet
__tostring = function( self )
local unknown1 = "116b04"
local unknown2 = "0000002200000001000000033b05fefffffff4010000fefffffffeffffff"
return bin.pack(">SHCH", self.flags, unknown1, tonumber(self.sessid), unknown2 )
end
}
-- Class responsible for sending queries to the server and handling the first
-- row returned by the server. This class is 100% based on packet captures and
-- guesswork.
Packet.Query = {
tns_type = Packet.TNS.Type.DATA,
flags = 0x0000,
--- Creates a new instance of Query
-- @param query string containing the SQL query
-- @return instance of Query
@@ -950,19 +950,19 @@ Packet.Query = {
self.__index = self
return o
end,
--- Gets the current counter value
-- @return counter number containing the current counter value
getCounter = function(self) return self.counter end,
--- Sets the current counter value
-- This function is called from sendTNSPacket
-- @param counter number containing the counter value to set
setCounter = function(self, counter) self.counter = counter end,
--- Converts the DATA packet to string
--
-- @return string containing the packet
-- @return string containing the packet
__tostring = function( self )
local unknown1 = "035e"
local unknown2 = "6180000000000000feffffff"
@@ -970,7 +970,7 @@ Packet.Query = {
local unknown4 = "01000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000"
return bin.pack(">SHCHCHCAH", self.flags, unknown1, self.counter, unknown2, #self.query, unknown3, #self.query, self.query, unknown4 )
end,
--- Parses the Query response from the server
-- @param tns response as received from the <code>Comm.recvTNSPacket</code>
-- function.
@@ -983,9 +983,9 @@ Packet.Query = {
parseResponse = function( self, tns )
local data = tns.data
local result = {}
local pos, columns = bin.unpack("C", tns.data, 35)
pos = 40
for i=1, columns do
local sql_type
@@ -1000,9 +1000,9 @@ Packet.Query = {
table.insert(result.types, sql_type)
pos = pos + 10
end
pos = pos + 55
result.rows = {}
local row = {}
for i=1, columns do
@@ -1023,7 +1023,7 @@ Packet.Query = {
table.insert(row, val)
end
table.insert(result.rows, row)
local moredata = true
-- check if we've got any more data?
if ( #data > pos + 97 ) then
@@ -1034,7 +1034,7 @@ Packet.Query = {
moredata = false
end
end
return true, { data = result, moredata = moredata }
end,
}
@@ -1046,7 +1046,7 @@ Packet.QueryResponseAck = {
tns_type = Packet.TNS.Type.DATA,
flags = 0x0000,
--- Creates a new QueryResponseAck instance
-- @param result table containing the results as received from the
-- <code>Query.parseResponse</code> function.
@@ -1061,19 +1061,19 @@ Packet.QueryResponseAck = {
--- Gets the current counter value
-- @return counter number containing the current counter value
getCounter = function(self) return self.counter end,
--- Sets the current counter value
-- This function is called from sendTNSPacket
-- @param counter number containing the counter value to set
setCounter = function(self, counter) self.counter = counter end,
--- Serializes the packet into a string suitable to be sent to the DB
-- server.
-- @return str string containing the serialized packet
__tostring = function(self)
return bin.pack(">SHCH", self.flags, "0305", self.counter, "030000000f000000")
end,
--
-- This is how I (Patrik Karlsson) think this is supposed to work
-- At this point we have the 2nd row (the query response has the first)
@@ -1093,7 +1093,7 @@ Packet.QueryResponseAck = {
-- data it is run through a decoder, that decodes the *real* value from
-- the encoded data.
--
parseResponse = function( self, tns )
parseResponse = function( self, tns )
local data = tns.data
local pos, len = bin.unpack("C", data, 21)
local mask = ""
@@ -1108,7 +1108,7 @@ Packet.QueryResponseAck = {
end
pos = pos + 4
else
pos = pos +3
pos = pos +3
end
while(true) do
@@ -1149,7 +1149,7 @@ Packet.QueryResponseAck = {
else
pos, len = bin.unpack("C", data, pos)
pos, val = bin.unpack("A" .. len, data, pos)
local sql_type = result.types[col]
if ( DataTypeDecoders[sql_type] ) then
val = DataTypeDecoders[sql_type](val)
@@ -1164,7 +1164,7 @@ Packet.QueryResponseAck = {
return true, tns.data
end,
}
Marshaller = {
@@ -1175,11 +1175,11 @@ Marshaller = {
-- @param flags The flags
-- @return A binary packed string representing the KVP structure
marshalKvp = function( key, value, flags )
return Marshaller.marshalKvpComponent( key ) ..
return Marshaller.marshalKvpComponent( key ) ..
Marshaller.marshalKvpComponent( value ) ..
bin.pack( "<I", ( flags or 0 ) )
end,
--- Parses a TNS key-value pair data structure.
--
-- @param data Packed string to parse
@@ -1187,14 +1187,14 @@ Marshaller = {
-- @return table containing the last position read, the key, the value, and the KVP flags
unmarshalKvp = function( data, pos )
local key, value, flags
pos, key = Marshaller.unmarshalKvpComponent( data, pos )
pos, value = Marshaller.unmarshalKvpComponent( data, pos )
pos, flags = bin.unpack("<I", data, pos )
return pos, key, value, flags
end,
--- Marshals a key or value element from a TNS key-value pair data structure
--
-- @param value The key or value
@@ -1241,7 +1241,7 @@ Marshaller = {
return result
end,
--- Parses a key or value element from a TNS key-value pair data structure.
--
-- @param data Packed string to parse
@@ -1284,14 +1284,14 @@ Marshaller = {
-- The TNS communication class uses the TNSSocket to transmit data
Comm = {
--- Creates a new instance of the Comm class
--
-- @param socket containing a TNSSocket
-- @return new instance of Comm
new = function(self, socket)
local o = {
socket = socket,
local o = {
socket = socket,
data_counter = 06
}
setmetatable(o, self)
@@ -1351,9 +1351,9 @@ Comm = {
local msg
pos, msg = bin.unpack("p", tns.data, pos )
return false, msg
return false, msg
end,
--- Recieves a TNS packet and handles TNS-resends
--
-- @return status true on success, false on failure
@@ -1390,7 +1390,7 @@ Comm = {
return true, tns
end,
--- Sends a TNS packet and recieves (and handles) the response
--
-- @param pkt containingt the Packet.* to send to the server
@@ -1400,7 +1400,7 @@ Comm = {
exchTNSPacket = function( self, pkt )
local status = self:sendTNSPacket( pkt )
local tns, response
if ( not(status) ) then
return false, "sendTNSPacket failed"
end
@@ -1421,7 +1421,7 @@ Comm = {
return status, response
end
}
--- Class that handles all Oracle encryption
@@ -1432,7 +1432,7 @@ Crypt = {
local combined_sesskey = ""
local sha1 = openssl.sha1(pass .. salt) .. "\0\0\0\0"
local auth_sesskey = s_sesskey
local auth_sesskey_c = c_sesskey
local auth_sesskey_c = c_sesskey
local server_sesskey = openssl.decrypt( "aes-192-cbc", sha1, nil, auth_sesskey )
local client_sesskey = openssl.decrypt( "aes-192-cbc", sha1, nil, auth_sesskey_c )
@@ -1475,7 +1475,7 @@ Crypt = {
local cli_sesskey = openssl.decrypt( "AES-128-CBC", pwhash, nil, cli_sesskey_enc )
local auth_pass = bin.pack("H", "4C5E28E66B6382117F9D41B08957A3B9E363B42760C33B44CA5D53EA90204ABE" )
local combined_sesskey = ""
local pass
local pass
for i=17, 32 do
combined_sesskey = combined_sesskey .. string.char( bit.bxor( string.byte(srv_sesskey, i), string.byte(cli_sesskey, i) ) )
@@ -1489,7 +1489,7 @@ Crypt = {
print( select(2, bin.unpack("H" .. #combined_sesskey, combined_sesskey )))
print( "pass=" .. pass )
end,
--- Performs the relevant encryption needed for the Oracle 10g response
--
-- @param user containing the Oracle user name
@@ -1510,7 +1510,7 @@ Crypt = {
local rnd = bin.pack("H", "4C31AFE05F3B012C0AE9AB0CDFF0C508")
local combined_sesskey = ""
local auth_pass
for i=17, 32 do
combined_sesskey = combined_sesskey .. string.char( bit.bxor( string.byte(srv_sesskey, i), string.byte(cli_sesskey, i) ) )
end
@@ -1529,7 +1529,7 @@ Crypt = {
-- @param auth_vrfy_data containing the password salt as recieved from the
-- PreAuth packet
-- @return cli_sesskey_enc the encrypted client session key
-- @return auth_pass the encrypted Oracle password
-- @return auth_pass the encrypted Oracle password
Encrypt11g = function( self, pass, srv_sesskey_enc, auth_vrfy_data )
-- This value should really be random, not this static cruft
@@ -1541,7 +1541,7 @@ Crypt = {
local cli_sesskey_enc
local combined_sesskey = ""
local data = ""
for i=17, 40 do
combined_sesskey = combined_sesskey .. string.char( bit.bxor( string.byte(srv_sesskey, i), string.byte(cli_sesskey, i) ) )
end
@@ -1555,19 +1555,19 @@ Crypt = {
return cli_sesskey_enc, auth_password
end,
}
Helper = {
--- Creates a new Helper instance
--
-- @param host table containing the host table as received by action
-- @param port table containing the port table as received by action
-- @param instance string containing the instance name
-- @return o new instance of Helper
-- @return o new instance of Helper
new = function(self, host, port, instance )
local o = {
local o = {
host = host,
port = port,
socket = nmap.new_socket(),
@@ -1578,7 +1578,7 @@ Helper = {
self.__index = self
return o
end,
--- Connects and performs protocol negotiation with the Oracle server
--
-- @return true on success, false on failure
@@ -1594,7 +1594,7 @@ Helper = {
local conn, packet, tns
if( not(status) ) then return status, data end
self.comm = Comm:new( self.socket )
status, self.version = self.comm:exchTNSPacket( Packet.Connect:new( self.host.ip, self.port.number, self.dbinstance ) )
@@ -1632,12 +1632,12 @@ Helper = {
status = self.comm:sendTNSPacket( Packet.Unknown1:new( self.os ) )
if ( not(status) ) then
return false, "ERROR: Helper.Connect failed"
end
end
status, data = self.comm:sendTNSPacket( Packet.Unknown2:new( self.os ) )
if ( not(status) ) then return false, data end
if ( not(status) ) then return false, data end
status, data = self.comm:recvTNSPacket( Packet.Unknown2:new( ) )
if ( not(status) ) then return false, data end
if ( not(status) ) then return false, data end
-- Oracle 10g under Windows needs this additional read, there's
-- probably a better way to detect this by analysing the packets
-- further.
@@ -1659,7 +1659,7 @@ Helper = {
status, data = self.comm:recvTNSPacket( Packet.Unknown2:new( ) )
if ( not(status) ) then
return false, data
end
end
else
status = self.comm:exchTNSPacket( Packet.Unknown1:new( self.os ) )
@@ -1667,10 +1667,10 @@ Helper = {
return false, "ERROR: Helper.Connect failed"
end
end
return true
end,
--- Sends a command to the TNS lsnr
-- It currently accepts and tries to send all commands recieved
--
@@ -1706,7 +1706,7 @@ Helper = {
return true, data
end,
--- Authenticates to the database
--
-- @param user containing the Oracle user name
@@ -1757,7 +1757,7 @@ Helper = {
return false
end
end,
--- Queries the database
--
-- @param query string containing the SQL query
@@ -1812,7 +1812,7 @@ Helper = {
local status = self.comm:sendTNSPacket( Packet.EOF:new( ) )
self.socket:close()
end,
}
return _ENV;

View File

@@ -64,7 +64,7 @@ end
--
-- Holds and runs tests.
TestSuite = {
--- Creates a new TestSuite object
--
-- @return TestSuite object

Some files were not shown because too many files have changed in this diff Show More