1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-18 05:29:02 +00:00

Switch to string packing instead of bin packing and return order for asn1-related libs

This commit is contained in:
dmiller
2017-03-29 20:42:01 +00:00
parent 3dec043ead
commit 4cef14a873
8 changed files with 120 additions and 134 deletions

View File

@@ -17,7 +17,6 @@
-- o Each script or library should now create its own Encoder and Decoder instance -- o Each script or library should now create its own Encoder and Decoder instance
-- --
local bin = require "bin"
local bit = require "bit" local bit = require "bit"
local math = require "math" local math = require "math"
local stdnse = require "stdnse" local stdnse = require "stdnse"
@@ -62,7 +61,7 @@ ASN1Decoder = {
-- Boolean -- Boolean
self.decoder["\x01"] = function( self, encStr, elen, pos ) self.decoder["\x01"] = function( self, encStr, elen, pos )
local val = string.byte(encStr, pos) local val = string.byte(encStr, pos)
return pos + 1, val ~= 0xFF return val ~= 0xFF, pos + 1
end end
-- Integer -- Integer
@@ -72,12 +71,12 @@ ASN1Decoder = {
-- Octet String -- Octet String
self.decoder["\x04"] = function( self, encStr, elen, pos ) self.decoder["\x04"] = function( self, encStr, elen, pos )
return bin.unpack("A" .. elen, encStr, pos) return string.unpack("c" .. elen, encStr, pos)
end end
-- Null -- Null
self.decoder["\x05"] = function( self, encStr, elen, pos ) self.decoder["\x05"] = function( self, encStr, elen, pos )
return pos, false return false, pos
end end
-- Object Identifier -- Object Identifier
@@ -107,8 +106,8 @@ ASN1Decoder = {
-- @param encStr Encoded string -- @param encStr Encoded string
-- @param elen Length of the object in bytes -- @param elen Length of the object in bytes
-- @param pos Current position in the string -- @param pos Current position in the string
-- @return The position after decoding
-- @return The decoded object -- @return The decoded object
-- @return The position after decoding
--- Allows for registration of additional tag decoders --- Allows for registration of additional tag decoders
-- @name ASN1Decoder.registerTagDecoders -- @name ASN1Decoder.registerTagDecoders
@@ -125,21 +124,21 @@ ASN1Decoder = {
-- @name ASN1Decoder.decode -- @name ASN1Decoder.decode
-- @param encStr Encoded string. -- @param encStr Encoded string.
-- @param pos Current position in the string. -- @param pos Current position in the string.
-- @return The position after decoding
-- @return The decoded value(s). -- @return The decoded value(s).
-- @return The position after decoding
decode = function(self, encStr, pos) decode = function(self, encStr, pos)
local etype, elen local etype, elen
local newpos = pos local newpos = pos
etype, newpos = string.unpack("c1", encStr, newpos) etype, newpos = string.unpack("c1", encStr, newpos)
newpos, elen = self.decodeLength(encStr, newpos) elen, newpos = self.decodeLength(encStr, newpos)
if self.decoder[etype] then if self.decoder[etype] then
return self.decoder[etype]( self, encStr, elen, newpos ) return self.decoder[etype]( self, encStr, elen, newpos )
else else
stdnse.debug1("no decoder for etype: " .. etype) stdnse.debug1("no decoder for etype: " .. etype)
return newpos, nil return nil, newpos
end end
end, end,
@@ -149,23 +148,22 @@ ASN1Decoder = {
-- @name ASN1Decoder.decodeLength -- @name ASN1Decoder.decodeLength
-- @param encStr Encoded string. -- @param encStr Encoded string.
-- @param pos Current position in the string. -- @param pos Current position in the string.
-- @return The position after decoding.
-- @return The length of the following value. -- @return The length of the following value.
-- @return The position after decoding.
decodeLength = function(encStr, pos) decodeLength = function(encStr, pos)
local elen local elen, newpos = string.unpack('B', encStr, pos)
pos, elen = bin.unpack('C', encStr, pos)
if (elen > 128) then if (elen > 128) then
elen = elen - 128 elen = elen - 128
local elenCalc = 0 local elenCalc = 0
local elenNext local elenNext
for i = 1, elen do for i = 1, elen do
elenCalc = elenCalc * 256 elenCalc = elenCalc * 256
pos, elenNext = bin.unpack("C", encStr, pos) elenNext, newpos = string.unpack('B', encStr, newpos)
elenCalc = elenCalc + elenNext elenCalc = elenCalc + elenNext
end end
elen = elenCalc elen = elenCalc
end end
return pos, elen return elen, newpos
end, end,
--- ---
@@ -174,20 +172,19 @@ ASN1Decoder = {
-- @param encStr Encoded string. -- @param encStr Encoded string.
-- @param len Length of sequence in bytes. -- @param len Length of sequence in bytes.
-- @param pos Current position in the string. -- @param pos Current position in the string.
-- @return The position after decoding.
-- @return The decoded sequence as a table. -- @return The decoded sequence as a table.
-- @return The position after decoding.
decodeSeq = function(self, encStr, len, pos) decodeSeq = function(self, encStr, len, pos)
local seq = {} local seq = {}
local sPos = 1 local sPos = 1
local sStr local sStr, newpos = string.unpack("c" .. len, encStr, pos)
pos, sStr = bin.unpack("A" .. len, encStr, pos)
while (sPos < len) do while (sPos < len) do
local newSeq local newSeq
sPos, newSeq = self:decode(sStr, sPos) newSeq, sPos = self:decode(sStr, sPos)
if ( not(newSeq) and self.stoponerror ) then break end if ( not(newSeq) and self.stoponerror ) then break end
table.insert(seq, newSeq) table.insert(seq, newSeq)
end end
return pos, seq return seq, newpos
end, end,
-- Decode one component of an OID from a byte string. 7 bits of the component -- Decode one component of an OID from a byte string. 7 bits of the component
@@ -200,11 +197,11 @@ ASN1Decoder = {
local n = 0 local n = 0
repeat repeat
pos, octet = bin.unpack("C", encStr, pos) octet, pos = string.unpack("B", encStr, pos)
n = n * 128 + bit.band(0x7F, octet) n = n * 128 + bit.band(0x7F, octet)
until octet < 128 until octet < 128
return pos, n return n, pos
end, end,
--- Decodes an OID from a sequence of bytes. --- Decodes an OID from a sequence of bytes.
@@ -212,8 +209,8 @@ ASN1Decoder = {
-- @param encStr Encoded string. -- @param encStr Encoded string.
-- @param len Length of sequence in bytes. -- @param len Length of sequence in bytes.
-- @param pos Current position in the string. -- @param pos Current position in the string.
-- @return The position after decoding.
-- @return The OID as an array. -- @return The OID as an array.
-- @return The position after decoding.
decodeOID = function(self, encStr, len, pos) decodeOID = function(self, encStr, len, pos)
local last local last
local oid = {} local oid = {}
@@ -222,7 +219,7 @@ ASN1Decoder = {
last = pos + len - 1 last = pos + len - 1
if pos <= last then if pos <= last then
oid._snmp = '\x06' oid._snmp = '\x06'
pos, octet = bin.unpack("C", encStr, pos) octet, pos = string.unpack("B", encStr, pos)
oid[2] = math.fmod(octet, 40) oid[2] = math.fmod(octet, 40)
octet = octet - oid[2] octet = octet - oid[2]
oid[1] = octet//40 oid[1] = octet//40
@@ -230,11 +227,11 @@ ASN1Decoder = {
while pos <= last do while pos <= last do
local c local c
pos, c = self.decode_oid_component(encStr, pos) c, pos = self.decode_oid_component(encStr, pos)
oid[#oid + 1] = c oid[#oid + 1] = c
end end
return pos, oid return oid, pos
end, end,
--- ---
@@ -243,11 +240,10 @@ ASN1Decoder = {
-- @param encStr Encoded string. -- @param encStr Encoded string.
-- @param len Length of integer in bytes. -- @param len Length of integer in bytes.
-- @param pos Current position in the string. -- @param pos Current position in the string.
-- @return The position after decoding.
-- @return The decoded integer. -- @return The decoded integer.
-- @return The position after decoding.
decodeInt = function(encStr, len, pos) decodeInt = function(encStr, len, pos)
local value, pos = string.unpack(">i" .. len, encStr, pos) return string.unpack(">i" .. len, encStr, pos)
return pos, value
end, end,
} }
@@ -392,7 +388,7 @@ ASN1Encoder = {
local valStr = "" local valStr = ""
while (val > 0) do while (val > 0) do
lsb = math.fmod(val, 256) lsb = math.fmod(val, 256)
valStr = valStr .. bin.pack("C", lsb) valStr = valStr .. string.pack("B", lsb)
val = math.floor(val/256) val = math.floor(val/256)
end end
if lsb > 127 then -- two's complement collision if lsb > 127 then -- two's complement collision
@@ -410,12 +406,12 @@ ASN1Encoder = {
local valStr = "" local valStr = ""
while (tcval > 0) do while (tcval > 0) do
lsb = math.fmod(tcval, 256) lsb = math.fmod(tcval, 256)
valStr = valStr .. bin.pack("C", lsb) valStr = valStr .. string.pack("B", lsb)
tcval = math.floor(tcval/256) tcval = math.floor(tcval/256)
end end
return string.reverse(valStr) return string.reverse(valStr)
else -- val == 0 else -- val == 0
return bin.pack("x") return '\0'
end end
end, end,

View File

@@ -18,7 +18,6 @@
-- --
local asn1 = require "asn1" local asn1 = require "asn1"
local bin = require "bin"
local io = require "io" local io = require "io"
local nmap = require "nmap" local nmap = require "nmap"
local os = require "os" local os = require "os"
@@ -94,15 +93,15 @@ tagEncoder['table'] = function(self, val)
if (val._ldap == '\x0A') then if (val._ldap == '\x0A') then
local ival = self.encodeInt(val[1]) local ival = self.encodeInt(val[1])
local len = self.encodeLength(#ival) local len = self.encodeLength(#ival)
return bin.pack('HAA', '0A', len, ival) return val._ldap .. len .. ival
end end
if (val._ldaptype) then if (val._ldaptype) then
local len local len
if val[1] == nil or #val[1] == 0 then if val[1] == nil or #val[1] == 0 then
return bin.pack('HC', val._ldaptype, 0) return val._ldaptype .. '\0'
else else
len = self.encodeLength(#val[1]) len = self.encodeLength(#val[1])
return bin.pack('HAA', val._ldaptype, len, val[1]) return val._ldaptype .. len .. val[1]
end end
end end
@@ -111,7 +110,7 @@ tagEncoder['table'] = function(self, val)
encVal = encVal .. encode(v) -- todo: buffer? encVal = encVal .. encode(v) -- todo: buffer?
end end
local tableType = val._snmp or "\x30" local tableType = val._snmp or "\x30"
return bin.pack('AAA', tableType, self.encodeLength(#encVal), encVal) return tableType .. self.encodeLength(#encVal) .. encVal
end end
@@ -144,12 +143,12 @@ tagDecoder["\x0A"] = function( self, encStr, elen, pos )
end end
tagDecoder["\x8A"] = function( self, encStr, elen, pos ) tagDecoder["\x8A"] = function( self, encStr, elen, pos )
return bin.unpack("A" .. elen, encStr, pos) return string.unpack("c" .. elen, encStr, pos)
end end
-- null decoder -- null decoder
tagDecoder["\x31"] = function( self, encStr, elen, pos ) tagDecoder["\x31"] = function( self, encStr, elen, pos )
return pos, nil return nil, pos
end end
@@ -158,8 +157,8 @@ end
-- rules. -- rules.
-- @param encStr Encoded string. -- @param encStr Encoded string.
-- @param pos Current position in the string. -- @param pos Current position in the string.
-- @return The position after decoding
-- @return The decoded value(s). -- @return The decoded value(s).
-- @return The position after decoding
function decode(encStr, pos) function decode(encStr, pos)
-- register the LDAP specific tag decoders -- register the LDAP specific tag decoders
local decoder = asn1.ASN1Decoder:new() local decoder = asn1.ASN1Decoder:new()
@@ -173,22 +172,21 @@ end
-- @param encStr Encoded string. -- @param encStr Encoded string.
-- @param len Length of sequence in bytes. -- @param len Length of sequence in bytes.
-- @param pos Current position in the string. -- @param pos Current position in the string.
-- @return The position after decoding.
-- @return The decoded sequence as a table. -- @return The decoded sequence as a table.
-- @return The position after decoding.
local function decodeSeq(encStr, len, pos) local function decodeSeq(encStr, len, pos)
local seq = {} local seq = {}
local sPos = 1 local sPos = 1
local sStr local sStr, newpos = string.unpack("c" .. len, encStr, pos)
pos, sStr = bin.unpack("A" .. len, encStr, pos)
if(sStr==nil) then if(sStr==nil) then
return pos,seq return seq, newpos
end end
while (sPos < len) do while (sPos < len) do
local newSeq local newSeq
sPos, newSeq = decode(sStr, sPos) newSeq, sPos = decode(sStr, sPos)
table.insert(seq, newSeq) table.insert(seq, newSeq)
end end
return pos, seq return seq, newpos
end end
-- Encodes an LDAP Application operation and its data as a sequence -- Encodes an LDAP Application operation and its data as a sequence
@@ -202,7 +200,7 @@ function encodeLDAPOp( appno, isConstructed, data )
local encoded_str = "" local encoded_str = ""
local asn1_type = asn1.BERtoInt( asn1.BERCLASS.Application, isConstructed, appno ) local asn1_type = asn1.BERtoInt( asn1.BERCLASS.Application, isConstructed, appno )
encoded_str = encode( { _ldaptype = string.format("%X", asn1_type), data } ) encoded_str = encode( { _ldaptype = string.pack("B", asn1_type), data } )
return encoded_str return encoded_str
end end
@@ -247,7 +245,7 @@ function searchRequest( socket, params )
if params.filter then if params.filter then
request = request .. createFilter( params.filter ) request = request .. createFilter( params.filter )
else else
request = request .. encode( { _ldaptype='87', "objectclass" } )-- filter : string, presence request = request .. encode( { _ldaptype='\x87', "objectclass" } )-- filter : string, presence
end end
if attributes~= nil then if attributes~= nil then
for _,attr in ipairs(attributes) do for _,attr in ipairs(attributes) do
@@ -278,24 +276,24 @@ function searchRequest( socket, params )
end end
if data:len() > 6 then if data:len() > 6 then
pos, len = decoder.decodeLength( data, pos ) len, pos = decoder.decodeLength( data, pos )
else else
data = data .. try( socket:receive() ) data = data .. try( socket:receive() )
pos, len = decoder.decodeLength( data, pos ) len, pos = decoder.decodeLength( data, pos )
end end
-- pos should be at the right position regardless if length is specified in 1 or 2 bytes -- pos should be at the right position regardless if length is specified in 1 or 2 bytes
while ( len + pos - 1 > data:len() ) do while ( len + pos - 1 > data:len() ) do
data = data .. try( socket:receive() ) data = data .. try( socket:receive() )
end end
pos, messageId = decode( data, pos ) messageId, pos = decode( data, pos )
pos, tmp = bin.unpack("C", data, pos) tmp, pos = string.unpack("B", data, pos)
pos, len = decoder.decodeLength( data, pos ) len, pos = decoder.decodeLength( data, pos )
ldapOp = asn1.intToBER( tmp ) ldapOp = asn1.intToBER( tmp )
searchResEntry = {} searchResEntry = {}
if ldapOp.number == APPNO.SearchResDone then if ldapOp.number == APPNO.SearchResDone then
pos, searchResEntry.resultCode = decode( data, pos ) searchResEntry.resultCode, pos = decode( data, pos )
-- errors may occur after a large amount of data has been received (eg. size limit exceeded) -- errors may occur after a large amount of data has been received (eg. size limit exceeded)
-- we want to be able to return the data received prior to this error to the user -- we want to be able to return the data received prior to this error to the user
-- however, we also need to alert the user of the error. This is achieved through "softerrors" -- however, we also need to alert the user of the error. This is achieved through "softerrors"
@@ -303,8 +301,8 @@ function searchRequest( socket, params )
-- this allows for the caller to output data while still being able to catch the error -- this allows for the caller to output data while still being able to catch the error
if ( searchResEntry.resultCode ~= 0 ) then if ( searchResEntry.resultCode ~= 0 ) then
local error_msg local error_msg
pos, searchResEntry.matchedDN = decode( data, pos ) searchResEntry.matchedDN, pos = decode( data, pos )
pos, searchResEntry.errorMessage = decode( data, pos ) searchResEntry.errorMessage, pos = decode( data, pos )
error_msg = ERROR_MSG[searchResEntry.resultCode] error_msg = ERROR_MSG[searchResEntry.resultCode]
-- if the table is empty return a hard error -- if the table is empty return a hard error
if #searchResEntries == 0 then if #searchResEntries == 0 then
@@ -318,9 +316,9 @@ function searchRequest( socket, params )
break break
end end
pos, searchResEntry.objectName = decode( data, pos ) searchResEntry.objectName, pos = decode( data, pos )
if ldapOp.number == APPNO.SearchResponse then if ldapOp.number == APPNO.SearchResponse then
pos, searchResEntry.attributes = decode( data, pos ) searchResEntry.attributes, pos = decode( data, pos )
table.insert( searchResEntries, searchResEntry ) table.insert( searchResEntries, searchResEntry )
end end
@@ -376,7 +374,7 @@ function udpSearchRequest( host, port, params )
if params.filter then if params.filter then
request = request .. createFilter( params.filter ) request = request .. createFilter( params.filter )
else else
request = request .. encode( { _ldaptype='87', "objectclass" } )-- filter : string, presence request = request .. encode( { _ldaptype='\x87', "objectclass" } )-- filter : string, presence
end end
if attributes~= nil then if attributes~= nil then
for _,attr in ipairs(attributes) do for _,attr in ipairs(attributes) do
@@ -405,16 +403,16 @@ function udpSearchRequest( host, port, params )
maxObjects = maxObjects - 1 maxObjects = maxObjects - 1
end end
pos, tmp = bin.unpack("C", response, pos) tmp, pos = string.unpack("B", response, pos)
pos, len = decoder.decodeLength( response, pos ) len, pos = decoder.decodeLength( response, pos )
pos, messageId = decode( response, pos ) messageId, pos = decode( response, pos )
pos, tmp = bin.unpack("C", response, pos) tmp, pos = string.unpack("B", response, pos)
pos, len = decoder.decodeLength( response, pos ) len, pos = decoder.decodeLength( response, pos )
ldapOp = asn1.intToBER( tmp ) ldapOp = asn1.intToBER( tmp )
searchResEntry = {} searchResEntry = {}
if ldapOp.number == APPNO.SearchResDone then if ldapOp.number == APPNO.SearchResDone then
pos, searchResEntry.resultCode = decode( response, pos ) searchResEntry.resultCode, pos = decode( response, pos )
-- errors may occur after a large amount of response has been received (eg. size limit exceeded) -- errors may occur after a large amount of response has been received (eg. size limit exceeded)
-- we want to be able to return the response received prior to this error to the user -- we want to be able to return the response received prior to this error to the user
-- however, we also need to alert the user of the error. This is achieved through "softerrors" -- however, we also need to alert the user of the error. This is achieved through "softerrors"
@@ -422,8 +420,8 @@ function udpSearchRequest( host, port, params )
-- this allows for the caller to output response while still being able to catch the error -- this allows for the caller to output response while still being able to catch the error
if ( searchResEntry.resultCode ~= 0 ) then if ( searchResEntry.resultCode ~= 0 ) then
local error_msg local error_msg
pos, searchResEntry.matchedDN = decode( response, pos ) searchResEntry.matchedDN, pos = decode( response, pos )
pos, searchResEntry.errorMessage = decode( response, pos ) searchResEntry.errorMessage, pos = decode( response, pos )
error_msg = ERROR_MSG[searchResEntry.resultCode] error_msg = ERROR_MSG[searchResEntry.resultCode]
-- if the table is empty return a hard error -- if the table is empty return a hard error
if #searchResEntries == 0 then if #searchResEntries == 0 then
@@ -437,9 +435,9 @@ function udpSearchRequest( host, port, params )
break break
end end
pos, searchResEntry.objectName = decode( response, pos ) searchResEntry.objectName, pos = decode( response, pos )
if ldapOp.number == APPNO.SearchResponse then if ldapOp.number == APPNO.SearchResponse then
pos, searchResEntry.attributes = decode( response, pos ) searchResEntry.attributes, pos = decode( response, pos )
table.insert( searchResEntries, searchResEntry ) table.insert( searchResEntries, searchResEntry )
end end
if response:len() > pos then if response:len() > pos then
@@ -461,7 +459,7 @@ function bindRequest( socket, params )
local catch = function() socket:close() stdnse.debug1("bindRequest failed") end local catch = function() socket:close() stdnse.debug1("bindRequest failed") end
local try = nmap.new_try(catch) local try = nmap.new_try(catch)
local ldapAuth = encode( { _ldaptype = '80', params.password } ) local ldapAuth = encode( { _ldaptype = '\x80', params.password } )
local bindReq = encode( params.version ) .. encode( params.username ) .. ldapAuth local bindReq = encode( params.version ) .. encode( params.username ) .. ldapAuth
local ldapMsg = encode(ldapMessageId) .. encodeLDAPOp( APPNO.BindRequest, true, bindReq ) local ldapMsg = encode(ldapMessageId) .. encodeLDAPOp( APPNO.BindRequest, true, bindReq )
local packet local packet
@@ -479,22 +477,22 @@ function bindRequest( socket, params )
try( socket:send( packet ) ) try( socket:send( packet ) )
packet = try( socket:receive() ) packet = try( socket:receive() )
pos, packet_len = decoder.decodeLength( packet, 2 ) packet_len, pos = decoder.decodeLength( packet, 2 )
pos, response.messageID = decode( packet, pos ) response.messageID, pos = decode( packet, pos )
pos, tmp = bin.unpack("C", packet, pos) tmp, pos = string.unpack("B", packet, pos)
pos, len = decoder.decodeLength( packet, pos ) len, pos = decoder.decodeLength( packet, pos )
response.protocolOp = asn1.intToBER( tmp ) response.protocolOp = asn1.intToBER( tmp )
if response.protocolOp.number ~= APPNO.BindResponse then if response.protocolOp.number ~= APPNO.BindResponse then
return false, string.format("Received incorrect Op in packet: %d, expected %d", response.protocolOp.number, APPNO.BindResponse) return false, string.format("Received incorrect Op in packet: %d, expected %d", response.protocolOp.number, APPNO.BindResponse)
end end
pos, response.resultCode = decode( packet, pos ) response.resultCode, pos = decode( packet, pos )
if ( response.resultCode ~= 0 ) then if ( response.resultCode ~= 0 ) then
local error_msg local error_msg
pos, response.matchedDN = decode( packet, pos ) response.matchedDN, pos = decode( packet, pos )
pos, response.errorMessage = decode( packet, pos ) response.errorMessage, pos = decode( packet, pos )
error_msg = ERROR_MSG[response.resultCode] error_msg = ERROR_MSG[response.resultCode]
return false, string.format("\n Error: %s\n Details: %s", return false, string.format("\n Error: %s\n Details: %s",
error_msg or "Unknown error occurred (code: " .. response.resultCode .. error_msg or "Unknown error occurred (code: " .. response.resultCode ..
@@ -550,25 +548,25 @@ function createFilter( filter )
if (#tmptable <= 1 ) then if (#tmptable <= 1 ) then
-- 0x81 = 10000001 = 10 0 00001 -- 0x81 = 10000001 = 10 0 00001
-- hex binary Context Primitive value Field: Sequence Value: 1 (any / any position in string) -- hex binary Context Primitive value Field: Sequence Value: 1 (any / any position in string)
tmp_result = bin.pack('HAA' , '81', string.char(#filter.val), filter.val) tmp_result = string.pack('Bs1', 0x81, filter.val)
else else
for indexval, substr in ipairs(tmptable) do for indexval, substr in ipairs(tmptable) do
if (indexval == 1) and (substr ~= '') then if (indexval == 1) and (substr ~= '') then
-- 0x81 = 10000000 = 10 0 00000 -- 0x81 = 10000000 = 10 0 00000
-- hex binary Context Primitive value Field: Sequence Value: 0 (initial / match at start of string) -- hex binary Context Primitive value Field: Sequence Value: 0 (initial / match at start of string)
tmp_result = bin.pack('HAA' , '80', string.char(#substr), substr) tmp_result = '\x80' .. string.char(#substr) .. substr
end end
if (indexval ~= #tmptable) and (indexval ~= 1) and (substr ~= '') then if (indexval ~= #tmptable) and (indexval ~= 1) and (substr ~= '') then
-- 0x81 = 10000001 = 10 0 00001 -- 0x81 = 10000001 = 10 0 00001
-- hex binary Context Primitive value Field: Sequence Value: 1 (any / match in any position in string) -- hex binary Context Primitive value Field: Sequence Value: 1 (any / match in any position in string)
tmp_result = tmp_result .. bin.pack('HAA' , '81', string.char(#substr), substr) tmp_result = tmp_result .. string.pack('Bs1', 0x81, substr)
end end
if (indexval == #tmptable) and (substr ~= '') then if (indexval == #tmptable) and (substr ~= '') then
-- 0x82 = 10000010 = 10 0 00010 -- 0x82 = 10000010 = 10 0 00010
-- hex binary Context Primitive value Field: Sequence Value: 2 (final / match at end of string) -- hex binary Context Primitive value Field: Sequence Value: 2 (final / match at end of string)
tmp_result = tmp_result .. bin.pack('HAA' , '82', string.char(#substr), substr) tmp_result = tmp_result .. string.pack('Bs1', 0x82, substr)
end end
end end
end end
@@ -593,33 +591,32 @@ function createFilter( filter )
return false, ("ERROR: Invalid extensibleMatch query format") return false, ("ERROR: Invalid extensibleMatch query format")
end end
tmp_result = string.pack('Bs1 Bs1 Bs1 Bs1',
-- Format and create matchingRule using OID -- Format and create matchingRule using OID
-- 0x81 = 10000001 = 10 0 00001 -- 0x81 = 10000001 = 10 0 00001
-- hex binary Context Primitive value Field: matchingRule Value: 1 -- hex binary Context Primitive value Field: matchingRule Value: 1
tmp_result = bin.pack('HAA' , '81', string.char(#OID), OID) 0x81, OID,
-- Format and create type using ldap attribute -- Format and create type using ldap attribute
-- 0x82 = 10000010 = 10 0 00010 -- 0x82 = 10000010 = 10 0 00010
-- hex binary Context Primitive value Field: Type Value: 2 -- hex binary Context Primitive value Field: Type Value: 2
tmp_result = tmp_result .. bin.pack('HAA' , '82', string.char(#filter.obj), filter.obj) 0x82, filter.obj,
-- Format and create matchValue using bitmask -- Format and create matchValue using bitmask
-- 0x83 = 10000011 = 10 0 00011 -- 0x83 = 10000011 = 10 0 00011
-- hex binary Context Primitive value Field: matchValue Value: 3 -- hex binary Context Primitive value Field: matchValue Value: 3
tmp_result = tmp_result .. bin.pack('HAA' , '83', string.char(#bitmask), bitmask) 0x83, bitmask,
-- Format and create dnAttributes, defaulting to false -- Format and create dnAttributes, defaulting to false
-- 0x84 = 10000100 = 10 0 00100 -- 0x84 = 10000100 = 10 0 00100
-- hex binary Context Primitive value Field: dnAttributes Value: 4 -- hex binary Context Primitive value Field: dnAttributes Value: 4
--
-- 0x01 = field length
-- 0x00 = boolean value, in this case false -- 0x00 = boolean value, in this case false
tmp_result = tmp_result .. bin.pack('H' , '840100') 0x84, '\x00')
-- Format the overall extensibleMatch block -- Format the overall extensibleMatch block
-- 0xa9 = 10101001 = 10 1 01001 -- 0xa9 = 10101001 = 10 1 01001
-- hex binary Context Constructed Field: Filter Value: 9 (extensibleMatch) -- hex binary Context Constructed Field: Filter Value: 9 (extensibleMatch)
return bin.pack('HAA' , 'a9', asn1.ASN1Encoder.encodeLength(#tmp_result), tmp_result) return '\xa9' .. asn1.ASN1Encoder.encodeLength(#tmp_result) .. tmp_result
else else
val = encode( filter.val ) val = encode( filter.val )
@@ -628,7 +625,7 @@ function createFilter( filter )
filter_str = filter_str .. obj .. val filter_str = filter_str .. obj .. val
end end
return encode( { _ldaptype=string.format("%X", asn1_type), filter_str } ) return encode( { _ldaptype=string.pack("B", asn1_type), filter_str } )
end end
--- Converts a search result as received from searchRequest to a "result" table --- Converts a search result as received from searchRequest to a "result" table
@@ -659,8 +656,9 @@ function searchResultToTable( searchEntries )
if ( attrib[1] == "objectSid" ) then if ( attrib[1] == "objectSid" ) then
table.insert( attribs, string.format( "%s: %d", attrib[1], decode( attrib[i] ) ) ) table.insert( attribs, string.format( "%s: %d", attrib[1], decode( attrib[i] ) ) )
elseif ( attrib[1] == "objectGUID") then elseif ( attrib[1] == "objectGUID") then
local _, o1, o2, o3, o4, o5, o6, o7, o8, o9, oa, ob, oc, od, oe, of = bin.unpack("C16", attrib[i] ) local o = {string.unpack(("B"):rep(16), attrib[i] )}
table.insert( attribs, string.format( "%s: %x%x%x%x-%x%x-%x%x-%x%x-%x%x%x%x%x", attrib[1], o4, o3, o2, o1, o5, o6, o7, o8, o9, oa, ob, oc, od, oe, of ) ) table.insert( attribs, string.format( "%s: %x%x%x%x-%x%x-%x%x-%x%x-%x%x%x%x%x%x",
attrib[1], o[4], o[3], o[2], o[1], table.unpack(o, 5, 16)))
elseif ( attrib[1] == "lastLogon" or attrib[1] == "lastLogonTimestamp" or attrib[1] == "pwdLastSet" or attrib[1] == "accountExpires" or attrib[1] == "badPasswordTime" ) then elseif ( attrib[1] == "lastLogon" or attrib[1] == "lastLogonTimestamp" or attrib[1] == "pwdLastSet" or attrib[1] == "accountExpires" or attrib[1] == "badPasswordTime" ) then
table.insert( attribs, string.format( "%s: %s", attrib[1], convertADTimeStamp(attrib[i]) ) ) table.insert( attribs, string.format( "%s: %s", attrib[1], convertADTimeStamp(attrib[i]) ) )
elseif ( attrib[1] == "whenChanged" or attrib[1] == "whenCreated" or attrib[1] == "dSCorePropagationData" ) then elseif ( attrib[1] == "whenChanged" or attrib[1] == "whenCreated" or attrib[1] == "dSCorePropagationData" ) then
@@ -743,8 +741,10 @@ function searchResultToFile( searchEntries, filename )
host_table[string.format("%s", v.objectName)].attributes[attrib[1]] = string.format( "%d", decode( attrib[i] ) ) host_table[string.format("%s", v.objectName)].attributes[attrib[1]] = string.format( "%d", decode( attrib[i] ) )
elseif ( attrib[1] == "objectGUID") then elseif ( attrib[1] == "objectGUID") then
local _, o1, o2, o3, o4, o5, o6, o7, o8, o9, oa, ob, oc, od, oe, of = bin.unpack("C16", attrib[i] ) local o = {string.unpack(("B"):rep(16), attrib[i] )}
host_table[string.format("%s", v.objectName)].attributes[attrib[1]] = string.format( "%x%x%x%x-%x%x-%x%x-%x%x-%x%x%x%x%x", o4, o3, o2, o1, o5, o6, o7, o8, o9, oa, ob, oc, od, oe, of ) host_table[string.format("%s", v.objectName)].attributes[attrib[1]] = string.format(
"%s: %x%x%x%x-%x%x-%x%x-%x%x-%x%x%x%x%x%x",
attrib[1], o[4], o[3], o[2], o[1], table.unpack(o, 5, 16))
elseif ( attrib[1] == "lastLogon" or attrib[1] == "lastLogonTimestamp" or attrib[1] == "pwdLastSet" or attrib[1] == "accountExpires" or attrib[1] == "badPasswordTime" ) then elseif ( attrib[1] == "lastLogon" or attrib[1] == "lastLogonTimestamp" or attrib[1] == "pwdLastSet" or attrib[1] == "accountExpires" or attrib[1] == "badPasswordTime" ) then
host_table[string.format("%s", v.objectName)].attributes[attrib[1]] = convertADTimeStamp(attrib[i]) host_table[string.format("%s", v.objectName)].attributes[attrib[1]] = convertADTimeStamp(attrib[i])

View File

@@ -85,16 +85,17 @@ local tagDecoder = {}
tagDecoder["\xa2"] = function( self, encStr, elen, pos ) tagDecoder["\xa2"] = function( self, encStr, elen, pos )
local seq = {} local seq = {}
pos, seq = self:decodeSeq(encStr, elen, pos) seq, pos = self:decodeSeq(encStr, elen, pos)
seq._snmp = "\xa2" seq._snmp = "\xa2"
return pos, seq return seq, pos
end end
tagDecoder["\x40"] = function( self, encStr, elen, pos ) tagDecoder["\x40"] = function( self, encStr, elen, pos )
local ip = {} local ip = {}
pos, ip[1], ip[2], ip[3], ip[4] = bin.unpack("C4", encStr, pos) -- TODO: possibly convert to ipOps.str_to_ip() if octets are not used separately elsewhere.
ip[1], ip[2], ip[3], ip[4], pos = string.unpack("BBBB", encStr, pos)
ip._snmp = '\x40' ip._snmp = '\x40'
return pos, ip return ip, pos
end end
--- ---
@@ -102,8 +103,8 @@ end
-- rules. -- rules.
-- @param encStr Encoded string. -- @param encStr Encoded string.
-- @param pos Current position in the string. -- @param pos Current position in the string.
-- @return The position after decoding
-- @return The decoded value(s). -- @return The decoded value(s).
-- @return The position after decoding
function decode(encStr, pos) function decode(encStr, pos)
local decoder = asn1.ASN1Decoder:new() local decoder = asn1.ASN1Decoder:new()
@@ -381,10 +382,7 @@ end
-- @return Table with all decoded responses and their OIDs. -- @return Table with all decoded responses and their OIDs.
function fetchResponseValues(resp) function fetchResponseValues(resp)
if (type(resp) == "string") then if (type(resp) == "string") then
local nsedebug = require "nsedebug" resp = decode(resp)
local _
_, resp = decode(resp)
stdnse.debug1("Decoded: >>>%s<<<", nsedebug.tostr(resp))
end end
if (type(resp) ~= "table") then if (type(resp) ~= "table") then
@@ -553,21 +551,15 @@ Helper = {
local oid = base_oid local oid = base_oid
local options = {} local options = {}
local nsedebug = require "nsedebug"
local status, snmpdata = self:getnext(options, oid) local status, snmpdata = self:getnext(options, oid)
stdnse.debug1("got data: >>>%s<<<", nsedebug.tostr(snmpdata))
while ( snmpdata and snmpdata[1] and snmpdata[1][1] and snmpdata[1][2] ) do while ( snmpdata and snmpdata[1] and snmpdata[1][1] and snmpdata[1][2] ) do
oid = snmpdata[1][2] oid = snmpdata[1][2]
stdnse.debug1("Comparing %s to %s", oid, base_oid)
if not oid:match(base_oid) or base_oid == oid then break end if not oid:match(base_oid) or base_oid == oid then break end
stdnse.debug1("matched %s", base_oid)
table.insert(snmp_table, { oid = oid, value = snmpdata[1][1] }) table.insert(snmp_table, { oid = oid, value = snmpdata[1][1] })
local _ -- NSE don't want you to use global even if it is _ local _ -- NSE don't want you to use global even if it is _
_, snmpdata = self:getnext(options, oid) _, snmpdata = self:getnext(options, oid)
stdnse.debug1("got data: >>>%s<<<", nsedebug.tostr(snmpdata))
end end
stdnse.debug1("done")
return status, snmp_table return status, snmp_table
end end

View File

@@ -317,9 +317,9 @@ StartTLS = {
local decoder = asn1.ASN1Decoder:new() local decoder = asn1.ASN1Decoder:new()
local len, pos, messageId, ldapOp, tmp = "" local len, pos, messageId, ldapOp, tmp = ""
pos, len = decoder.decodeLength(response, 2) len, pos = decoder.decodeLength(response, 2)
pos, messageId = ldap.decode(response, pos) messageId, pos = ldap.decode(response, pos)
pos, tmp = bin.unpack("C", response, pos) tmp, pos = string.unpack("B", response, pos)
ldapOp = asn1.intToBER(tmp) ldapOp = asn1.intToBER(tmp)
if ldapOp.number ~= ExtendedResponse then if ldapOp.number ~= ExtendedResponse then
@@ -330,8 +330,8 @@ StartTLS = {
end end
local resultCode local resultCode
pos, len = decoder.decodeLength(response, pos) len, pos = decoder.decodeLength(response, pos)
pos, resultCode = ldap.decode(response, pos) resultCode, pos = ldap.decode(response, pos)
if resultCode ~= 0 then if resultCode ~= 0 then
starttls_supported(host, port, false) starttls_supported(host, port, false)

View File

@@ -5,6 +5,7 @@ local nmap = require "nmap"
local os = require "os" local os = require "os"
local shortport = require "shortport" local shortport = require "shortport"
local stdnse = require "stdnse" local stdnse = require "stdnse"
local string = require "string"
local table = require "table" local table = require "table"
local unpwdb = require "unpwdb" local unpwdb = require "unpwdb"
@@ -100,15 +101,13 @@ KRB5 = {
tagDecoder = { tagDecoder = {
["\x18"] = function( self, encStr, elen, pos ) ["\x18"] = function( self, encStr, elen, pos )
return bin.unpack("A" .. elen, encStr, pos) return string.unpack("c" .. elen, encStr, pos)
end, end,
["\x1B"] = function( ... ) return KRB5.tagDecoder["\x18"](...) end, ["\x1B"] = function( ... ) return KRB5.tagDecoder["\x18"](...) end,
["\x6B"] = function( self, encStr, elen, pos ) ["\x6B"] = function( self, encStr, elen, pos )
local seq return self:decodeSeq(encStr, elen, pos)
pos, seq = self:decodeSeq(encStr, elen, pos)
return pos, seq
end, end,
-- Not really sure what these are, but they all decode sequences -- Not really sure what these are, but they all decode sequences
@@ -262,7 +261,7 @@ KRB5 = {
local decoder = asn1.ASN1Decoder:new() local decoder = asn1.ASN1Decoder:new()
decoder:registerTagDecoders(KRB5.tagDecoder) decoder:registerTagDecoders(KRB5.tagDecoder)
decoder:setStopOnError(true) decoder:setStopOnError(true)
local pos, result = decoder:decode(data) local result = decoder:decode(data)
local msg = {} local msg = {}

View File

@@ -113,7 +113,7 @@ function action(host,port)
if ( not(status) ) then return data end if ( not(status) ) then return data end
socket:close() socket:close()
local _, response = ldap.decode(data) local response = ldap.decode(data)
-- make sure the result code was a success -- make sure the result code was a success
local rescode = ( #response >= 2 ) and response[2] local rescode = ( #response >= 2 ) and response[2]

View File

@@ -194,8 +194,7 @@ local sniff_snmp_responses = function(host, port, lport, result)
end end
local response = p:raw(p.udp_offset + 8, #p.buf) local response = p:raw(p.udp_offset + 8, #p.buf)
local res local res = snmp.decode(response)
_, res = snmp.decode(response)
if type(res) == "table" then if type(res) == "table" then
communities:add(nil, res[2], creds.State.VALID) communities:add(nil, res[2], creds.State.VALID)

View File

@@ -74,7 +74,7 @@ action = function (host, port)
end end
end end
local pos, decoded = snmp.decode(response) local decoded = snmp.decode(response)
-- Check for SNMP version 3 and msgid 0x4a69 (from the probe) -- Check for SNMP version 3 and msgid 0x4a69 (from the probe)
if ((not decoded) or if ((not decoded) or
@@ -93,7 +93,7 @@ action = function (host, port)
end end
-- Decode the msgSecurityParameters octet-string -- Decode the msgSecurityParameters octet-string
pos, decoded = snmp.decode(decoded[3]) decoded = snmp.decode(decoded[3])
local output = stdnse.output_table() local output = stdnse.output_table()
-- Decode the msgAuthoritativeEngineID octet-string -- Decode the msgAuthoritativeEngineID octet-string