1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-15 12:19:02 +00:00

o [NSE] Added SPNEGO authentication supporting Windows 7 and Windows 2008 to

the smb library. [Patrik Karlsson]
This commit is contained in:
patrik
2012-06-09 12:17:01 +00:00
parent 0c4e3d0446
commit bc0defc8ff
4 changed files with 80 additions and 13 deletions

View File

@@ -1,5 +1,8 @@
# Nmap Changelog ($Id$); -*-text-*-
o [NSE] Added SPNEGO authentication supporting Windows 7 and Windows 2008 to
the smb library. [Patrik Karlsson]
o Fixed an error that occurred when scanning certain addresses like
192.168.0.0 on Windows XP:
get_srcaddr: can't connect socket: The requested address is not valid in its context.

View File

@@ -277,11 +277,12 @@ ASN1Decoder = {
--
ASN1Encoder = {
new = function(self,o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
new = function(self)
local o = {}
setmetatable(o, self)
self.__index = self
o:registerBaseEncoders()
return o
end,
---
@@ -332,6 +333,14 @@ ASN1Encoder = {
end
end
-- Table encoder
self.encoder['table'] = function( self, val )
assert('table' == type(val), "val is not a table")
assert(#val.type > 0, "Table is missing the type field")
assert(val.value ~= nil, "Table is missing the value field")
return bin.pack("HAA", val.type, self.encodeLength(#val.value), val.value)
end
-- Integer encoder
self.encoder['number'] = function( self, val )
local ival = self.encodeInt(val)

View File

@@ -121,6 +121,7 @@
-- @author Ron Bowes <ron@skullsecurity.net>
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
-----------------------------------------------------------------------
local asn1 = require "asn1"
local bin = require "bin"
local bit = require "bit"
local coroutine = require "coroutine"
@@ -1029,6 +1030,9 @@ function negotiate_protocol(smb, overrides)
if(smb['key_length'] == nil) then
smb['key_length'] = 0
end
if(smb['byte_count'] == nil) then
smb['byte_count'] = 0
end
-- Convert the time and timezone to more useful values
smb['time'] = (smb['time'] / 10000000) - 11644473600
@@ -1053,6 +1057,11 @@ function negotiate_protocol(smb, overrides)
if(smb['server_guid'] == nil) then
return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [12]"
end
-- do we have a security blob?
if ( #data - pos > 0 ) then
pos, smb['security_blob'] = bin.unpack("<A" .. #data - pos, data, pos )
end
else
pos, smb['server_challenge'] = bin.unpack(string.format("<A%d", smb['key_length']), data)
if(smb['server_challenge'] == nil) then
@@ -1279,6 +1288,13 @@ local function start_session_extended(smb, log_errors, overrides)
end
end
-- check what kind of security blob we were given in the negotiate protocol request
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
end
while result ~= false do
-- These are loop variables
local security_blob = nil
@@ -1287,7 +1303,42 @@ local function start_session_extended(smb, log_errors, overrides)
-- This loop takes care of the multiple packets that "extended security" requires
repeat
-- Get the new security blob, passing the old security blob as a parameter. If there was no previous security blob, then nil is passed, which creates a new one
status, security_blob, smb['mac_key'] = smbauth.get_security_blob(security_blob, smb['ip'], username, domain, password, password_hash, hash_type)
if ( not(security_blob) ) then
status, security_blob, smb['mac_key'] = smbauth.get_security_blob(security_blob, smb['ip'], username, domain, password, password_hash, hash_type, (sp_nego and 0x00088215))
if ( sp_nego ) then
local enc = asn1.ASN1Encoder:new()
local mechtype = enc:encode( { type = 'A0', value = enc:encode( { type = '30', value = enc:encode( { type = '06', value = bin.pack("H", "2b06010401823702020a") } ) } ) } )
local oid = enc:encode( { type = '06', value = bin.pack("H", "2b0601050502") } )
security_blob = enc:encode(security_blob)
security_blob = enc:encode( { type = 'A2', value = security_blob } )
security_blob = mechtype .. security_blob
security_blob = enc:encode( { type = '30', value = security_blob } )
security_blob = enc:encode( { type = 'A0', value = security_blob } )
security_blob = oid .. security_blob
security_blob = enc:encode( { type = '60', value = security_blob } )
end
else
if ( sp_nego ) then
if ( smb['domain'] or smb['server'] and ( not(domain) or #domain == 0 ) ) then
domain = smb['domain'] or smb['server']
end
hash_type = "v2"
end
status, security_blob, smb['mac_key'] = smbauth.get_security_blob(security_blob, smb['ip'], username, domain, password, password_hash, hash_type, (sp_nego and 0x00088215))
if ( sp_nego ) then
local enc = asn1.ASN1Encoder:new()
security_blob = enc:encode(security_blob)
security_blob = enc:encode( { type = 'A2', value = security_blob } )
security_blob = enc:encode( { type = '30', value = security_blob } )
security_blob = enc:encode( { type = 'A1', value = security_blob } )
end
end
-- There was an error processing the security blob
if(status == false) then
@@ -1351,6 +1402,12 @@ local function start_session_extended(smb, log_errors, overrides)
-- Parse the data
pos, security_blob, os, lanmanager = bin.unpack(string.format("<A%dzz", security_blob_length), data)
if ( status_name == "NT_STATUS_MORE_PROCESSING_REQUIRED" and sp_nego ) then
local start = security_blob:find("NTLMSSP")
security_blob = security_blob:sub(start)
end
if(security_blob == nil or lanmanager == nil) then
return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [19]"
end

View File

@@ -667,10 +667,10 @@ function get_password_response(ip, username, domain, password, password_hash, ha
return lm_response, ntlm_response, mac_key
end
function get_security_blob(security_blob, ip, username, domain, password, password_hash, hash_type)
function get_security_blob(security_blob, ip, username, domain, password, password_hash, hash_type, flags)
local pos = 1
local new_blob
local flags = 0x00008215 -- (NEGOTIATE_SIGN_ALWAYS | NEGOTIATE_NTLM | NEGOTIATE_SIGN | REQUEST_TARGET | NEGOTIATE_UNICODE)
local flags = flags or 0x00008215 -- (NEGOTIATE_SIGN_ALWAYS | NEGOTIATE_NTLM | NEGOTIATE_SIGN | REQUEST_TARGET | NEGOTIATE_UNICODE)
if(security_blob == nil) then
-- If security_blob is nil, this is the initial packet
@@ -684,10 +684,8 @@ function get_security_blob(security_blob, ip, username, domain, password, passwo
return true, new_blob, "", ""
else
local identifier, message_type, domain_length, domain_max, domain_offset, server_flags, challenge, reserved
-- Parse the old security blob
pos, identifier, message_type, domain_length, domain_max, domain_offset, server_flags, challenge, reserved = bin.unpack("<LISSIIA8A8", security_blob, 1)
local pos, identifier, message_type, domain_length, domain_max, domain_offset, server_flags, challenge, reserved = bin.unpack("<LISSIIA8A8", security_blob, 1)
-- Get the information for the current login
local lanman, ntlm, mac_key = get_password_response(ip, username, domain, password, password_hash, hash_type, challenge, true)