Skip to content

Commit 25f74b7

Browse files
committed
Land rapid7#3484, bad pack/unpack specifier fix
2 parents b95a5eb + 4ff211e commit 25f74b7

File tree

30 files changed

+100
-95
lines changed

30 files changed

+100
-95
lines changed

lib/bit-struct/octet-field.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def add_accessors_to(cl, attr = name) # :nodoc:
3737
old_writer = "#{attr_chars}="
3838

3939
define_method "#{attr}=" do |val|
40-
data = val.split(sep).map{|s|s.to_i(base)}.pack("c*")
40+
data = val.split(sep).map{|s|s.to_i(base)}.pack("C*")
4141
send(old_writer, data)
4242
end
4343
end

lib/msf/core/exploit/afp.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,7 @@ def parse_info_response(response)
246246
end
247247

248248
def parse_header(packet)
249-
header = packet.unpack('CCnNNN') #ruby 1.8.7 don't support unpacking signed integers in big-endian order
250-
header[3] = packet[4..7].reverse.unpack("l").first
249+
header = packet.unpack('CCnNNN')
251250
return header
252251
end
253252

lib/msf/core/post/windows/accounts.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ def check_dir_perms(dir, token)
270270

271271
#define generic mapping structure
272272
gen_map = [0,0,0,0]
273-
gen_map = gen_map.pack("L")
273+
gen_map = gen_map.pack("V")
274274
buffer_size = 500
275275

276276
#get Security Descriptor for the directory

lib/msf/core/post/windows/ldap.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,15 +248,15 @@ def query_ldap(session_handle, base, scope, filter, fields)
248248
# @param pEntry [Fixnum] Pointer to the Entry
249249
# @return [Array] Entry data structure
250250
def get_entry(pEntry)
251-
return client.railgun.memread(pEntry,41).unpack('LLLLLLLLLSCCC')
251+
return client.railgun.memread(pEntry,41).unpack('VVVVVVVVVvCCC')
252252
end
253253

254254
# Get BER Element data structure from LDAPMessage
255255
#
256256
# @param msg [String] The LDAP Message from the server
257257
# @return [String] The BER data structure
258258
def get_ber(msg)
259-
ber = client.railgun.memread(msg[2],60).unpack('L*')
259+
ber = client.railgun.memread(msg[2],60).unpack('V*')
260260

261261
# BER Pointer is different between x86 and x64
262262
if client.platform =~ /x64/

lib/msf/core/post/windows/services.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ def service_status(name, server=nil)
334334
raise RuntimeError.new("Could not query service. QueryServiceStatus error: #{handle["GetLastError"]}")
335335
end
336336

337-
vals = status['lpServiceStatus'].unpack('L*')
337+
vals = status['lpServiceStatus'].unpack('V*')
338338
adv.CloseServiceHandle(handle["return"])
339339

340340
ret = {

lib/msf/util/exe.rb

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -340,22 +340,22 @@ def self.to_winpe_only(framework, code, opts={}, arch="x86")
340340

341341
# look for section with entry point
342342
sections_header.each do |sec|
343-
virtualAddress = sec[1][virtualAddress_offset,0x4].unpack('L')[0]
344-
sizeOfRawData = sec[1][sizeOfRawData_offset,0x4].unpack('L')[0]
345-
characteristics = sec[1][characteristics_offset,0x4].unpack('L')[0]
343+
virtualAddress = sec[1][virtualAddress_offset,0x4].unpack('V')[0]
344+
sizeOfRawData = sec[1][sizeOfRawData_offset,0x4].unpack('V')[0]
345+
characteristics = sec[1][characteristics_offset,0x4].unpack('V')[0]
346346

347347
if (virtualAddress...virtualAddress+sizeOfRawData).include?(addressOfEntryPoint)
348-
importsTable = pe.hdr.opt.DataDirectory[8..(8+4)].unpack('L')[0]
348+
importsTable = pe.hdr.opt.DataDirectory[8..(8+4)].unpack('V')[0]
349349
if (importsTable - addressOfEntryPoint) < code.length
350350
#shift original entry point to prevent tables overwritting
351351
addressOfEntryPoint = importsTable - (code.length + 4)
352352

353353
entry_point_offset = pe._dos_header.v['e_lfanew'] + entryPoint_offset
354-
exe[entry_point_offset,4] = [addressOfEntryPoint].pack('L')
354+
exe[entry_point_offset,4] = [addressOfEntryPoint].pack('V')
355355
end
356356
# put this section writable
357357
characteristics |= 0x8000_0000
358-
newcharacteristics = [characteristics].pack('L')
358+
newcharacteristics = [characteristics].pack('V')
359359
exe[sec[0],newcharacteristics.length] = newcharacteristics
360360
end
361361
end
@@ -572,20 +572,20 @@ def self.to_win32pe_service(framework, code, opts={})
572572
"\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58\x5F\x5A\x8B\x12\xEB\x86\x5D" +
573573
"\x6A\x00\x68\x70\x69\x33\x32\x68\x61\x64\x76\x61\x54\x68\x4C\x77" +
574574
"\x26\x07\xFF\xD5"+pushed_service_name+"\x89\xE1" +
575-
"\x8D\x85"+[svcmain_code_offset].pack('<I')+"\x6A\x00\x50\x51\x89\xE0\x6A\x00\x50\x68" +
575+
"\x8D\x85"+[svcmain_code_offset].pack('V')+"\x6A\x00\x50\x51\x89\xE0\x6A\x00\x50\x68" +
576576
"\xFA\xF7\x72\xCB\xFF\xD5\x6A\x00\x68\xF0\xB5\xA2\x56\xFF\xD5\x58" +
577577
"\x58\x58\x58\x31\xC0\xC3\xFC\xE8\x00\x00\x00\x00\x5D\x81\xED" +
578-
[hash_code_offset].pack('<I')+pushed_service_name+"\x89\xE1\x8D" +
579-
"\x85"+[svcctrlhandler_code_offset].pack('<I')+"\x6A\x00\x50\x51\x68\x0B\xAA\x44\x52\xFF\xD5" +
578+
[hash_code_offset].pack('V')+pushed_service_name+"\x89\xE1\x8D" +
579+
"\x85"+[svcctrlhandler_code_offset].pack('V')+"\x6A\x00\x50\x51\x68\x0B\xAA\x44\x52\xFF\xD5" +
580580
"\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x6A\x04\x6A\x10" +
581581
"\x89\xE1\x6A\x00\x51\x50\x68\xC6\x55\x37\x7D\xFF\xD5\x31\xFF\x6A" +
582582
"\x04\x68\x00\x10\x00\x00\x6A\x54\x57\x68\x58\xA4\x53\xE5\xFF\xD5" +
583583
"\xC7\x00\x44\x00\x00\x00\x8D\x70\x44\x57\x68\x2E\x65\x78\x65\x68" +
584584
"\x6C\x6C\x33\x32\x68\x72\x75\x6E\x64\x89\xE1\x56\x50\x57\x57\x6A" +
585585
"\x44\x57\x57\x57\x51\x57\x68\x79\xCC\x3F\x86\xFF\xD5\x8B\x0E\x6A" +
586-
"\x40\x68\x00\x10\x00\x00\x68"+[code.length].pack('<I')+"\x57\x51\x68\xAE\x87" +
586+
"\x40\x68\x00\x10\x00\x00\x68"+[code.length].pack('V')+"\x57\x51\x68\xAE\x87" +
587587
"\x92\x3F\xFF\xD5\xE8\x00\x00\x00\x00\x5A\x89\xC7\x8B\x0E\x81\xC2" +
588-
[shellcode_code_offset].pack('<I')+"\x54\x68"+[code.length].pack('<I') +
588+
[shellcode_code_offset].pack('V')+"\x54\x68"+[code.length].pack('V') +
589589
"\x52\x50\x51\x68\xC5\xD8\xBD\xE7\xFF" +
590590
"\xD5\x31\xC0\x8B\x0E\x50\x50\x50\x57\x50\x50\x51\x68\xC6\xAC\x9A" +
591591
"\x79\xFF\xD5\x8B\x0E\x51\x68\xC6\x96\x87\x52\xFF\xD5\x8B\x4E\x04" +
@@ -654,12 +654,17 @@ def self.replace_msi_buffer(pe, opts)
654654
msi = fd.read(fd.stat.size)
655655
}
656656

657-
section_size = 2**(msi[30..31].unpack('s')[0])
658-
sector_allocation_table = msi[section_size..section_size*2].unpack('l*')
657+
section_size = 2**(msi[30..31].unpack('v')[0])
658+
659+
# This table is one of the few cases where signed values are needed
660+
sector_allocation_table = msi[section_size..section_size*2].unpack('l<*')
659661

660662
buffer_chain = []
661-
current_secid = 5 # This is closely coupled with the template provided and ideally
662-
# would be calculated from the dir stream?
663+
664+
# This is closely coupled with the template provided and ideally
665+
# would be calculated from the dir stream?
666+
current_secid = 5
667+
663668

664669
until current_secid == -2
665670
buffer_chain << current_secid
@@ -827,22 +832,22 @@ def self.to_exe_elf(framework, opts, template, code, big_endian=false)
827832

828833
# Check EI_CLASS to determine if the header is 32 or 64 bit
829834
# Use the proper offsets and pack size
830-
case elf[4]
831-
when 1, "\x01" # ELFCLASS32 - 32 bit (ruby 1.8 and 1.9)
835+
case elf[4,1].unpack("C").first
836+
when 1 # ELFCLASS32 - 32 bit (ruby 1.9+)
832837
if big_endian
833838
elf[0x44,4] = [elf.length].pack('N') #p_filesz
834839
elf[0x48,4] = [elf.length + code.length].pack('N') #p_memsz
835840
else # little endian
836841
elf[0x44,4] = [elf.length].pack('V') #p_filesz
837842
elf[0x48,4] = [elf.length + code.length].pack('V') #p_memsz
838843
end
839-
when 2, "\x02" # ELFCLASS64 - 64 bit (ruby 1.8 and 1.9)
844+
when 2 # ELFCLASS64 - 64 bit (ruby 1.9+)
840845
if big_endian
841846
elf[0x60,8] = [elf.length].pack('Q>') #p_filesz
842847
elf[0x68,8] = [elf.length + code.length].pack('Q>') #p_memsz
843848
else # little endian
844-
elf[0x60,8] = [elf.length].pack('Q') #p_filesz
845-
elf[0x68,8] = [elf.length + code.length].pack('Q') #p_memsz
849+
elf[0x60,8] = [elf.length].pack('Q<') #p_filesz
850+
elf[0x68,8] = [elf.length + code.length].pack('Q<') #p_memsz
846851
end
847852
else
848853
raise RuntimeError, "Invalid ELF template: EI_CLASS value not supported"

lib/rex/arch.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def self.pack_addr(arch, addr)
4949
when ARCH_X86
5050
[addr].pack('V')
5151
when ARCH_X86_64
52-
[addr].pack('Q')
52+
[addr].pack('Q<')
5353
when ARCH_MIPS # ambiguous
5454
[addr].pack('N')
5555
when ARCH_MIPSBE

lib/rex/encoder/ndr.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def NDR.short(string)
2828
# use to encode:
2929
# byte element_1;
3030
def NDR.byte(string)
31-
return [string].pack('c')
31+
return [string].pack('C')
3232
end
3333

3434
# Encode a byte array

lib/rex/ole/util.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,15 @@ def self.pack8(value)
124124

125125

126126
def self.getUnicodeString(buf)
127-
buf = buf.unpack('S*').pack('C*')
127+
buf = buf.unpack('v*').pack('C*')
128128
if (idx = buf.index(0x00.chr))
129129
buf.slice!(idx, buf.length)
130130
end
131131
buf
132132
end
133133

134134
def self.putUnicodeString(buf)
135-
buf = buf.unpack('C*').pack('S*')
135+
buf = buf.unpack('C*').pack('v*')
136136
if (buf.length < 0x40)
137137
buf << "\x00" * (0x40 - buf.length)
138138
end

lib/rex/post/meterpreter/extensions/stdapi/railgun/type/pointer_util.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ def self.pack_pointer(pointer, platform)
2727

2828
case platform
2929
when PlatformUtil::X86_64
30-
# XXX: Only works if attacker and victim are like-endianed
31-
[pointer].pack('Q')
30+
# Assume little endian
31+
[pointer].pack('Q<')
3232
when PlatformUtil::X86_32
3333
[pointer].pack('V')
3434
else
@@ -40,8 +40,8 @@ def self.pack_pointer(pointer, platform)
4040
def self.unpack_pointer(packed_pointer, platform)
4141
case platform
4242
when PlatformUtil::X86_64
43-
# XXX: Only works if attacker and victim are like-endianed
44-
packed_pointer.unpack('Q').first
43+
# Assume little endian
44+
packed_pointer.unpack('Q<').first
4545
when PlatformUtil::X86_32
4646
packed_pointer.unpack('V').first
4747
else

0 commit comments

Comments
 (0)