From b0228a212b93753021c9b2315050f4030bf96b50 Mon Sep 17 00:00:00 2001 From: paulino Date: Sat, 27 May 2017 07:28:44 +0000 Subject: [PATCH] Updates smb.lua and msrpc.lua to support fully qualified path names as share names and updates match for OID. Modern Windows versions require FQPN and older version work the same. The level of information requested with the call NetShareGetInfo was reduced to support newer versions of Windows. This closes #266, closes #704, closes #238, and closes #883. --- CHANGELOG | 4 ++++ nselib/msrpc.lua | 16 +++++++++++++--- nselib/smb.lua | 33 +++++++++++++++++++++++++++------ scripts/smb-ls.nse | 3 ++- 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1258e2350..25a04dca3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ # Nmap Changelog ($Id$); -*-text-*- +o [NSE][GH#266][GH#704][GH#238][GH#883] NSE libraries smb and msrpc now use + fully qualified paths. SMB scripts now work against all modern versions + of Microsoft Windows. [Paulino Calderon] + o New service probes and matches for Apache HBase and Hadoop MapReduce. [Paulino Calderon] diff --git a/nselib/msrpc.lua b/nselib/msrpc.lua index a8989aa26..afb66ee65 100644 --- a/nselib/msrpc.lua +++ b/nselib/msrpc.lua @@ -200,8 +200,10 @@ local UUID2EXE = { --@return status true or false --@return smbstate if status is true, or an error message. function start_smb(host, path, disable_extended, overrides) + local sharename overrides = overrides or {} - return smb.start_ex(host, true, true, "IPC$", path, disable_extended, overrides) + _, sharename = smb.get_fqpn(host, "IPC$") + return smb.start_ex(host, true, true, sharename, path, disable_extended, overrides) end --- A wrapper around the smb.stop function. @@ -663,10 +665,17 @@ end --@return (status, result) If status is false, result is an error message. Otherwise, result is a table of values, the most -- useful one being 'shares', which is a list of the system's shares. function srvsvc_netsharegetinfo(smbstate, server, share, level) - local status, result + stdnse.debug2("Calling NetShareGetInfo(%s, %s, %d)", server, share, level) + local status, result, sharename local arguments local pos, align + --NetGetShareInfo seems to reject FQPN and reads the server value from the request + --If any function called this function using a FQPN, this should take care of it. + _, _, sharename = string.find(share, "\\\\.*\\(.*)") + if sharename then + share = sharename + end -- [in] [string,charset(UTF16)] uint16 *server_unc, arguments = msrpctypes.marshall_unicode_ptr("\\\\" .. server, true) @@ -4705,7 +4714,8 @@ function get_share_info(host, name) end -- Call NetShareGetInfo - local status, netsharegetinfo_result = srvsvc_netsharegetinfo(smbstate, host.ip, name, 2) + + local status, netsharegetinfo_result = srvsvc_netsharegetinfo(smbstate, host.ip, name, 1) if(status == false) then smb.stop(smbstate) return false, netsharegetinfo_result diff --git a/nselib/smb.lua b/nselib/smb.lua index 02a28c0f6..efd31e2cd 100644 --- a/nselib/smb.lua +++ b/nselib/smb.lua @@ -1316,7 +1316,7 @@ local function start_session_extended(smb, log_errors, overrides) local sp_nego = false if ( smb['security_blob'] and #smb['security_blob'] > 11 ) then local pos, oid = bin.unpack(">A6", smb['security_blob'], 5) - sp_nego = ( oid == "\x2b\x06\x01\x05\x05\x02" ) -- check for SPNEGO OID 1.3.6.1.5.5.2 + sp_nego = ( oid == "\x2b\x06\x01\x05\x05\x02" or oid == "\x06\x06\x2b\x06\x01\x05" ) -- check for SPNEGO OID 1.3.6.1.5.5.2 end local ntlm_challenge_accepted = false @@ -3075,6 +3075,12 @@ function share_get_details(host, share) local i local details = {} + --Transform name to FQPN form + status, share = get_fqpn(host, share) + if not status then + stdnse.debug1("SMB:Couldn't obtain FQPN share name. Trying with '%s'", share) + end + -- Save the name details['name'] = share @@ -3442,7 +3448,7 @@ end -- 'false' is simply returned. function is_admin(host, username, domain, password, password_hash, hash_type) local msrpc = require "msrpc" -- avoid require cycle - local status, smbstate, err, result + local status, smbstate, err, result, fqpn_share local overrides = get_overrides(username, domain, password, password_hash, hash_type) stdnse.debug1("SMB: Checking if %s is an administrator", username) @@ -3467,8 +3473,9 @@ function is_admin(host, username, domain, password, password_hash, hash_type) stop(smbstate) return false end - - status, err = tree_connect(smbstate, "IPC$", overrides) + + _, fqpn_share = get_fqpn(host, "IPC$") + status, err = tree_connect(smbstate, fqpn_share, overrides) if(status == false) then stdnse.debug1("SMB; is_admin: Failed to connect tree: %s [%s]", err, username) stop(smbstate) @@ -3502,6 +3509,19 @@ function is_admin(host, username, domain, password, password_hash, hash_type) return true end +--- +-- Returns the fully qualified path name (FQPN) for shares. +-- This is required for modern versions of Windows. +-- Returns \\\ when successful. Otherwise, returns the same share name. +--- +function get_fqpn(host, sharename) + if host.ip and sharename then + return true, string.format("\\\\%s\\%s", host.ip, sharename) + end + stdnse.debug1("SMB: get_fqpn: Couldn't determine server IP address") + return false, sharename +end + command_codes = { SMB_COM_CREATE_DIRECTORY = 0x00, @@ -4213,10 +4233,11 @@ namedpipes = self.name = namedpipes.make_pipe_name( self._host.ip, self._pipeSubPath ) stdnse.debug2("%s: Connecting to named pipe: %s", NP_LIBRARY_NAME, self.name ) - local status, result, errorMessage + local status, result, errorMessage, fqpn_share local bool_negotiate_protocol, bool_start_session, bool_disable_extended = true, true, false + _, fqpn_share = get_fqpn(host, "IPC$") status, result = start_ex( self._host, bool_negotiate_protocol, bool_start_session, - "IPC$", self._pipeSubPath, bool_disable_extended, self._overrides ) + fqpn_share, self._pipeSubPath, bool_disable_extended, self._overrides ) if status then self._smbstate = result diff --git a/scripts/smb-ls.nse b/scripts/smb-ls.nse index 1bf808830..609900340 100644 --- a/scripts/smb-ls.nse +++ b/scripts/smb-ls.nse @@ -181,6 +181,7 @@ action = function(host) local output = ls.new_listing() for _, share in ipairs(arg_shares) do + stdnse.debug1("Share name:%s", share) local status, smbstate = smb.start_ex(host, true, true, share, nil, nil, nil) if ( not(status) ) then @@ -199,7 +200,7 @@ action = function(host) ls.new_vol( output, - '\\\\' .. stdnse.get_hostname(host) .. '\\' .. share .. path, + share .. path, false) continue = list_files(host, share, smbstate, path, options, output, ls.config('maxdepth'))