1
0
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:
dmiller
2014-02-19 22:14:16 +00:00
parent 1ff0062589
commit 6e3980733e
3 changed files with 37 additions and 85 deletions

View File

@@ -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
end
local endpos = pos + length * 2 - 1
if(do_null == true and length > 0) then
length = length - 1
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)
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
else
string = string .. string.char(ch)
end
local str = unicode.utf16to8(string.sub(buffer, pos, endpos))
if do_null then
str = string.sub(str, 1, -2) -- Eat the null terminator
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
-------------------------------------

View File

@@ -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
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
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

View File

@@ -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