1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 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
|