From c9b6c05eab5d654f790dd4005fcdcf6c65f8cecd Mon Sep 17 00:00:00 2001 From: HD Moore Date: Mon, 30 Jun 2014 02:48:18 -0500 Subject: [PATCH] Fix improper use of host-endian or signed pack/unpack Note that there are some cases of host-endian left, these are intentional because they operate on host-local memory or services. When in doubt, please use: ``` ri pack ``` --- lib/bit-struct/octet-field.rb | 2 +- lib/msf/core/exploit/afp.rb | 3 +-- lib/msf/core/post/windows/accounts.rb | 2 +- lib/msf/core/post/windows/ldap.rb | 4 ++-- lib/msf/core/post/windows/services.rb | 2 +- lib/msf/util/exe.rb | 4 ++-- lib/rex/encoder/ndr.rb | 2 +- lib/rex/ole/util.rb | 4 ++-- .../extensions/stdapi/railgun/util.rb | 4 ++-- lib/rex/proto/dcerpc/ndr.rb | 2 +- lib/rex/proto/natpmp/packet.rb | 6 +++--- lib/rex/registry/lfkey.rb | 2 +- lib/rex/registry/nodekey.rb | 20 +++++++++---------- lib/rex/registry/valuekey.rb | 10 +++++----- lib/rex/registry/valuelist.rb | 2 +- lib/rex/socket/ip.rb | 1 + lib/sshkey/lib/sshkey.rb | 2 +- lib/windows_console_color_support.rb | 2 +- .../windows/fileformat/ms14_017_rtf.rb | 2 +- .../windows/local/ms11_080_afdjoinleaf.rb | 14 ++++++------- ...dworks_workgroup_pdmwservice_file_write.rb | 4 ++-- .../scada/ge_proficy_cimplicity_gefebt.rb | 2 +- .../stagers/windows/reverse_https_proxy.rb | 2 +- .../gather/credentials/enum_cred_store.rb | 10 +++++----- modules/post/windows/gather/enum_ie.rb | 14 ++++++------- .../gather/forensics/recovery_files.rb | 8 ++++---- 26 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lib/bit-struct/octet-field.rb b/lib/bit-struct/octet-field.rb index 5967967fc8..1281a136a5 100644 --- a/lib/bit-struct/octet-field.rb +++ b/lib/bit-struct/octet-field.rb @@ -37,7 +37,7 @@ class BitStruct old_writer = "#{attr_chars}=" define_method "#{attr}=" do |val| - data = val.split(sep).map{|s|s.to_i(base)}.pack("c*") + data = val.split(sep).map{|s|s.to_i(base)}.pack("C*") send(old_writer, data) end end diff --git a/lib/msf/core/exploit/afp.rb b/lib/msf/core/exploit/afp.rb index 1141a25c2d..0feffb6c51 100644 --- a/lib/msf/core/exploit/afp.rb +++ b/lib/msf/core/exploit/afp.rb @@ -246,8 +246,7 @@ module Exploit::Remote::AFP end def parse_header(packet) - header = packet.unpack('CCnNNN') #ruby 1.8.7 don't support unpacking signed integers in big-endian order - header[3] = packet[4..7].reverse.unpack("l").first + header = packet.unpack('CCnNNN') return header end diff --git a/lib/msf/core/post/windows/accounts.rb b/lib/msf/core/post/windows/accounts.rb index f092f48240..5590fce301 100644 --- a/lib/msf/core/post/windows/accounts.rb +++ b/lib/msf/core/post/windows/accounts.rb @@ -270,7 +270,7 @@ module Accounts #define generic mapping structure gen_map = [0,0,0,0] - gen_map = gen_map.pack("L") + gen_map = gen_map.pack("V") buffer_size = 500 #get Security Descriptor for the directory diff --git a/lib/msf/core/post/windows/ldap.rb b/lib/msf/core/post/windows/ldap.rb index 960ca5af0e..0e3aae269a 100644 --- a/lib/msf/core/post/windows/ldap.rb +++ b/lib/msf/core/post/windows/ldap.rb @@ -248,7 +248,7 @@ module LDAP # @param pEntry [Fixnum] Pointer to the Entry # @return [Array] Entry data structure def get_entry(pEntry) - return client.railgun.memread(pEntry,41).unpack('LLLLLLLLLSCCC') + return client.railgun.memread(pEntry,41).unpack('VVVVVVVVVvCCC') end # Get BER Element data structure from LDAPMessage @@ -256,7 +256,7 @@ module LDAP # @param msg [String] The LDAP Message from the server # @return [String] The BER data structure def get_ber(msg) - ber = client.railgun.memread(msg[2],60).unpack('L*') + ber = client.railgun.memread(msg[2],60).unpack('V*') # BER Pointer is different between x86 and x64 if client.platform =~ /x64/ diff --git a/lib/msf/core/post/windows/services.rb b/lib/msf/core/post/windows/services.rb index 2893e9b640..a3d0d20b5a 100644 --- a/lib/msf/core/post/windows/services.rb +++ b/lib/msf/core/post/windows/services.rb @@ -334,7 +334,7 @@ module Services raise RuntimeError.new("Could not query service. QueryServiceStatus error: #{handle["GetLastError"]}") end - vals = status['lpServiceStatus'].unpack('L*') + vals = status['lpServiceStatus'].unpack('V*') adv.CloseServiceHandle(handle["return"]) ret = { diff --git a/lib/msf/util/exe.rb b/lib/msf/util/exe.rb index 4ea17988d5..4747316fe4 100644 --- a/lib/msf/util/exe.rb +++ b/lib/msf/util/exe.rb @@ -654,8 +654,8 @@ require 'msf/core/exe/segment_injector' msi = fd.read(fd.stat.size) } - section_size = 2**(msi[30..31].unpack('s<')[0]) - sector_allocation_table = msi[section_size..section_size*2].unpack('l<*') + section_size = 2**(msi[30..31].unpack('v')[0]) + sector_allocation_table = msi[section_size..section_size*2].unpack('V*') buffer_chain = [] current_secid = 5 # This is closely coupled with the template provided and ideally diff --git a/lib/rex/encoder/ndr.rb b/lib/rex/encoder/ndr.rb index b1bfb2c5da..7ccd7d75d1 100644 --- a/lib/rex/encoder/ndr.rb +++ b/lib/rex/encoder/ndr.rb @@ -28,7 +28,7 @@ module NDR # use to encode: # byte element_1; def NDR.byte(string) - return [string].pack('c') + return [string].pack('C') end # Encode a byte array diff --git a/lib/rex/ole/util.rb b/lib/rex/ole/util.rb index 867bc16b46..e2dfbca281 100644 --- a/lib/rex/ole/util.rb +++ b/lib/rex/ole/util.rb @@ -124,7 +124,7 @@ class Util def self.getUnicodeString(buf) - buf = buf.unpack('S*').pack('C*') + buf = buf.unpack('v*').pack('C*') if (idx = buf.index(0x00.chr)) buf.slice!(idx, buf.length) end @@ -132,7 +132,7 @@ class Util end def self.putUnicodeString(buf) - buf = buf.unpack('C*').pack('S*') + buf = buf.unpack('C*').pack('v*') if (buf.length < 0x40) buf << "\x00" * (0x40 - buf.length) end diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb index d98e63e4ee..6b25a60042 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb @@ -452,9 +452,9 @@ class Util # Both on x86 and x64, DWORD is 32 bits return raw.unpack('V').first when :BOOL - return raw.unpack('l').first == 1 + return raw.unpack('V').first == 1 when :LONG - return raw.unpack('l').first + return raw.unpack('V').first end #If nothing worked thus far, return it raw diff --git a/lib/rex/proto/dcerpc/ndr.rb b/lib/rex/proto/dcerpc/ndr.rb index f730378085..2129adae0f 100644 --- a/lib/rex/proto/dcerpc/ndr.rb +++ b/lib/rex/proto/dcerpc/ndr.rb @@ -34,7 +34,7 @@ class NDR # byte element_1; def self.byte(string) warn 'should be using Rex::Encoder::NDR' - return [string].pack('c') + return [string].pack('C') end # Encode a byte array diff --git a/lib/rex/proto/natpmp/packet.rb b/lib/rex/proto/natpmp/packet.rb index 4ce7c88cba..16b791f3ac 100644 --- a/lib/rex/proto/natpmp/packet.rb +++ b/lib/rex/proto/natpmp/packet.rb @@ -19,7 +19,7 @@ module NATPMP # Parse a NAT-PMP external address response +resp+. # Returns the decoded parts of the response as an array. def self.parse_external_address_response(resp) - (ver, op, result, epoch, addr) = resp.unpack("CCSLN") + (ver, op, result, epoch, addr) = resp.unpack("CCvVN") [ ver, op, result, epoch, Rex::Socket::addr_itoa(addr) ] end @@ -31,13 +31,13 @@ module NATPMP lport, rport, lifetime - ].pack("ccnnnN") + ].pack("CCnnnN") end # Parse a NAT-PMP mapping response +resp+. # Returns the decoded parts as an array. def self.parse_map_port_response(resp) - resp.unpack("CCSLnnN") + resp.unpack("CCvVnnN") end end diff --git a/lib/rex/registry/lfkey.rb b/lib/rex/registry/lfkey.rb index fddeb75332..220cfa7306 100644 --- a/lib/rex/registry/lfkey.rb +++ b/lib/rex/registry/lfkey.rb @@ -41,7 +41,7 @@ class LFHashRecord attr_accessor :nodekey_offset, :nodekey_name_verification def initialize(hive_blob, offset) - @nodekey_offset = hive_blob[offset, 4].unpack('l').first + @nodekey_offset = hive_blob[offset, 4].unpack('V').first @nodekey_name_verification = hive_blob[offset+0x04, 4].to_s end diff --git a/lib/rex/registry/nodekey.rb b/lib/rex/registry/nodekey.rb index d32c52407a..7530792f96 100644 --- a/lib/rex/registry/nodekey.rb +++ b/lib/rex/registry/nodekey.rb @@ -23,16 +23,16 @@ class NodeKey return end - @timestamp = hive[offset+0x04, 8].unpack('q').first - @parent_offset = hive[offset+0x10, 4].unpack('l').first - @subkeys_count = hive[offset+0x14, 4].unpack('l').first - @lf_record_offset = hive[offset+0x1c, 4].unpack('l').first - @value_count = hive[offset+0x24, 4].unpack('l').first - @value_list_offset = hive[offset+0x28, 4].unpack('l').first - @security_key_offset = hive[offset+0x2c, 4].unpack('l').first - @class_name_offset = hive[offset+0x30, 4].unpack('l').first - @name_length = hive[offset+0x48, 2].unpack('c').first - @class_name_length = hive[offset+0x4a, 2].unpack('c').first + @timestamp = hive[offset+0x04, 8].unpack('Q').first + @parent_offset = hive[offset+0x10, 4].unpack('V').first + @subkeys_count = hive[offset+0x14, 4].unpack('V').first + @lf_record_offset = hive[offset+0x1c, 4].unpack('V').first + @value_count = hive[offset+0x24, 4].unpack('V').first + @value_list_offset = hive[offset+0x28, 4].unpack('V').first + @security_key_offset = hive[offset+0x2c, 4].unpack('V').first + @class_name_offset = hive[offset+0x30, 4].unpack('V').first + @name_length = hive[offset+0x48, 2].unpack('C').first + @class_name_length = hive[offset+0x4a, 2].unpack('C').first @name = hive[offset+0x4c, @name_length].to_s windows_time = @timestamp diff --git a/lib/rex/registry/valuekey.rb b/lib/rex/registry/valuekey.rb index fdb27fb6e6..61a7c07d2d 100644 --- a/lib/rex/registry/valuekey.rb +++ b/lib/rex/registry/valuekey.rb @@ -17,10 +17,10 @@ class ValueKey return end - @name_length = hive[offset+0x02, 2].unpack('c').first - @length_of_data = hive[offset+0x04, 4].unpack('l').first - @data_offset = hive[offset+ 0x08, 4].unpack('l').first - @value_type = hive[offset+0x0C, 4].unpack('c').first + @name_length = hive[offset+0x02, 2].unpack('C').first + @length_of_data = hive[offset+0x04, 4].unpack('V').first + @data_offset = hive[offset+ 0x08, 4].unpack('V').first + @value_type = hive[offset+0x0C, 4].unpack('C').first if @value_type == 1 @readable_value_type = "Unicode character string" @@ -34,7 +34,7 @@ class ValueKey @readable_value_type = "Multiple unicode strings separated with '\\x00'" end - flag = hive[offset+0x10, 2].unpack('c').first + flag = hive[offset+0x10, 2].unpack('C').first if flag == 0 @name = "Default" diff --git a/lib/rex/registry/valuelist.rb b/lib/rex/registry/valuelist.rb index 1fb0906dfe..63900c14a4 100644 --- a/lib/rex/registry/valuelist.rb +++ b/lib/rex/registry/valuelist.rb @@ -18,7 +18,7 @@ class ValueList valuekey_offset = hive[offset + inner_offset, 4] next if !valuekey_offset - valuekey_offset = valuekey_offset.unpack('l').first + valuekey_offset = valuekey_offset.unpack('V').first @values << ValueKey.new(hive, valuekey_offset + 0x1000) inner_offset = inner_offset + 4 end diff --git a/lib/rex/socket/ip.rb b/lib/rex/socket/ip.rb index 6a2d11b81d..4399df98c5 100644 --- a/lib/rex/socket/ip.rb +++ b/lib/rex/socket/ip.rb @@ -75,6 +75,7 @@ module Rex::Socket::Ip Rex::Compat.is_macosx ) gram=gram.dup + # Note that these are *intentionally* host order for BSD support gram[2,2]=gram[2,2].unpack("n").pack("s") gram[6,2]=gram[6,2].unpack("n").pack("s") end diff --git a/lib/sshkey/lib/sshkey.rb b/lib/sshkey/lib/sshkey.rb index 6035c10416..6a89dbee21 100644 --- a/lib/sshkey/lib/sshkey.rb +++ b/lib/sshkey/lib/sshkey.rb @@ -159,7 +159,7 @@ class SSHKey SSH_CONVERSION[type].each do |method| byte_array = to_byte_array(key_object.public_key.send(method).to_i) - out += encode_unsigned_int_32(byte_array.length).pack("c*") + out += encode_unsigned_int_32(byte_array.length).pack("C*") out += byte_array.pack("C*") end diff --git a/lib/windows_console_color_support.rb b/lib/windows_console_color_support.rb index a2d23d6dad..2b626cc078 100644 --- a/lib/windows_console_color_support.rb +++ b/lib/windows_console_color_support.rb @@ -36,7 +36,7 @@ class WindowsConsoleColorSupport def setcolor(color) csbi = 0.chr * 24 @GetConsoleScreenBufferInfo.Call(@hConsoleHandle,csbi) - wAttr = csbi[8,2].unpack('S').first + wAttr = csbi[8,2].unpack('v').first case color when 0 # reset diff --git a/modules/exploits/windows/fileformat/ms14_017_rtf.rb b/modules/exploits/windows/fileformat/ms14_017_rtf.rb index c5f47fbc8c..b1e687832a 100644 --- a/modules/exploits/windows/fileformat/ms14_017_rtf.rb +++ b/modules/exploits/windows/fileformat/ms14_017_rtf.rb @@ -99,7 +99,7 @@ class Metasploit3 < Msf::Exploit::Remote exploit_data << rop_chain exploit_data << payload.encoded exploit_data << make_nops(exploit_data.length % 2) - exploit_data = exploit_data.unpack("S<*") + exploit_data = exploit_data.unpack("v*") exploit_data = exploit_data.map { |word| " ?\\u-#{0x10000 - word}" } exploit_data = exploit_data.join diff --git a/modules/exploits/windows/local/ms11_080_afdjoinleaf.rb b/modules/exploits/windows/local/ms11_080_afdjoinleaf.rb index 636f60f378..747861ed60 100644 --- a/modules/exploits/windows/local/ms11_080_afdjoinleaf.rb +++ b/modules/exploits/windows/local/ms11_080_afdjoinleaf.rb @@ -89,7 +89,7 @@ class Metasploit3 < Msf::Exploit::Local session.railgun.add_function('psapi', 'EnumDeviceDrivers', 'BOOL', [ ["PBLOB", "lpImageBase", "out"], ["DWORD", "cb", "in"], ["PDWORD", "lpcbNeeded", "out"]]) session.railgun.add_function('psapi', 'GetDeviceDriverBaseNameA', 'DWORD', [ ["LPVOID", "ImageBase", "in"], ["PBLOB", "lpBaseName", "out"], ["DWORD", "nSize", "in"]]) results = session.railgun.psapi.EnumDeviceDrivers(4096, 1024, 4) - addresses = results['lpImageBase'][0..results['lpcbNeeded'] - 1].unpack("L*") + addresses = results['lpImageBase'][0..results['lpcbNeeded'] - 1].unpack("V*") addresses.each do |address| results = session.railgun.psapi.GetDeviceDriverBaseNameA(address, 48, 48) @@ -172,7 +172,7 @@ class Metasploit3 < Msf::Exploit::Local irpstuff << rand_text_alpha(231) if not this_proc.memory.writable?(0x1000) - result = session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ base_addr ].pack("L"), nil, [ 0x1000 ].pack("L"), "MEM_COMMIT | MEM_RESERVE", "PAGE_EXECUTE_READWRITE") + result = session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ base_addr ].pack("V"), nil, [ 0x1000 ].pack("V"), "MEM_COMMIT | MEM_RESERVE", "PAGE_EXECUTE_READWRITE") end if not this_proc.memory.writable?(0x1000) print_error('Failed to properly allocate memory') @@ -202,10 +202,10 @@ class Metasploit3 < Msf::Exploit::Local halDispatchTable0x8 = halDispatchTable + 0x8 restore_ptrs = "\x31\xc0" - restore_ptrs << "\xb8" + [ halpSetSystemInformation ].pack("L") - restore_ptrs << "\xa3" + [ halDispatchTable0x8 ].pack("L") - restore_ptrs << "\xb8" + [ haliQuerySystemInformation ].pack("L") - restore_ptrs << "\xa3" + [ halDispatchTable0x4 ].pack("L") + restore_ptrs << "\xb8" + [ halpSetSystemInformation ].pack("V") + restore_ptrs << "\xa3" + [ halDispatchTable0x8 ].pack("V") + restore_ptrs << "\xb8" + [ haliQuerySystemInformation ].pack("V") + restore_ptrs << "\xa3" + [ halDispatchTable0x4 ].pack("V") tokenstealing = "\x52" tokenstealing << "\x53" @@ -241,7 +241,7 @@ class Metasploit3 < Msf::Exploit::Local this_proc.memory.write(shellcode_address_nodep, shellcode) this_proc.memory.protect(0x00020000) - addr = [ 2, 4455, 0x7f000001, 0, 0 ].pack("s!S!L!L!L!") + addr = [ 2, 4455, 0x7f000001, 0, 0 ].pack("vvVVV") result = session.railgun.ws2_32.connect(socket, addr, addr.length) if result['return'] != 0xffffffff print_error("The socket is not in the correct state") diff --git a/modules/exploits/windows/misc/solidworks_workgroup_pdmwservice_file_write.rb b/modules/exploits/windows/misc/solidworks_workgroup_pdmwservice_file_write.rb index 25ed303ca5..0a6c6d3200 100644 --- a/modules/exploits/windows/misc/solidworks_workgroup_pdmwservice_file_write.rb +++ b/modules/exploits/windows/misc/solidworks_workgroup_pdmwservice_file_write.rb @@ -105,11 +105,11 @@ class Metasploit3 < Msf::Exploit::Remote # op code req = "\xD0\x07\x00\x00" # filename length - req << "#{[fname.length].pack('l')}" + req << "#{[fname.length].pack('V')}" # file name req << "#{fname}" # data length - req << "#{[data.length].pack('l')}" + req << "#{[data.length].pack('V')}" # data req << "#{data}" connect diff --git a/modules/exploits/windows/scada/ge_proficy_cimplicity_gefebt.rb b/modules/exploits/windows/scada/ge_proficy_cimplicity_gefebt.rb index 4ad7445083..115f4bd7d4 100644 --- a/modules/exploits/windows/scada/ge_proficy_cimplicity_gefebt.rb +++ b/modules/exploits/windows/scada/ge_proficy_cimplicity_gefebt.rb @@ -228,7 +228,7 @@ class Metasploit3 < Msf::Exploit::Remote exe = generate_payload_exe # Padding to be sure we're aligned to 4 bytes. exe << "\x00" until exe.length % 4 == 0 - longs = exe.unpack("l*") + longs = exe.unpack("V*") offset = 0 # gefebt.exe isn't able to handle (on my test environment) long diff --git a/modules/payloads/stagers/windows/reverse_https_proxy.rb b/modules/payloads/stagers/windows/reverse_https_proxy.rb index 72de85106c..1133fe0252 100644 --- a/modules/payloads/stagers/windows/reverse_https_proxy.rb +++ b/modules/payloads/stagers/windows/reverse_https_proxy.rb @@ -129,7 +129,7 @@ module Metasploit3 jmphost_loc = p.index("\x68\x3a\x56\x79\xa7\xff\xd5") + 8 # push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" ) ; call ebp p[jmphost_loc, 4] = [p[jmphost_loc, 4].unpack("V")[0] - jmp_offset].pack("V") #patch call Internetopen - p[p.length - 4, 4] = [p[p.length - 4, 4].unpack("l")[0] + jmp_offset].pack("V") + p[p.length - 4, 4] = [p[p.length - 4, 4].unpack("V")[0] + jmp_offset].pack("V") # patch the LPORT lport = datastore['LPORT'] diff --git a/modules/post/windows/gather/credentials/enum_cred_store.rb b/modules/post/windows/gather/credentials/enum_cred_store.rb index e0fbaa22bd..a12997c5fa 100644 --- a/modules/post/windows/gather/credentials/enum_cred_store.rb +++ b/modules/post/windows/gather/credentials/enum_cred_store.rb @@ -37,7 +37,7 @@ class Metasploit3 < Msf::Post if is_86 addr = [data].pack("V") else - addr = [data].pack("Q") + addr = [data].pack("Q<") end return addr end @@ -95,7 +95,7 @@ class Metasploit3 < Msf::Post len,add = ret["pDataOut"].unpack("V2") else ret = c32.CryptUnprotectData("#{len}#{addr}",16,"#{elen}#{eaddr}",nil,nil,0,16) - len,add = ret["pDataOut"].unpack("Q2") + len,add = ret["pDataOut"].unpack("Q<2") end #get data, and return it @@ -177,14 +177,14 @@ class Metasploit3 < Msf::Post #read array of addresses as pointers to each structure raw = read_str(p_to_arr[0], arr_len, 2) pcred_array = raw.unpack("V*") if is_86 - pcred_array = raw.unpack("Q*") unless is_86 + pcred_array = raw.unpack("Q<*") unless is_86 #loop through the addresses and read each credential structure pcred_array.each do |pcred| cred = {} raw = read_str(pcred, 52,2) - cred_struct = raw.unpack("VVVVQVVVVVVV") if is_86 - cred_struct = raw.unpack("VVQQQQQVVQQQ") unless is_86 + cred_struct = raw.unpack("VVVVQ