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'))