1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-15 12:19:02 +00:00

Update afp-ls, nfs-ls, smb-ls to use ls.lua. See #106

This commit is contained in:
dmiller
2015-09-04 12:52:08 +00:00
parent 087fadf2a9
commit 893f0c32f9
3 changed files with 372 additions and 289 deletions

View File

@@ -2,8 +2,7 @@ local afp = require "afp"
local nmap = require "nmap"
local shortport = require "shortport"
local stdnse = require "stdnse"
local tab = require "tab"
local table = require "table"
local ls = require "ls"
description = [[
Attempts to get useful information about files from AFP volumes.
@@ -12,45 +11,88 @@ The output is intended to resemble the output of <code>ls</code>.
---
--
--@output
-- @usage
-- nmap -sS -sV -p 548 --script=afp-ls target
--
-- @output
-- PORT STATE SERVICE
-- 548/tcp open afp syn-ack
-- | afp-ls:
-- | Macintosh HD
-- | PERMISSION UID GID SIZE TIME FILENAME
-- | -rw-r--r-- 501 80 15364 2010-06-13 17:52 .DS_Store
-- | ---------- 0 80 0 2009-10-05 07:42 .file
-- | drwx------ 501 20 0 2009-11-04 17:28 .fseventsd
-- | -rw------- 0 0 393216 2010-06-14 01:49 .hotfiles.btree
-- | drwx------ 0 80 0 2009-11-04 18:19 .Spotlight-V100
-- | d-wx-wx-wx 0 80 0 2009-11-04 18:25 .Trashes
-- | drwxr-xr-x 0 0 0 2009-05-18 21:29 .vol
-- | drwxrwxr-x 0 80 0 2009-04-28 00:06 Applications
-- | drwxr-xr-x 0 0 0 2009-05-18 21:43 bin
-- | drwxr-xr-x 501 80 0 2010-08-10 22:55 bundles
-- | Patrik Karlsson's Public Folder
-- | PERMISSION UID GID SIZE TIME FILENAME
-- | -rw------- 501 20 6148 2010-12-27 23:45 .DS_Store
-- | -rw-r--r-- 501 20 0 2007-07-24 21:17 .localized
-- | drwx-wx-wx 501 20 0 2009-06-19 04:01 Drop Box
-- | patrik
-- | PERMISSION UID GID SIZE TIME FILENAME
-- | -rw------- 501 20 11281 2010-06-14 22:51 .bash_history
-- | -rw-r--r-- 501 20 33 2011-01-19 20:11 .bashrc
-- | -rw------- 501 20 3 2007-07-24 21:17 .CFUserTextEncoding
-- | drwx------ 501 20 0 2010-09-12 14:52 .config
-- | drwx------ 501 20 0 2010-09-12 12:29 .cups
-- | -rw-r--r-- 501 20 15364 2010-06-13 18:34 .DS_Store
-- | drwxr-xr-x 501 20 0 2010-09-12 14:13 .fontconfig
-- | -rw------- 501 20 102 2010-06-14 01:46 .lesshst
-- | -rw-r--r-- 501 20 241 2010-06-14 01:45 .profile
-- | -rw------- 501 20 218 2010-09-12 16:35 .recently-used.xbel
-- | Information retrieved as patrik
-- | Volume Macintosh HD
-- | maxfiles limit reached (10)
-- | PERMISSION UID GID SIZE TIME FILENAME
-- | -rw-r--r-- 501 80 15364 2010-06-13 17:52 .DS_Store
-- | ---------- 0 80 0 2009-10-05 07:42 .file
-- | drwx------ 501 20 0 2009-11-04 17:28 .fseventsd
-- | -rw------- 0 0 393216 2010-06-14 01:49 .hotfiles.btree
-- | drwx------ 0 80 0 2009-11-04 18:19 .Spotlight-V100
-- | d-wx-wx-wx 0 80 0 2009-11-04 18:25 .Trashes
-- | drwxr-xr-x 0 0 0 2009-05-18 21:29 .vol
-- | drwxrwxr-x 0 80 0 2009-04-28 00:06 Applications
-- | drwxr-xr-x 0 0 0 2009-05-18 21:43 bin
-- | drwxr-xr-x 501 80 0 2010-08-10 22:55 bundles
-- |
-- | Information retrieved as: patrik
-- |_ Output restricted to 10 entries per volume. (See afp-ls.maxfiles)
--
-- @args afp-ls.maxfiles If set, limits the amount of files returned by the script (default 10).
-- | Volume Patrik Karlsson's Public Folder
-- | PERMISSION UID GID SIZE TIME FILENAME
-- | -rw------- 501 20 6148 2010-12-27 23:45 .DS_Store
-- | -rw-r--r-- 501 20 0 2007-07-24 21:17 .localized
-- | drwx-wx-wx 501 20 0 2009-06-19 04:01 Drop Box
-- |
-- | Volume patrik
-- | maxfiles limit reached (10)
-- | PERMISSION UID GID SIZE TIME FILENAME
-- | -rw------- 501 20 11281 2010-06-14 22:51 .bash_history
-- | -rw-r--r-- 501 20 33 2011-01-19 20:11 .bashrc
-- | -rw------- 501 20 3 2007-07-24 21:17 .CFUserTextEncoding
-- | drwx------ 501 20 0 2010-09-12 14:52 .config
-- | drwx------ 501 20 0 2010-09-12 12:29 .cups
-- | -rw-r--r-- 501 20 15364 2010-06-13 18:34 .DS_Store
-- | drwxr-xr-x 501 20 0 2010-09-12 14:13 .fontconfig
-- | -rw------- 501 20 102 2010-06-14 01:46 .lesshst
-- | -rw-r--r-- 501 20 241 2010-06-14 01:45 .profile
-- | -rw------- 501 20 218 2010-09-12 16:35 .recently-used.xbel
-- |_
--
-- @xmloutput
-- <table key="volumes">
-- <table>
-- <elem key="volume">Storage01</elem>
-- <table key="files">
-- <table>
-- <elem key="permission">drwx-&#45;&#45;&#45;&#45;&#45;</elem>
-- <elem key="uid">0</elem>
-- <elem key="gid">100</elem>
-- <elem key="size">0</elem>
-- <elem key="time">2015-06-26 17:17</elem>
-- <elem key="filename">Backups</elem>
-- </table>
-- <table>
-- <elem key="permission">drwxr-xr-x</elem>
-- <elem key="uid">0</elem>
-- <elem key="gid">37</elem>
-- <elem key="size">0</elem>
-- <elem key="time">2015-06-19 06:36</elem>
-- <elem key="filename">Network Trash Folder</elem>
-- </table>
-- <table>
-- <elem key="permission">drwxr-xr-x</elem>
-- <elem key="uid">0</elem>
-- <elem key="gid">37</elem>
-- <elem key="size">0</elem>
-- <elem key="time">2015-06-19 06:36</elem>
-- <elem key="filename">Temporary Items</elem>
-- </table>
-- </table>
-- </table>
-- </table>
-- <table key="info">
-- <elem>information retrieved as nil</elem>
-- </table>
-- <table key="total">
-- <elem key="files">3</elem>
-- <elem key="bytes">0</elem>
-- </table>
-- Version 0.1
-- Created 04/03/2011 - v0.1 - created by Patrik Karlsson
@@ -59,34 +101,17 @@ The output is intended to resemble the output of <code>ls</code>.
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"}
dependencies = {"afp-brute"}
portrule = shortport.portnumber(548, "tcp")
local function createFileTable()
local filetab = tab.new()
tab.add(filetab, 1, "PERMISSION")
tab.add(filetab, 2, "UID")
tab.add(filetab, 3, "GID")
tab.add(filetab, 4, "SIZE")
tab.add(filetab, 5, "TIME")
tab.add(filetab, 6, "FILENAME")
tab.nextrow(filetab)
return filetab
end
portrule = shortport.port_or_service(548, {"afp"})
action = function(host, port)
local afpHelper = afp.Helper:new()
local args = nmap.registry.args
local users = nmap.registry.afp or { ['nil'] = 'nil' }
local maxfiles = tonumber(stdnse.get_script_args("afp-ls.maxfiles") or 10)
local output = {}
local maxfiles = ls.config("maxfiles")
local output = ls.new_listing()
if ( args['afp.username'] ) then
users = {}
@@ -122,12 +147,12 @@ action = function(host, port)
for _, vol in ipairs( vols ) do
local status, tbl = afpHelper:Dir( vol )
if ( not(status) ) then
table.insert(
ls.report_error(
output,
("ERROR: Failed to list the contents of %s"):format(vol))
else
local file_tab = createFileTable()
local counter = maxfiles or 10
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(
@@ -135,27 +160,30 @@ action = function(host, port)
if ( status ) then
local status, fsize = afpHelper:GetFileSize( vol, item.name)
if ( not(status) ) then
table.insert(
ls.report_error(
output,
("\n\nERROR: Failed to retrieve file size for %/%s"):format(vol, item.name))
("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
table.insert(
ls.report_error(
output,
("\n\nERROR: Failed to retrieve file dates for %/%s"):format(vol, item.name))
else
tab.addrow(file_tab, result.privs, result.uid, result.gid, fsize, date.create, item.name)
counter = counter - 1
continue = ls.add_file(output, {
result.privs, result.uid, result.gid,
fsize, date.create, item.name
})
end
end
end
end
if ( counter == 0 ) then break end
if not continue then
ls.report_info(output, ("maxfiles limit reached (%d)"):format(maxfiles))
break
end
end
local result_part = { name = vol }
table.insert(result_part, tab.dump(file_tab))
table.insert(output, result_part)
ls.end_vol(output)
end
end
end
@@ -164,13 +192,9 @@ action = function(host, port)
status, response = afpHelper:CloseSession()
-- stop after first successful attempt
if ( output and #output > 0 ) then
table.insert(output, "")
table.insert(output, ("Information retrieved as: %s"):format(username))
if ( maxfiles > 0 ) then
table.insert(output, ("Output restricted to %d entries per volume. (See afp-ls.maxfiles)"):format(maxfiles))
end
return stdnse.format_output(true, output)
if #output["volumes"] > 0 then
ls.report_info(output, ("information retrieved as %s"):format(username))
return ls.end_listing(output)
end
end
return

View File

@@ -2,7 +2,7 @@ local rpc = require "rpc"
local shortport = require "shortport"
local stdnse = require "stdnse"
local string = require "string"
local tab = require "tab"
local ls = require "ls"
local table = require "table"
local nmap = require "nmap"
@@ -29,47 +29,99 @@ These access permissions are shown only with NFSv3:
* Extend: Write new data or add directory entries.
* Delete: Delete an existing directory entry.
* Execute: Execute file (no meaning for a directory).
Recursive listing is not implemented.
]]
---
-- @usage
-- nmap -p 111 --script=nfs-ls <target>
-- nmap -sV --script=nfs-ls <target>
-- @output
-- PORT STATE SERVICE
-- 111/tcp open rpcbind
-- | nfs-ls:
-- | Arguments:
-- | maxfiles: 10 (file listing output limited)
-- |
-- | NFS Export: /mnt/nfs/files
-- | NFS Access: Read Lookup NoModify NoExtend NoDelete NoExecute
-- | PERMISSION UID GID SIZE MODIFICATION TIME FILENAME
-- | drwxr-xr-x 1000 100 4096 2010-06-17 12:28 /mnt/nfs/files
-- | drwxr--r-- 1000 1002 4096 2010-05-14 12:58 sources
-- | -rw------- 1000 1002 23606 2010-06-17 12:28 notes
-- |
-- | NFS Export: /home/storage/backup
-- | NFS Access: Read Lookup Modify Extend Delete NoExecute
-- | PERMISSION UID GID SIZE MODIFICATION TIME FILENAME
-- | drwxr-xr-x 1000 100 4096 2010-06-11 22:31 /home/storage/backup
-- | -rw-r--r-- 1000 1002 0 2010-06-10 08:34 filetest
-- | drwx------ 1000 100 16384 2010-02-05 17:05 lost+found
-- | -rw-r--r-- 0 0 5 2010-06-10 11:32 rootfile
-- |_ lrwxrwxrwx 1000 1002 8 2010-06-10 08:34 symlink
--
-- @args nfs-ls.maxfiles If set, limits the amount of files returned by
-- the script. If set to 0
-- or less, all files are shown. The default value is 10.
-- @args nfs-ls.human If set to <code>1</code> or <code>true</code>,
-- shows file sizes in a human readable format with suffixes like
-- <code>KB</code> and <code>MB</code>.
-- @args nfs-ls.time Specifies which one of the last mac times to use in
-- the files attributes output. Possible values are:
-- * <code>m</code>: last modification time (mtime)
-- * <code>a</code>: last access time (atime)
-- * <code>c</code>: last change time (ctime)
-- The default value is <code>m</code> (mtime).
-- @args nfs.version The NFS protocol version to use
--
-- @output
-- PORT STATE SERVICE
-- 111/tcp open rpcbind
-- | nfs-ls:
-- | Volume /mnt/nfs/files
-- | access: Read Lookup NoModify NoExtend NoDelete NoExecute
-- | PERMISSION UID GID SIZE MODIFICATION TIME FILENAME
-- | drwxr-xr-x 1000 100 4096 2010-06-17 12:28 /mnt/nfs/files
-- | drwxr--r-- 1000 1002 4096 2010-05-14 12:58 sources
-- | -rw------- 1000 1002 23606 2010-06-17 12:28 notes
-- |
-- | Volume /home/storage/backup
-- | access: Read Lookup Modify Extend Delete NoExecute
-- | PERMISSION UID GID SIZE MODIFICATION TIME FILENAME
-- | drwxr-xr-x 1000 100 4096 2010-06-11 22:31 /home/storage/backup
-- | -rw-r--r-- 1000 1002 0 2010-06-10 08:34 filetest
-- | drwx------ 1000 100 16384 2010-02-05 17:05 lost+found
-- | -rw-r--r-- 0 0 5 2010-06-10 11:32 rootfile
-- | lrwxrwxrwx 1000 1002 8 2010-06-10 08:34 symlink
-- |_
--
-- @xmloutput
-- <table key="volumes">
-- <table>
-- <elem key="volume">/mnt/nfs/files</elem>
-- <table key="files">
-- <table>
-- <elem key="permission">drwxr-xr-x</elem>
-- <elem key="uid">1000</elem>
-- <elem key="gid">100</elem>
-- <elem key="size">4096</elem>
-- <elem key="time">2010-06-11 22:31</elem>
-- <elem key="filename">/mnt/nfs/files</elem>
-- </table>
-- <table>
-- <elem key="permission">-rw-r-&#45;r-&#45;</elem>
-- <elem key="uid">1000</elem>
-- <elem key="gid">1002</elem>
-- <elem key="size">0</elem>
-- <elem key="time">2010-06-10 08:34</elem>
-- <elem key="filename">filetest</elem>
-- </table>
-- <table>
-- <elem key="permission">drwx-&#45;&#45;&#45;&#45;&#45;</elem>
-- <elem key="uid">0</elem>
-- <elem key="gid">0</elem>
-- <elem key="size">16384</elem>
-- <elem key="time">2010-02-05 17:05</elem>
-- <elem key="filename">lost+found</elem>
-- </table>
-- <table>
-- <elem key="permission">-rw-r-&#45;r-&#45;</elem>
-- <elem key="uid">0</elem>
-- <elem key="gid">0</elem>
-- <elem key="size">5</elem>
-- <elem key="time">2010-06-10 11:32</elem>
-- <elem key="filename">rootfile</elem>
-- </table>
-- <table>
-- <elem key="permission">lrwxrwxrwx</elem>
-- <elem key="uid">1000</elem>
-- <elem key="gid">1002</elem>
-- <elem key="size">8</elem>
-- <elem key="time">2010-06-10 08:34</elem>
-- <elem key="filename">symlink</elem>
-- </table>
-- </table>
-- <table key="info">
-- <elem>access: Read Lookup NoModify NoExtend NoDelete NoExecute</elem>
-- </table>
-- </table>
-- </table>
-- <table key="total">
-- <elem key="files">5</elem>
-- <elem key="bytes">20493</elem>
-- </table>
-- Created 05/28/2010 - v0.1 - combined nfs-dirlist and nfs-acls scripts
-- Revised 06/04/2010 - v0.2 - make NFS exports listing with their acls
@@ -185,14 +237,12 @@ local function table_dirlist(nfs, mount, dirlist)
break
end
if v.name ~= ".." and v.name ~= "." then
if v.attributes then
table.insert(files, v.name)
attrs[files[idx]] = table_attributes(nfs, v.name, v.attributes)
idx = idx + 1
else
stdnse.debug1("ERROR attributes: %s", v.name)
end
if v.attributes then
table.insert(files, v.name)
attrs[files[idx]] = table_attributes(nfs, v.name, v.attributes)
idx = idx + 1
else
stdnse.debug1("ERROR attributes: %s", v.name)
end
end
@@ -210,53 +260,59 @@ local function unmount_nfs(mount, mnt_obj, nfs_obj)
rpc.Helper.UnmountPath(mnt_obj, mount)
end
local function nfs_ls(nfs, mount, results, access)
local function nfs_ls(nfs, mount, output)
local dirs, attr, acs = {}, {}, {}
local nfsobj = rpc.NFS:new()
local mnt_comm, nfs_comm, fhandle
mnt_comm, fhandle = procedures.MountPath(nfs.host, mount)
if mnt_comm == nil then
return false, fhandle
ls.report_error(output, fhandle)
return false
end
local nfs_comm, status = procedures.NfsOpen(nfs.host)
if nfs_comm == nil then
rpc.Helper.UnmountPath(mnt_comm, mount)
return false, status
ls.report_error(output, status)
return false
end
-- check if NFS and Mount versions are compatible
-- RPC library will check if the Mount and NFS versions are supported
if (nfs_comm.version == 1) then
unmount_nfs(mount, mnt_comm, nfs_comm)
return false, string.format("NFS v%d not supported", nfs_comm.version)
unmount_nfs(mount, mnt_comm, nfs_comm)
ls.report_error(output,
string.format("NFS v%d not supported", nfs_comm.version))
return false
elseif ((nfs_comm.version == 2 and mnt_comm.version > 2) or
(nfs_comm.version == 3 and mnt_comm.version ~= 3)) then
unmount_nfs(mount, mnt_comm, nfs_comm)
return false, string.format("versions mismatch, NFS v%d - Mount v%d",
nfs_comm.version, mnt_comm.version)
(nfs_comm.version == 3 and mnt_comm.version ~= 3)) then
unmount_nfs(mount, mnt_comm, nfs_comm)
ls.report_error(output,
string.format("versions mismatch, NFS v%d - Mount v%d",
nfs_comm.version, mnt_comm.version))
return false
end
status, attr = nfsobj:GetAttr(nfs_comm, fhandle)
if not status then
unmount_nfs(mount, mnt_comm, nfs_comm)
return status, attr
ls.report_error(output, attr)
return status
end
table.insert(results, table_attributes(nfs, mount, attr))
if nfs_comm.version == 3 then
status, acs = nfsobj:Access(nfs_comm, fhandle, 0x0000003F)
if status then
acs.str = rpc.Util.format_access(acs.mask, nfs_comm.version)
table.insert(access, acs.str)
ls.report_info(output, string.format("access: %s", acs.str))
end
status, dirs = nfsobj:ReadDirPlus(nfs_comm, fhandle)
if status then
for _,v in ipairs(table_dirlist(nfs, mount, dirs.entries)) do
table.insert(results, v)
ls.add_file(output, {v.type .. v.mode, v.uid, v.gid, v.size,
v.time, v.filename})
end
end
elseif nfs_comm.version == 2 then
@@ -265,67 +321,39 @@ local function nfs_ls(nfs, mount, results, access)
local lookup = {}
for _, v in ipairs(dirs.entries) do
if ((0 < nfs.maxfiles) and (#lookup >= nfs.maxfiles)) then
break
break
end
if v.name ~= ".." and v.name ~= "." then
local f = {}
status, f = nfsobj:LookUp(nfs_comm, fhandle, v.name)
f.name = v.name
table.insert(lookup, f)
end
local f = {}
status, f = nfsobj:LookUp(nfs_comm, fhandle, v.name)
f.name = v.name
table.insert(lookup, f)
end
for _, v in ipairs(table_dirlist(nfs, mount, lookup)) do
table.insert(results, v)
ls.add_file(output, {v.type .. v.mode, v.uid, v.gid, v.size,
v.time, v.filename})
end
end
end
unmount_nfs(mount, mnt_comm, nfs_comm)
return status, dirs
end
local function report(nfs, table)
local outtab, time = tab.new(), ""
if nfs.time == "mtime" then
time = "MODIFICATION TIME"
elseif nfs.time == "atime" then
time = "ACCESS TIME"
elseif nfs.time == "ctime" then
time = "CHANGE TIME"
end
tab.add(outtab, 1, "PERMISSION")
tab.add(outtab, 2, "UID")
tab.add(outtab, 3, "GID")
tab.add(outtab, 4, "SIZE")
tab.add(outtab, 5, time)
tab.add(outtab, 6, "FILENAME")
tab.nextrow(outtab)
for _,f in pairs(table) do
local perm = f.type .. f.mode
tab.addrow(outtab, perm, f.uid, f.gid,
f.size, f.time, f.filename)
end
return tab.dump(outtab)
return status
end
local mainaction = function(host)
local o, results, mounts, status = {}, {}, {}
local results, mounts, status = {}, {}
local nfs_info =
{
host = host,
--recurs = tonumber(nmap.registry.args['nfs-ls.recurs']) or 1,
}
local output = ls.new_listing()
nfs_info.version, nfs_info.maxfiles, nfs_info.time,
nfs_info.human = stdnse.get_script_args('nfs.version',
'nfs-ls.maxfiles','nfs-ls.time','nfs-ls.human')
nfs_info.maxfiles = tonumber(nfs_info.maxfiles) or 10
nfs_info.version, nfs_info.time = stdnse.get_script_args('nfs.version',
'nfs-ls.time')
nfs_info.maxfiles = ls.config('maxfiles')
nfs_info.human = ls.config('human')
if nfs_info.time == "a" or nfs_info.time == "A" then
nfs_info.time = "atime"
@@ -335,15 +363,6 @@ local mainaction = function(host)
nfs_info.time = "mtime"
end
if nfs_info.maxfiles > 0 then
local args = {}
args['name'] = 'Arguments:'
table.insert(args,
string.format("maxfiles: %d (file listing output limited)",
nfs_info.maxfiles))
table.insert(o, args)
end
status, mounts = procedures.ShowMounts(nfs_info.host)
if not status or mounts == nil then
if mounts then
@@ -354,22 +373,13 @@ local mainaction = function(host)
end
for _, v in ipairs(mounts) do
local results, access, err = {}, {}
status, err = nfs_ls(nfs_info, v.name, results, access)
if not status then
table.insert(o, string.format("\nNFS Export %s", v.name))
table.insert(o, string.format("ERROR: %s", err))
else
table.insert(o,
string.format("\nNFS Export: %s", results[1].filename))
if #access ~= 0 then
table.insert(o, string.format("NFS Access: %s", access[1]))
end
table.insert(o, {report(nfs_info, results)})
end
local err
ls.new_vol(output, v.name, true)
status = nfs_ls(nfs_info, v.name, output)
ls.end_vol(output)
end
return stdnse.format_output(true, o)
return ls.end_listing(output)
end
hostaction = function(host)

View File

@@ -1,8 +1,9 @@
local bit = require 'bit'
local smb = require 'smb'
local string = require 'string'
local stdnse = require 'stdnse'
local tab = require 'tab'
local table = require "table"
local ls = require 'ls'
local openssl= stdnse.silent_require 'openssl'
description = [[
@@ -13,32 +14,97 @@ The output is intended to resemble the output of the UNIX <code>ls</code> comman
---
-- @usage
-- nmap -p 445 <ip> --script smb-ls --script-args 'share=c$,path=\temp'
-- nmap -p 445 <ip> --script smb-enum-shares,smb-ls
--
-- @args smb-ls.share (or smb-ls.shares) the share (or a colon-separated list
-- of shares) to connect to (default: use shares found by smb-enum-shares)
-- @args smb-ls.path the path, relative to the share to list the contents from
-- (default: root of the share)
-- @args smb-ls.pattern the search pattern to execute (default: *)
-- @args smb-ls.checksum download each file and calculate a checksum
-- (default: false)
--
-- @output
-- Host script results:
-- | smb-ls:
-- | Directory of \\192.168.56.101\c$\
-- | 2007-12-02 00:20:09 0 AUTOEXEC.BAT
-- | 2007-12-02 00:20:09 0 CONFIG.SYS
-- | 2007-12-02 00:53:39 <DIR> Documents and Settings
-- | 2009-09-08 13:26:10 <DIR> e5a6b742d36facb19c5192852c43
-- | 2008-12-01 02:06:29 <DIR> Inetpub
-- | 2007-02-18 00:31:38 94720 msizap.exe
-- | 2007-12-02 00:55:01 <DIR> Program Files
-- | 2008-12-01 02:05:52 <DIR> temp
-- | 2011-12-16 14:40:18 <DIR> usr
-- | 2007-12-02 00:42:40 <DIR> WINDOWS
-- |_ 2007-12-02 00:22:38 <DIR> wmpub
--
-- @args smb-ls.share [optional] the share to connect to
-- @args smb-ls.shares [optional] a colon-separated list of shares to connect to
-- @args smb-ls.path [optional] the path, relative to the share to list the contents from
-- @args smb-ls.pattern [optional] the search pattern to execute (default: *)
-- @args smb-ls.maxdepth [optional] the maximum depth to recurse into a directory (default: no recursion)
-- @args smb-ls.maxfiles [optional] return only a certain amount of files
-- @args smb-ls.checksum [optional] download each file and calculate a SHA1 checksum
-- @args smb-ls.errors [optional] report connection errors
-- | Volume \\192.168.56.101\c$\
-- | SIZE TIME FILENAME
-- | 0 2007-12-02 00:20:09 AUTOEXEC.BAT
-- | 0 2007-12-02 00:20:09 CONFIG.SYS
-- | <DIR> 2007-12-02 00:53:39 Documents and Settings
-- | <DIR> 2009-09-08 13:26:10 e5a6b742d36facb19c5192852c43
-- | <DIR> 2008-12-01 02:06:29 Inetpub
-- | 94720 2007-02-18 00:31:38 msizap.exe
-- | <DIR> 2007-12-02 00:55:01 Program Files
-- | <DIR> 2008-12-01 02:05:52 temp
-- | <DIR> 2011-12-16 14:40:18 usr
-- | <DIR> 2007-12-02 00:42:40 WINDOWS
-- | <DIR> 2007-12-02 00:22:38 wmpub
-- |_
--
-- @xmloutput
-- <table key="volumes">
-- <table>
-- <table key="files">
-- <table>
-- <elem key="size">0</elem>
-- <elem key="time">2007-12-02 00:20:09</elem>
-- <elem key="filename">AUTOEXEC.BAT</elem>
-- </table>
-- <table>
-- <elem key="size">0</elem>
-- <elem key="time">2007-12-02 00:20:09</elem>
-- <elem key="filename">CONFIG.SYS</elem>
-- </table>
-- <table>
-- <elem key="size">&lt;DIR&gt;</elem>
-- <elem key="time">2007-12-02 00:53:39</elem>
-- <elem key="filename">Documents and Settings</elem>
-- </table>
-- <table>
-- <elem key="size">&lt;DIR&gt;</elem>
-- <elem key="time">2009-09-08 13:26:10</elem>
-- <elem key="filename">e5a6b742d36facb19c5192852c43</elem>
-- </table>
-- <table>
-- <elem key="size">&lt;DIR&gt;</elem>
-- <elem key="time">2008-12-01 02:06:29</elem>
-- <elem key="filename">Inetpub</elem>
-- </table>
-- <table>
-- <elem key="size">94720</elem>
-- <elem key="time">2007-02-18 00:31:38</elem>
-- <elem key="filename">msizap.exe</elem>
-- </table>
-- <table>
-- <elem key="size">&lt;DIR&gt;</elem>
-- <elem key="time">2007-12-02 00:55:01</elem>
-- <elem key="filename">Program Files</elem>
-- </table>
-- <table>
-- <elem key="size">&lt;DIR&gt;</elem>
-- <elem key="time">2008-12-01 02:05:52</elem>
-- <elem key="filename">temp</elem>
-- </table>
-- <table>
-- <elem key="size">&lt;DIR&gt;</elem>
-- <elem key="time">2011-12-16 14:40:18</elem>
-- <elem key="filename">usr</elem>
-- </table>
-- <table>
-- <elem key="size">&lt;DIR&gt;</elem>
-- <elem key="time">2007-12-02 00:42:40</elem>
-- <elem key="filename">WINDOWS</elem>
-- </table>
-- <table>
-- <elem key="size">&lt;DIR&gt;</elem>
-- <elem key="time">2007-12-02 00:22:38</elem>
-- <elem key="filename">wmpub</elem>
-- </table>
-- </table>
-- <elem key="volume">\\192.168.1.2\Downloads</elem>
-- </table>
-- </table>
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
@@ -49,10 +115,6 @@ local arg_shares = stdnse.get_script_args(SCRIPT_NAME .. '.shares')
local arg_share = stdnse.get_script_args(SCRIPT_NAME .. '.share')
local arg_path = stdnse.get_script_args(SCRIPT_NAME .. '.path') or '\\'
local arg_pattern = stdnse.get_script_args(SCRIPT_NAME .. '.pattern') or '*'
local arg_maxfiles = tonumber(stdnse.get_script_args(SCRIPT_NAME .. '.maxfiles'))
local arg_maxdepth = stdnse.get_script_args(SCRIPT_NAME .. '.maxdepth')
local arg_checksum = stdnse.get_script_args(SCRIPT_NAME .. '.checksum')
local arg_errors = stdnse.get_script_args(SCRIPT_NAME .. '.errors')
hostrule = function(host)
return ( smb.get_port(host) ~= nil and
@@ -65,7 +127,45 @@ local function is_dir(fe)
return ( bit.band(fe.attrs, 16) == 16 )
end
local function fail(err) return stdnse.format_output(false, err) end
local function list_files(host, share, smbstate, path, options, output, maxdepth, basedir)
basedir = basedir or ""
local continue
for fe in smb.find_files(smbstate, path .. '\\' .. arg_pattern, options) do
if basedir == "" or (fe.fname ~= "." and fe.fname ~= "..") then
if ls.config('checksum') and not(is_dir(fe)) then
local status, content = smb.file_read(host, share, path .. '\\' .. fe.fname, nil, {file_create_disposition=1})
local sha1 = status and stdnse.tohex(openssl.sha1(content)) or ""
continue = ls.add_file(output, {is_dir(fe) and '<DIR>' or fe.eof,
fe.created, basedir .. fe.fname, sha1})
else
continue = ls.add_file(output, {is_dir(fe) and '<DIR>' or fe.eof,
fe.created, basedir .. fe.fname})
end
if not continue then
return false
end
if is_dir(fe) then
continue = true
if maxdepth > 0 then
continue = list_files(host, share, smbstate,
path .. '\\' .. fe.fname, options,
output, maxdepth - 1,
basedir .. fe.fname .. '\\')
elseif maxdepth < 0 then
continue = list_files(host, share, smbstate,
path .. '\\' .. fe.fname, options,
output, -1,
basedir .. fe.fname .. '\\')
end
if not continue then
return false
end
end
end
end
return true
end
action = function(host)
@@ -78,91 +178,40 @@ action = function(host)
arg_shares = host.registry['smb_shares']
end
-- arg_maxdepth defaults to 1 (no recursion)
if arg_maxdepth == nil then
arg_maxdepth = 1
else
arg_maxdepth = tonumber(arg_maxdepth)
end
local output = {}
local output = ls.new_listing()
for _, share in ipairs(arg_shares) do
local status, smbstate = smb.start_ex(host, true, true, share,
nil, nil, nil)
if ( not(status) ) then
if arg_errors then
table.insert(
output,
("Failed to authenticate to server (%s) for directory of \\\\%s\\%s%s"):format(smbstate, stdnse.get_hostname(host), share, arg_path))
table.insert(output, "")
end
ls.report_error(
output,
("Failed to authenticate to server (%s) for directory of \\\\%s\\%s%s"):format(smbstate, stdnse.get_hostname(host), share, arg_path))
else
table.insert(output, "")
-- remove leading slash
arg_path = ( arg_path:sub(1,2) == '\\' and arg_path:sub(2) or arg_path )
-- fixup checksum argument
arg_checksum = ( arg_checksum == 'true' or arg_checksum == '1' ) and true or false
local options = { max_depth = arg_maxdepth, max_files = arg_maxfiles }
local options = {}
local depth, path, dirs = 0, arg_path, {}
local file_count, dir_count, total_bytes = 0, 0, 0
local continue = true
repeat
-- we need three columns per row, plus one for checksum if
-- requested
local lstab = tab.new((arg_checksum and 4 or 3))
for fe in smb.find_files(smbstate, path .. '\\' .. arg_pattern, options ) do
if ( arg_checksum and not(is_dir(fe)) ) then
local status, content = smb.file_read(host, share, path .. '\\' .. fe.fname, nil, {file_create_disposition=1})
local sha1 = ( status and stdnse.tohex(openssl.sha1(content)) or "" )
tab.addrow(lstab, fe.created, (is_dir(fe) and '<DIR>' or fe.eof), fe.fname, sha1)
else
tab.addrow(lstab, fe.created, (is_dir(fe) and '<DIR>' or fe.eof), fe.fname)
end
arg_maxfiles = ( arg_maxfiles and arg_maxfiles - 1 )
if ( arg_maxfiles == 0 ) then
break
end
if ( is_dir(fe) ) then
dir_count = dir_count + 1
if ( fe.fname ~= '.' and fe.fname ~= '..' ) then
table.insert(dirs, { depth = depth + 1, path = path .. '\\' .. fe.fname } )
end
else
total_bytes = total_bytes + fe.eof
file_count = file_count + 1
end
end
table.insert(output, { name = ("Directory of %s"):format( '\\\\' .. stdnse.get_hostname(host) .. '\\' .. share .. path), tab.dump(lstab) })
path = nil
if ( #dirs ~= 0 ) then
local dir = table.remove(dirs, 1)
depth = dir.depth
if ( not(arg_maxdepth) or ( dir.depth < arg_maxdepth ) ) then
path = dir.path
table.insert(output, "")
end
end
until(not(path) or arg_maxfiles == 0)
ls.new_vol(
output,
'\\\\' .. stdnse.get_hostname(host) .. '\\' .. share .. path,
false)
continue = list_files(host, share, smbstate, path, options,
output, ls.config('maxdepth'))
if not continue then
ls.report_info(
output,
string.format("maxfiles limit reached (%d)", ls.config('maxfiles')))
end
ls.end_vol(output)
smb.stop(smbstate)
local summary = { name = "Total Files Listed:",
("%8d File(s)\t%d bytes"):format(file_count, total_bytes),
("%8d Dir(s)"):format(dir_count) }
table.insert(output, "")
table.insert(output, summary)
table.insert(output, "")
end
end
return stdnse.format_output(true, output)
return ls.end_listing(output)
end