mirror of
https://github.com/nmap/nmap.git
synced 2025-12-15 04:09:01 +00:00
Use unicode library for msrpc/smb
This commit is contained in:
@@ -109,6 +109,7 @@ local os = require "os"
|
||||
local stdnse = require "stdnse"
|
||||
local string = require "string"
|
||||
local table = require "table"
|
||||
local unicode = require "unicode"
|
||||
_ENV = stdnse.module("msrpctypes", stdnse.seeall)
|
||||
|
||||
local REFERENT_ID = 0x50414d4e
|
||||
@@ -125,7 +126,6 @@ local ALL = 'ALL'
|
||||
--@return The unicode version of the string.
|
||||
function string_to_unicode(string, do_null)
|
||||
local i
|
||||
local result = ""
|
||||
|
||||
stdnse.print_debug(4, "MSRPC: Entering string_to_unicode(string = %s)", string)
|
||||
|
||||
@@ -143,19 +143,16 @@ function string_to_unicode(string, do_null)
|
||||
end
|
||||
|
||||
|
||||
-- Loop through the string, adding each character followed by a char(0)
|
||||
for i = 1, #string, 1 do
|
||||
result = result .. string.sub(string, i, i) .. string.char(0)
|
||||
end
|
||||
local result = unicode.utf8to16(string)
|
||||
|
||||
-- Add a null, if the caller requested it
|
||||
if(do_null == true) then
|
||||
result = result .. string.char(0) .. string.char(0)
|
||||
result = result .. "\0\0"
|
||||
end
|
||||
|
||||
-- Align it to a multiple of 4, if necessary
|
||||
if(#result % 4 ~= 0) then
|
||||
result = result .. string.char(0) .. string.char(0)
|
||||
result = result .. "\0\0"
|
||||
end
|
||||
|
||||
stdnse.print_debug(4, "MSRPC: Leaving string_to_unicode()")
|
||||
@@ -173,48 +170,28 @@ end
|
||||
--@return (pos, string) The new position and the string read, again imitating <code>bin.unpack</code>. If there was an
|
||||
-- attempt to read off the end of the string, then 'nil' is returned for both parameters.
|
||||
function unicode_to_string(buffer, pos, length, do_null)
|
||||
local i, j, ch, dummy
|
||||
local string = ""
|
||||
|
||||
stdnse.print_debug(4, "MSRPC: Entering unicode_to_string(pos = %d, length = %d)", pos, length)
|
||||
|
||||
if(do_null == nil) then
|
||||
do_null = false
|
||||
local endpos = pos + length * 2 - 1
|
||||
|
||||
if endpos > #buffer then
|
||||
stdnse.print_debug(1, "MSRPC: ERROR: Ran off the end of a string in unicode_to_string(), this likely means we are reading a packet incorrectly. Please report! (pos = %d, #buffer = %d, endpos = %d)", pos, #buffer, endpos)
|
||||
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
if(do_null == true and length > 0) then
|
||||
length = length - 1
|
||||
local str = unicode.utf16to8(string.sub(buffer, pos, endpos))
|
||||
|
||||
if do_null then
|
||||
str = string.sub(str, 1, -2) -- Eat the null terminator
|
||||
end
|
||||
|
||||
for j = 1, length, 1 do
|
||||
|
||||
pos, ch, dummy = bin.unpack("<CC", buffer, pos)
|
||||
|
||||
if(ch == nil or dummy == nil) then
|
||||
stdnse.print_debug(1, "MSRPC: ERROR: Ran off the end of a string in unicode_to_string(), this likely means we are reading a packet incorrectly. Please report! (pos = %d, j = %d, length = %d)", pos, j, length)
|
||||
|
||||
return nil, nil
|
||||
else
|
||||
string = string .. string.char(ch)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if(do_null == true) then
|
||||
pos = pos + 2 -- Eat the null terminator
|
||||
end
|
||||
|
||||
if(do_null == true and ((length + 1) % 2) == 1) then
|
||||
pos = pos + 2
|
||||
end
|
||||
|
||||
if(do_null == false and (length % 2) == 1) then
|
||||
pos = pos + 2
|
||||
end
|
||||
-- Align to 4-byte boundary
|
||||
endpos = endpos + (endpos + 1 - pos) % 4
|
||||
|
||||
stdnse.print_debug(4, "MSRPC: Leaving unicode_to_string()")
|
||||
|
||||
return pos, string
|
||||
return endpos + 1, str
|
||||
end
|
||||
|
||||
-------------------------------------
|
||||
|
||||
@@ -135,6 +135,7 @@ local smbauth = require "smbauth"
|
||||
local stdnse = require "stdnse"
|
||||
local string = require "string"
|
||||
local table = require "table"
|
||||
local unicode = require "unicode"
|
||||
_ENV = stdnse.module("smb", stdnse.seeall)
|
||||
|
||||
-- These arrays are filled in with constants at the bottom of this file
|
||||
@@ -1077,29 +1078,23 @@ function negotiate_protocol(smb, overrides)
|
||||
return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [12]"
|
||||
end
|
||||
|
||||
-- Get the domain as a Unicode string
|
||||
local ch, dummy
|
||||
-- Get the (null-terminated) domain as a Unicode string
|
||||
smb['domain'] = ""
|
||||
smb['server'] = ""
|
||||
|
||||
pos, ch, dummy = bin.unpack("<CC", data, pos)
|
||||
--if(dummy == nil) then
|
||||
-- return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [13]"
|
||||
--end
|
||||
while ch ~= nil and ch ~= 0 do
|
||||
smb['domain'] = smb['domain'] .. string.char(ch)
|
||||
pos, ch, dummy = bin.unpack("<CC", data, pos)
|
||||
if(ch == nil or dummy == nil) then
|
||||
return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [14]"
|
||||
end
|
||||
local remainder = unicode.utf16to8(string.sub(data, pos))
|
||||
pos, pos = string.find(remainder, "\0", 1, true)
|
||||
if pos == nil then
|
||||
return false, "SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [14]"
|
||||
end
|
||||
smb['domain'] = string.sub(remainder, 1, pos)
|
||||
|
||||
-- Get the server name as a Unicode string
|
||||
-- Note: This can be nil, Samba leaves this off
|
||||
pos, ch, dummy = bin.unpack("<CC", data, pos)
|
||||
while ch ~= nil and ch ~= 0 do
|
||||
smb['server'] = smb['server'] .. string.char(ch)
|
||||
pos, ch, dummy = bin.unpack("<CC", data, pos)
|
||||
local pos2 = pos + 1
|
||||
pos, pos = string.find(remainder, "\0", pos2, true)
|
||||
if pos ~= nil then
|
||||
smb['server'] = string.sub(remainder, pos2, pos)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ local nmap = require "nmap"
|
||||
local stdnse = require "stdnse"
|
||||
local string = require "string"
|
||||
local table = require "table"
|
||||
local unicode = require "unicode"
|
||||
_ENV = stdnse.module("smbauth", stdnse.seeall)
|
||||
|
||||
local have_ssl, openssl = pcall(require, "openssl")
|
||||
@@ -304,27 +305,6 @@ function init_account(host)
|
||||
end
|
||||
end
|
||||
|
||||
local function to_unicode(str)
|
||||
local unicode = ""
|
||||
|
||||
for i = 1, #str, 1 do
|
||||
unicode = unicode .. bin.pack("<S", string.byte(str, i))
|
||||
end
|
||||
|
||||
return unicode
|
||||
end
|
||||
|
||||
local function from_unicode(unicode)
|
||||
local str = ""
|
||||
if ( unicode == nil ) then
|
||||
return nil
|
||||
end
|
||||
for char_itr = 1, unicode:len(), 2 do
|
||||
str = str .. unicode:sub(char_itr, char_itr)
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
---Generate the Lanman v1 hash (LMv1). The generated hash is incredibly easy to reverse, because the input
|
||||
-- is padded or truncated to 14 characters, then split into two 7-character strings. Each of these strings
|
||||
-- are used as a key to encrypt the string, "KGS!@#$%" in DES. Because the keys are no longer than
|
||||
@@ -373,7 +353,7 @@ function ntlm_create_hash(password)
|
||||
return false, "SMB: OpenSSL not present"
|
||||
end
|
||||
|
||||
return true, openssl.md4(to_unicode(password))
|
||||
return true, openssl.md4(unicode.utf8to16(password))
|
||||
end
|
||||
|
||||
---Create the Lanman response to send back to the server. To do this, the Lanman password is padded to 21
|
||||
@@ -482,8 +462,8 @@ function ntlmv2_create_hash(ntlm, username, domain)
|
||||
|
||||
local unicode = ""
|
||||
|
||||
username = to_unicode(string.upper(username))
|
||||
domain = to_unicode(string.upper(domain))
|
||||
username = unicode.utf8to16(string.upper(username))
|
||||
domain = unicode.utf8to16(string.upper(domain))
|
||||
|
||||
return true, openssl.hmac("MD5", ntlm, username .. domain)
|
||||
end
|
||||
@@ -680,9 +660,9 @@ function get_security_blob(security_blob, ip, username, domain, password, passwo
|
||||
local lanman, ntlm, mac_key = get_password_response(ip, username, domain, password, password_hash, hash_type, challenge, true)
|
||||
|
||||
-- Convert the username and domain to unicode (TODO: Disable the unicode flag, evaluate if that'll work)
|
||||
local hostname = to_unicode("nmap")
|
||||
username = to_unicode(username)
|
||||
domain = (#username > 0 ) and to_unicode(domain) or ""
|
||||
local hostname = unicode.utf8to16("nmap")
|
||||
username = unicode.utf8to16(username)
|
||||
domain = (#username > 0 ) and unicode.utf8to16(domain) or ""
|
||||
ntlm = (#username > 0 ) and ntlm or ""
|
||||
lanman = (#username > 0 ) and lanman or string.char(0)
|
||||
|
||||
@@ -763,7 +743,7 @@ function get_host_info_from_security_blob(security_blob)
|
||||
local pos = domain_offset + 1 -- +1 to convert to Lua's 1-based indexes
|
||||
local target_realm
|
||||
pos, target_realm = bin.unpack( string.format( "A%d", length ), security_blob, pos )
|
||||
ntlm_challenge[ "target_realm" ] = from_unicode( target_realm )
|
||||
ntlm_challenge[ "target_realm" ] = unicode.utf16to8( target_realm )
|
||||
end
|
||||
|
||||
-- Parse the TargetInfo data (Wireshark calls this the "Address List")
|
||||
@@ -814,7 +794,7 @@ function get_host_info_from_security_blob(security_blob)
|
||||
-- this is a FILETIME value (see [MS-DTYP]), representing the time in 100-ns increments since 1/1/1601
|
||||
ntlm_challenge[ friendly_name ] = bin.unpack( "<L", value )
|
||||
elseif ( friendly_name ) then
|
||||
ntlm_challenge[ friendly_name ] = from_unicode( value )
|
||||
ntlm_challenge[ friendly_name ] = unicode.utf16to8( value )
|
||||
end
|
||||
until ( pos >= #target_info )
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user