1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-10 17:59:04 +00:00
Files
nmap/scripts/smb-enumshares.nse
david ae7455279e Add a new msrpc.lua module, plus new scripts smb-enumdomains.nse,
smb-enumshares.nse, and smb-enumusers.nse. Also enhance the netbios.lua and
smb.lua modules. Remove the smb-enum.nse script. All these changes are from Ron
Bowes.
2008-10-04 21:58:39 +00:00

180 lines
5.6 KiB
Lua

--- Attempts to call the srvsvc.NetShareEnumAll() MSRPC function. This will
-- likely only work anonymously against Windows 2000. \n
--\n
-- There isn't a whole lot to say about this one. The sequence of calls after
-- the initial bind() is:\n
-- NetShareEnumAll()\n
--\n
-- Since NetShareEnumAll() only works anonymously, if it fails this will check
-- a handful of common shares. \n
--\n
-- Once it has a list of shares, whether it was pulled over MSRPC or guessed,
-- we attempt to connect to each of them with a standard smb tree_connect request
-- over a null session. We record which ones succeeded and failed (that is, which
-- shares allowed for anonymous access).\n
--
--@usage
-- nmap --script smb-enumshares.nse -p445 <host>\n
-- sudo nmap -sU -sS --script smb-enumshares.nse -p U:137,T:139 <host>\n
--
--@output
-- Host script results:\n
-- TODO
-----------------------------------------------------------------------
id = "MSRPC: NetShareEnumAll()"
description = "Tries calling the NetShareEnumAll() RPC function, and guessing shares"
author = "Ron Bowes"
copyright = "Ron Bowes"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"discovery","intrusive"}
require 'msrpc'
require 'smb'
require 'stdnse'
hostrule = function(host)
local port = smb.get_port(host)
if(port == nil) then
return false
else
return true
end
end
---Attempts to enumerate the shares on a remote system using MSRPC calls. This will likely fail
-- against a modern system, but will succeed against Windows 2000.
--
--@param host The host object.
--@return (status, result) If status is false, result is an error string. Otherwise, result is
-- a list of all shares on a system.
local function samr_enum_shares(host)
local status, socket, uid, tid, fid
local bind_result, netshareenumall_result
-- Create the SMB session
status, socket, uid, tid, fid = msrpc.start_smb(host, msrpc.SRVSVC_PATH)
if(status == false) then
return false, socket
end
-- Bind to SRVSVC service
status, bind_result = msrpc.bind(socket, msrpc.SRVSVC_UUID, msrpc.SRVSVC_VERSION, nil, uid, tid, fid)
if(status == false) then
smb.stop(socket)
return false, bind_result
end
-- Call netsharenumall
status, netshareenumall_result = msrpc.srvsvc_netshareenumall(socket, host.ip, uid, tid, fid)
if(status == false) then
smb.stop(socket)
return false, netshareenumall_result
end
-- Stop the SMB session
smb.stop(socket, uid, tid)
return true, netshareenumall_result['shares']
end
---Attempts to connect to a list of shares as the anonymous user, returning which ones
-- it has and doesn't have access to.
--
--@param host The host object
--@param shares An array of shares to check
--@return (allowed_shares, denied_shares) Lists of shares we can and can't access,
-- but all of which exist.
function check_shares(host, shares)
local i
local allowed_shares = {}
local denied_shares = {}
-- Begin the SMB session
status, socket = smb.start(host)
if(status == false) then
return false, socket
end
-- Negotiate the protocol
status, negotiate_result = smb.negotiate_protocol(socket)
if(status == false) then
smb.stop(socket)
return false, negotiate_result
end
-- Start up a null session
status, session_result = smb.start_session(socket, "", negotiate_result['session_key'], negotiate_result['capabilities'])
if(status == false) then
smb.stop(socket)
return false, session_result
end
-- Connect to the shares
stdnse.print_debug(2, "EnumShares: Testing %d shares", #shares)
for i = 1, #shares, 1 do
-- Change the share to the '\\ip\share' format
local share = string.format("\\\\%s\\%s", host.ip, shares[i])
-- Try connecting to the tree
stdnse.print_debug(3, "EnumShares: Testing share %s", share)
status, tree_result = smb.tree_connect(socket, share, session_result['uid'])
-- If it fails, checkwhy
if(status == false) then
-- If the result was ACCESS_DENIED, record it
if(tree_result == 0xc0000022 or tree_result == 'NT_STATUS_ACCESS_DENIED') then
stdnse.print_debug(3, "EnumShares: Access was denied")
denied_shares[#denied_shares + 1] = shares[i]
else
stdnse.print_debug(3, "EnumShares: Share didn't pan out: %s", tree_result)
end
else
-- Add it to allowed shares
stdnse.print_debug(3, "EnumShares: Access was granted")
allowed_shares[#allowed_shares + 1] = shares[i]
smb.tree_disconnect(socket, session_result['uid'], tree_result['tid'])
end
end
-- Log off the user
smb.stop(socket, session_result['uid'])
return allowed_shares, denied_shares
end
action = function(host)
local result, shared
local response = " \n"
local shares = {}
local allowed, denied
-- Try and do this the good way, make a MSRPC call to get the shares
result, shares = samr_enum_shares(host)
-- If that failed, try doing it with brute force. This almost certainly won't find everything, but it's the
-- best we can do.
if(result == false) then
response = response .. string.format("Couldn't enum all shares, checking for common ones (%s)\n", shares)
-- Take some common share names I've seen
shares = {"IPC$", "ADMIN$", "TEST", "TEST$", "HOME", "HOME$"}
-- Try every alphabetic share, with and without a trailing '$'
for i = string.byte("A", 1), string.byte("Z", 1), 1 do
shares[#shares + 1] = string.char(i)
shares[#shares + 1] = string.char(i) .. "$"
end
end
-- Break them into anonymous/authenticated shares
allowed, denied = check_shares(host, shares)
return response .. string.format("Anonymous shares: %s\nRestricted shares: %s\n", stdnse.strjoin(", ", allowed), stdnse.strjoin(", ", denied))
end