From 05ad57df2105d3b9b516f4b8188fa376c0846dfe Mon Sep 17 00:00:00 2001 From: nnposter Date: Mon, 31 Aug 2020 00:25:09 +0000 Subject: [PATCH] Speed improvement for script afp-ls. Closes #2098 --- CHANGELOG | 3 +++ nselib/afp.lua | 45 +++++++++++++++++++++++++++++++-------------- scripts/afp-ls.nse | 46 ++++++++++++++++------------------------------ 3 files changed, 50 insertions(+), 44 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 99daf1241..391182e75 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,9 @@ o [GH#2104] Fixed parsing of TCP options which would hang (infinite loop) if an o [NSE][GH#2105] Fetching of SSH2 keys might fail because of key exchange confusion [nnposter] +o [NSE][GH#2098] Performance of script afp-ls has been dramatically improved + [nnposter] + o [NSE][GH#2091] Parsing of AFP FPGetFileDirParms and FPEnumerateExt2FPEnumerateExt2 responses was not working correctly [nnposter] diff --git a/nselib/afp.lua b/nselib/afp.lua index c6e25f58e..84c26fb40 100644 --- a/nselib/afp.lua +++ b/nselib/afp.lua @@ -1567,15 +1567,22 @@ Helper = { -- @param depth number containing the current depth (used when called recursively) -- @param parent table containing information about the parent object (used when called recursively) -- @return status boolean true on success, false on failure - -- @return dir table containing a table for each directory item with the following type, - -- name and id + -- @return dir table containing a table for each directory item with the following: + -- type, name, id, + -- fsize, uid, gid, + -- privs, create, modify Dir = function( self, str_path, options, depth, parent ) local status, result local depth = depth or 1 local options = options or { max_depth = 1 } local response, records - 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 f_bm = FILE_BITMAP.NodeId | FILE_BITMAP.ParentDirId + | FILE_BITMAP.LongName | FILE_BITMAP.UnixPrivileges + | FILE_BITMAP.CreationDate | FILE_BITMAP.ModificationDate + | FILE_BITMAP.ExtendedDataForkSize + local d_bm = DIR_BITMAP.NodeId | DIR_BITMAP.ParentDirId + | DIR_BITMAP.LongName | DIR_BITMAP.UnixPrivileges + | DIR_BITMAP.CreationDate | DIR_BITMAP.ModificationDate local TYPE_DIR = 0x80 @@ -1597,29 +1604,39 @@ Helper = { end local path = { type=PATH_TYPE.LongName, name="" } - 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, 1000 * 300, path) if response:getErrorCode() ~= ERROR.FPNoErr then return false, response:getErrorMessage() end records = response.result or {} - local dir_item = {} + local dir_items = {} for _, record in ipairs( records ) do - if ( options and options.dironly ) then - if ( record.type == TYPE_DIR ) then - table.insert( dir_item, { ['type'] = record.type, ['name'] = record.LongName, ['id'] = record.NodeId } ) + local isdir = record.type == TYPE_DIR + -- Skip non-directories if option "dironly" is set + if isdir or not options.dironly then + local item = {type = record.type, + name = record.LongName, + id = record.NodeId, + fsize = record.ExtendedDataForkSize or 0} + local privs = (record.UnixPrivileges or {}).ua_permissions + if privs then + item.uid = record.UnixPrivileges.uid + item.gid = record.UnixPrivileges.gid + item.privs = (isdir and "d" or "-") .. Util.decode_unix_privs(privs) end - else - table.insert( dir_item, { ['type'] = record.type, ['name'] = record.LongName, ['id'] = record.NodeId } ) + item.create = Util.time_to_string(record.CreationDate) + item.modify = Util.time_to_string(record.ModificationDate) + table.insert( dir_items, item ) end - if ( record.type == TYPE_DIR ) then - self:Dir("", options, depth + 1, { vol_id = parent.vol_id, did=record.NodeId, dir_name=record.LongName, out_tbl=dir_item} ) + if isdir then + self:Dir("", options, depth + 1, { vol_id = parent.vol_id, did=record.NodeId, dir_name=record.LongName, out_tbl=dir_items} ) end end - table.insert( parent.out_tbl, dir_item ) + table.insert( parent.out_tbl, dir_items ) return true, parent.out_tbl end, diff --git a/scripts/afp-ls.nse b/scripts/afp-ls.nse index 4db44cdee..1108beaa0 100644 --- a/scripts/afp-ls.nse +++ b/scripts/afp-ls.nse @@ -94,8 +94,11 @@ The output is intended to resemble the output of ls. -- 0 -- --- Version 0.1 +-- Version 0.2 -- Created 04/03/2011 - v0.1 - created by Patrik Karlsson +-- Modified 08/02/2020 - v0.2 - replaced individual date/size/ownership calls +-- with direct sourcing from the output of +-- afp.Helper.Dir author = "Patrik Karlsson" @@ -147,41 +150,24 @@ action = function(host, port) for _, vol in ipairs( vols ) do local status, tbl = afpHelper:Dir( vol ) if ( not(status) ) then - ls.report_error( - output, - ("ERROR: Failed to list the contents of %s"):format(vol)) + ls.report_error(output, ("ERROR: Failed to list the contents of %s"):format(vol)) else ls.new_vol(output, vol, true) - local continue = true for _, item in ipairs(tbl[1]) do - if ( item and item.name ) then - local status, result = afpHelper:GetFileUnixPermissions( - vol, item.name) - if ( status ) then - local status, fsize = afpHelper:GetFileSize( vol, item.name) - if ( not(status) ) then - ls.report_error( - output, - ("ERROR: Failed to retrieve file size for %/%s"):format(vol, item.name)) - else - local status, date = afpHelper:GetFileDates( vol, item.name) - if ( not(status) ) then - ls.report_error( - output, - ("\n\nERROR: Failed to retrieve file dates for %/%s"):format(vol, item.name)) - else - continue = ls.add_file(output, { - result.privs, result.uid, result.gid, - fsize, date.create, item.name - }) - end + if item and item.name then + if not (item.privs and item.create) then + ls.report_error(output, ("ERROR: Failed to retrieve file details for %/%s"):format(vol, item.name)) + else + local continue = ls.add_file(output, { + item.privs, item.uid, item.gid, + item.fsize, item.create, item.name + }) + if not continue then + ls.report_info(output, ("maxfiles limit reached (%d)"):format(maxfiles)) + break end end end - if not continue then - ls.report_info(output, ("maxfiles limit reached (%d)"):format(maxfiles)) - break - end end ls.end_vol(output) end