summaryrefslogtreecommitdiffstats
path: root/scripts/smb-enum-shares.nse
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/smb-enum-shares.nse')
-rw-r--r--scripts/smb-enum-shares.nse194
1 files changed, 194 insertions, 0 deletions
diff --git a/scripts/smb-enum-shares.nse b/scripts/smb-enum-shares.nse
new file mode 100644
index 0000000..f21dac4
--- /dev/null
+++ b/scripts/smb-enum-shares.nse
@@ -0,0 +1,194 @@
+local smb = require "smb"
+local stdnse = require "stdnse"
+local string = require "string"
+local table = require "table"
+
+description = [[
+Attempts to list shares using the <code>srvsvc.NetShareEnumAll</code> MSRPC function and
+retrieve more information about them using <code>srvsvc.NetShareGetInfo</code>. If access
+to those functions is denied, a list of common share names are checked.
+
+Finding open shares is useful to a penetration tester because there may be private files
+shared, or, if it's writable, it could be a good place to drop a Trojan or to infect a file
+that's already there. Knowing where the share is could make those kinds of tests more useful,
+except that determining where the share is requires administrative privileges already.
+
+Running <code>NetShareEnumAll</code> will work anonymously against Windows 2000, and
+requires a user-level account on any other Windows version. Calling <code>NetShareGetInfo</code>
+requires an administrator account on all versions of Windows up to 2003, as well as Windows Vista
+and Windows 7, if UAC is turned down.
+
+Even if <code>NetShareEnumAll</code> is restricted, attempting to connect to a share will always
+reveal its existence. So, if <code>NetShareEnumAll</code> fails, a pre-generated list of shares,
+based on a large test network, are used. If any of those succeed, they are recorded.
+
+After a list of shares is found, the script attempts to connect to each of them anonymously,
+which divides them into "anonymous", for shares that the NULL user can connect to, or "restricted",
+for shares that require a user account.
+]]
+
+---
+--@usage
+-- nmap --script smb-enum-shares.nse -p445 <host>
+-- sudo nmap -sU -sS --script smb-enum-shares.nse -p U:137,T:139 <host>
+--
+--@output
+-- Host script results:
+-- | smb-enum-shares:
+-- | account_used: WORKGROUP\Administrator
+-- | ADMIN$
+-- | Type: STYPE_DISKTREE_HIDDEN
+-- | Comment: Remote Admin
+-- | Users: 0
+-- | Max Users: <unlimited>
+-- | Path: C:\WINNT
+-- | Anonymous access: <none>
+-- | Current user access: READ/WRITE
+-- | C$
+-- | Type: STYPE_DISKTREE_HIDDEN
+-- | Comment: Default share
+-- | Users: 0
+-- | Max Users: <unlimited>
+-- | Path: C:\
+-- | Anonymous access: <none>
+-- | Current user access: READ
+-- | IPC$
+-- | Type: STYPE_IPC_HIDDEN
+-- | Comment: Remote IPC
+-- | Users: 1
+-- | Max Users: <unlimited>
+-- | Path:
+-- | Anonymous access: READ
+-- |_ Current user access: READ
+--
+-- @xmloutput
+-- <elem key="account_used">WORKGROUP\Administrator</elem>
+-- <table key="ADMIN$">
+-- <elem key="Type">STYPE_DISKTREE_HIDDEN</elem>
+-- <elem key="Comment">Remote Admin</elem>
+-- <elem key="Users">0</elem>
+-- <elem key="Max Users"><unlimited></elem>
+-- <elem key="Path">C:\WINNT</elem>
+-- <elem key="Anonymous access"><none></elem>
+-- <elem key="Current user access">READ/WRITE</elem>
+-- </table>
+-- <table key="C$">
+-- <elem key="Type">STYPE_DISKTREE_HIDDEN</elem>
+-- <elem key="Comment">Default share</elem>
+-- <elem key="Users">0</elem>
+-- <elem key="Max Users"><unlimited></elem>
+-- <elem key="Path">C:\</elem>
+-- <elem key="Anonymous access"><none></elem>
+-- <elem key="Current user access">READ</elem>
+-- </table>
+-- <table key="IPC$">
+-- <elem key="Type">STYPE_IPC_HIDDEN</elem>
+-- <elem key="Comment">Remote IPC</elem>
+-- <elem key="Users">1</elem>
+-- <elem key="Max Users"><unlimited></elem>
+-- <elem key="Path"></elem>
+-- <elem key="Anonymous access">READ</elem>
+-- <elem key="Current user access">READ</elem>
+-- </table>
+
+author = "Ron Bowes"
+copyright = "Ron Bowes"
+license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
+categories = {"discovery","intrusive"}
+dependencies = {"smb-brute"}
+
+
+hostrule = function(host)
+ return smb.get_port(host) ~= nil
+end
+
+action = function(host)
+ local status, shares, extra
+ local response = stdnse.output_table()
+
+ -- Get the list of shares
+ status, shares, extra = smb.share_get_list(host)
+ if(status == false) then
+ return stdnse.format_output(false, string.format("Couldn't enumerate shares: %s", shares))
+ end
+
+ if(extra ~= nil and extra ~= '') then
+ response.note = extra
+ end
+
+ -- Find out who the current user is
+ local result, username, domain = smb.get_account(host)
+ if(result == false) then
+ username = "<unknown>"
+ domain = ""
+ end
+ if domain and domain ~= "" then
+ domain = domain .. "\\"
+ end
+ response.account_used = string.format("%s%s", domain, stdnse.string_or_blank(username, '<blank>'))
+
+ if host.registry['smb_shares'] == nil then
+ host.registry['smb_shares'] = {}
+ end
+
+ for i = 1, #shares, 1 do
+ local share = shares[i]
+ local share_output = stdnse.output_table()
+
+ if(type(share['details']) ~= 'table') then
+ share_output['warning'] = string.format("Couldn't get details for share: %s", share['details'])
+ -- A share of 'NT_STATUS_OBJECT_NAME_NOT_FOUND' indicates this isn't a fileshare
+ if(share['user_can_write'] == "NT_STATUS_OBJECT_NAME_NOT_FOUND") then
+ share_output["Type"] = "Not a file share"
+ else
+ table.insert(host.registry['smb_shares'], share.name)
+ end
+ else
+ local details = share['details']
+
+ share_output["Type"] = details.sharetype
+ share_output["Comment"] = details.comment
+ share_output["Users"] = details.current_users
+ share_output["Max Users"] = details.max_users
+ share_output["Path"] = details.path
+
+ if (share_output["Type"] == "STYPE_DISKTREE" or
+ share_output["Type"] == "STYPE_DISKTREE_TEMPORARY" or
+ share_output["Type"] == "STYPE_DISKTREE_HIDDEN") then
+ table.insert(host.registry['smb_shares'], share.name)
+ end
+ end
+ -- Print details for a file share
+ if(share['anonymous_can_read'] and share['anonymous_can_write']) then
+ share_output["Anonymous access"] = "READ/WRITE"
+ elseif(share['anonymous_can_read'] and not(share['anonymous_can_write'])) then
+ share_output["Anonymous access"] = "READ"
+ elseif(not(share['anonymous_can_read']) and share['anonymous_can_write']) then
+ share_output["Anonymous access"] = "WRITE"
+ else
+ share_output["Anonymous access"] = "<none>"
+ end
+
+ -- Don't bother printing this if we're already anonymous
+ if(username ~= '') then
+ if(share['user_can_read'] and share['user_can_write']) then
+ share_output["Current user access"] = "READ/WRITE"
+ elseif(share['user_can_read'] and not(share['user_can_write'])) then
+ share_output["Current user access"] = "READ"
+ elseif(not(share['user_can_read']) and share['user_can_write']) then
+ share_output["Current user access"] = "WRITE"
+ else
+ share_output["Current user access"] = "<none>"
+ end
+ end
+
+ response[share.name] = share_output
+ end
+
+ if next(host.registry['smb_shares']) == nil then
+ host.registry['smb_shares'] = nil
+ end
+
+ return response
+end
+