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