Thursday, May 28, 2015

Exploiting memory corruption bugs in PHP Part 3: Popping Remote Shells

This took longer than expected, but it's a journey worth taking! This is less descriptive than other blog posts, because I'd like to try the video format out once. AKA, I'm lazy :)

Disappointingly for some, this will be a guide to create a POC. See the video at the end for what a my automated & remote exploit looks like, as well as tips & tricks to get things working in a real environment.

I kept the app stupid to make life easy. It literally attempts to serialize whatever data is sent to the page, after base64_decoding it. More complicated exploits will require a little more fines :).

We need a way to execute arbitrary PHP code. Sure, we could try to inject shellcode, but that's not very creative, and much noisier than executing arbitrary PHP code (Also impossible in newer versions of PHP, unless it's very tiny). If you recall from Part 1, to execute code, we need to call php_execute_script AND zend_eval_string. However, since we're going to be attacking "remotely", we also need to find the executor_globals, and the JMP_BUF. More on those later.

In short, we need to find (In no particular order):
  • executor_globals
  • zend_eval_string
  • JMP_BUF
  • A way to write arbitrary data to the stack
Thankfully, some of these we can find relatively quickly, since they're in the binary. Let's go ahead and dump the String table of the PHP binary.



Great! Let's go ahead and start pulling addresses from it as well, and verifying that those addresses are correct in GDB.

Finding zend_eval_string's address
GDB showing that the address is legitimate
Finding executor_global's address
GDB showing that the address is legitimate
Awesome! Now, how do we find JMP_BUF? Well, while reading the source code for the _zend_executor_globals object, we find an interesting piece of information. A JMP_BUF pointer, called bailout. Let's look at this in GDB, and see if the address is useful.

Printing the _zend_executor_globals object
A better way to check the value of bailout
Well, we have an address, but what does this address point to? Is it even useful? Well, in PHP, JMP_BUF is used as a type of "try{} - catch{}" at the C level, but more on this later.

We're now only lacking one thing: A way to inject the malicious string onto the stack. Stefan's method in the 2010 Syscan talk will be discussed further in this blog post. Since we won't be freeing arbitrary memory addresses, what's the next best thing we could do? We could write to the stack, but how? And how do we guarantee that it won't be overwritten in the future? (Google is your friend here ;) ).

An RFC, specifically RFC1867.

This RFC allows POST requests with the multipart/form-data to set stack buffers, which aren't overwritten by PHP completely (due to a number of reasons). Let's try this out by posting "the usual" in a file. 


Awesome! We can write whatever we want to the stack now. But what do we want to write?
Hint: It's what we found earlier :)
Since we spent all this time figuring out what was where, we should probably use that! So, how do we lay it out? After some investigating, we need the stack to look like this:



Starting with the easy ones: We already have Zend_Eval String, since we found it earlier with readelf. Both the Ret Pointer and Zend_Bailout can be garbage, since we don't care about either of them (This will cause PHP to crash either way, without making the exploit more complicated). We can set the pointer_to_eval_string both times since we control the stack. So, here's what we have data on now:
  • POP; RET - ?????
  • XCHG EAX, ESP; RET - ????
  • Zend_Eval_String - 0x082da150
  • Zend_Bailout - 0x00000000
  • Pointer_To_Eval_String - 0xbfffda04
  • Ret Pointer - 0x00000000
  • Pointer_To_Eval_String - 0xbfffda04
Sweet! We have most of this already filled in, excellent! Unfortunately, it looks like we need some ROP gadgets. I prefer to use ROPGadget myself, but any gadget finding tool should suffice. We need to find XCHG EAX, ESP; RET (0x94 0xc3), and we also need to find POP EBP; RET (0x5d 0xc3). Once you have those gadgets, you're good to go! Let's go ahead and give it a shot!



Awesome! Now that we have these two locations (Why are the addresses so different? These are offsets!), we can complete the stack as follows:

  • POP; RET - 0x000e8e68
  • XCHG EAX, ESP; RET - 0x000057b7
  • Zend_Eval_String - 0x082da150
  • Zend_Bailout - 0x00000000
  • Pointer_To_Eval_String - 0xbfffda04
  • Ret Pointer - 0x00000000
  • Pointer_To_Eval_String - 0xbfffda04
Now that we have a complete view on how we want the stack to look, it's time to test this bad boy out. So, let's get to it! 


Hmmm, that didn't work out quite as expected, now did it? In fact, that looks like our code is trying to jump to our gadget (c394). Unfortunately, there's one more thing you have to know. There's a special object that's required for these gadgets to be useful without crashing PHP, otherwise the gadget's aren't useful at all. I'll save you the trouble of guessing/digging around in old code to figure it out. The object you need is SPLObjectStorage. Knowing this, we'll have to reformat all of our attacks from before. Once we have done that, then get the following after running through our exploit again, as shown below:

Screenshot taken from fully automated Python exploit. See video for details
This is my stopping point for this method, as it only affects older versions of php (With these same gadgets). For newer versions of PHP, keep reading :).

Fortunately not much changes. Recall that we looked up the address of php_execute_script AND the jmp_buf. We'll need both for this version of the exploit. 

jmp_buf is used by setjmp & longjmp, and saves the "environment" in case of an "unrecoverable" error. The jmpbuf is different depending on your architecture. For 32 bit, this is an unsigned array with 6 ints. If you're on 64 bit, there are 8 ints. Unfortunately, due to how this is implemented, there will be some digging in source code required for you to determine which position the registers are in within the jmp_buf. Here's an example of the jmp_buf layout. Of course, let's see how this looks in PHP...


Great! For my machine, the order of registers are: ebx, esp, ebp, esi, edi, eip. Since things worth doing in life aren't easy, this of course isn't a simple search! It looks like our edi & eip register are obfuscated. How're they obfuscated? By Glibc of course! Glibc has a macro called PTR_MANGLE. In the video we'll discuss how we crack the JMPBUF. 

Once we have it cracked, we need a way to overwrite and free memory. Thankfully, the same object (SPLObjectStorage) allows us to free memory remotely. All that's left is writing data to the stack. Just like in Part 2, we abuse the memory caching of PHP. We free some memory, write a small 7 byte string to fill it, and when php overwrites part of our data, we do it again. This 2nd overwriting allows us to write an arbitrarily amount of data on the stack (I did not test for values over 2048). This data that we want to write is very similar to what we used in the previous ROP example. We of course need to "encrypt" our values for PTR_MANGLE. Here's some example output:


With that said, here's the video!


NOTES FOR THE VIDEO: 
x86 Instruction Chart - http://sparksandflames.com/files/x86InstructionChart.html
Elf Header lowest 3 bits are 000
Elf layout - http://geezer.osdevbrasil.net/osd/exec/elf.txt
PMAP is your friend when trying to find the "Magic"
A look at PTR_MANGLE http://hmarco.org/bugs/CVE-2013-4788.html

Stay tuned for some iOS fun ;)

Monday, February 23, 2015

Exploiting memory corruption bugs in PHP (CVE-2014-8142 and CVE-2015-0231) Part 2: Remote Exploitation

In Part 1, we figured out how to locally exploit CVE-2014-8142 and CVE-2015-0231. In Part 2, we'll discuss remotely exploiting this vulnerability, and what we can steal from the application using the methods we discover. However, we will be focusing solely on CVE-2015-0231. Feel free to make the necessary changes as outlined in Part 1 to get CVE-2014-8142 working.

If you recall, Esser gave us code that leaked data at a non-attacker controlled address, which is shown below.

While this is useful, it's not as useful as the script we just wrote! We want to leak arbitrary memory remotely, not just random and basically useless memory. To do this, we need a way to:
  1. Write arbitrary data (without crashing PHP)
  2. Read arbitrary data (without crashing PHP)
As with anything in life, it's easier to tackle these problems one at a time! So, let's start with #1. We can write whatever we want, since we're sending our own object. However, we need a way to write useful information. Here's our last example:

We'll want to focus on the $fakezval variable. Is there someway we could write this zval remotely within a serialized object?? (Hint: It's a "feature" :D!)
As an aside, don't be stupid and lazy like I was. Read ALL of the code you're working on and around. I wasted a good 5-6 hours trying to figure this part out, until I face-punched myself a for missing this obvious portion of code.
Thankfully, there is, the 'S' character. The S character in a serialized string allows us to serialize and unserialize binary data. Let's play around with an S object, to get a better feel for how it works and how we can abuse it!

And let's go ahead and run our code, so we can see the awesomeness!


Hmm, this isn't exactly awesome. We're clearly doing something wrong here. To save everyone some face-palming, this error has to do with our S object, but feel free to count out the bytes by hand! And yes, I know PHP error messages suck.

In a normal serialized string, such as s:3:"123", the integer 3 is the number of characters that the string contains. However, in our above code, we have S:43:"\00\01\00\00AAAA\00\01\01\00\01\00\0B\BC\CC", which also has an integer (43), which is the length of our string, right?

Well, not exactly. We're not wanting a literal string here, we're wanting PHP to interpret this as binary data, as our string isn't actually 43 characters long, but 17. Let's try changing 43 to 17.


Excellent! But why did we use 17? Well, each \xx is considered to be 1 "character", which would leave us with 13. The "AAAA" characters are considered normal characters, so we add 4 to account for these. In short: Each \xx "triplet" is considered one character. Ok, now we can send this string, but how do we get information from the interpreter?

Before we leak arbitrary addresses, let's try to learn more about the server itself, as this will help us write a more reliable exploit (More on this in Part 3). To start, let's learn how to determine endianness of the server. To do so, we'll use a fake integer zval.

The idea stays the same:
  • Create an array of integers
  • Free the array we just created
  • Create our string from the previous example
  • Point to the reference of an integer that we just freed
Why use an integer zval instead of a string? Well, if you recall the zval struct, an integer will look like the following:
  • We set the value of the integer
    • 00 01 00 00
      • In Little Endian, this is 0x100
      • In Big Endian, this is 0x1000
  • We then fill the next 8 bytes with junk
    • 41 41 41 41 (Or: AAAA)
  • The next 8 bytes are the reference counter
    • 00 01 01 00
  • The final 8 bytes are 01 (Type Integer) and then we fill the rest with junk
    • 01 00 bc cc
 Putting this all together gives us our "S" value! But how does it tell us the endianness of the server? Well, in the server response, if it returns 0x100 (256), we'll know it's little endian! If it returns 65536, we'll know it's big endian! Let's see it in action:

And the application response:

Excellent! We now know the endianness of the server! Of course, we're trying to leak arbitrary data still, so let's figure that part out next. Since we can successfully leak data we supplied, is it possible to leak data at an arbitrary address?

Since the blog didn't stop here, it is assumed the answer is yes! However, instead of a fake integer zval, we'll use a fake string zval instead, which will look like the following:

  • We set the pointer to our string data
    • 00 80 04 08
  • We set the length of the string that we wish to extract (1024)
    • 00 04 00 00
  • We set the reference count to be not zero (0x101)
    • 00 01 01 00
  • Finally, we set the type to string, and fill the rest with junk
    • 06 00 0b bc
Here's what our new script looks like:

And when we run it, we get:


Excellent! We can now dump arbitrary memory, but we're required to know the address, which isn't practical. How do we extract addresses remotely? We could use the code from Part 1 to leak addresses, but the data leaked there isn't pointing to anything significant. Is there some other mechanism we can abuse to extract information?

Thankfully, there is! See the code below:


And when we run it:

Now, this is a rather big array, so let's break it down. The general idea is:
  • Create Integer Array #1
    • This will empty the memory cache
  • Create Integer Array #2
    • Fill in the variable table
  • Free Integer Array #2
    • Free spots in the variable table
  • Create an array of objects mixed with the S object
  • Free that Array of mixed objects
    • See comment below
  • Point to an integer value in Array #2 that was freed and overwritten
  • Response contains valuable data

We free the Object array so that the first 4 bytes in the array are overwritten by memory cache, since it was just freed (and therefore available for writing). In doing so, the string pointer (Which was previous 0x41414141) now points to the previously freed memory object. TL;DR - We get legit addresses!

But which addresses do we want? We're looking for the address that proceeds: "\x00\x00\x00\x00\x05\x00". This will be an object handler address, which is a struct in the data segment. Now, we can read the entire object handler table, and get information into the code segment of PHP(which is what we're interested in, since we want to pop a shell).

Here's the command to see the hex values returned by PHP
cphp newLeak.php | xxd -ps | sed 's/[[:xdigit:]]\{2\}/\\x&/g'
Let's go ahead and let it run, and when we grep for "\x00\x00\x00\x00\x05\x00", we find the following address:



If we load this into GDB, we also see that it is in fact a pointer into our object handler. Don't forget to set a breakpoint (I set one in var_unserializer.c:337) before running!


And what we see is:

Before we get too excited, let's make sure these are actually pointing to interesting things, let's just take the first entry: 0x0830a640. Here's what's stored at this address:


Awesome! We can now see everything that we need to! Thanks to these methods, we can now steal:
  • The entire PHP binary (and it's data)
  • SSL Certs (via mod_ssl)
  • PHP Symbols
  • Addresses of other modules (and their data as well)
Stay tuned for Part 3, where we pop a shell! This technique can also be used for CVE-2015-0273, as well as other UAF exploits in PHP.

Part 3 will take a while longer to get out, as I need to play around with PHP some more (and do some reading) before I can finish the exploit. But it will come!

    Thursday, February 5, 2015

    Exploiting memory corruption bugs in PHP (CVE-2014-8142 and CVE-2015-0231) Part 1: Local Exploitation

    Update: Part 2 here!

    Many people don't consider memory corruption bugs to be an issue for web-based applications. With XSS and SQL injection still being so wide spread, there is little room for concern for these types of bugs, as they're written off as "unexploitable" or plain ignored. However, these types of attack are much worse than SQLi or XSS, as
    • The attacker gets guaranteed system access
    • It can be difficult to identify the malicious traffic
    • Requires a patch from the maintainer/vendor, and with the hope that it was patched correctly. 
    This post will be the first post in a three part series, starting with how to exploit CVE-2014-8142(and CVE-2015-0231), followed by remotely leaking arbitrary information, and ending with getting control of the PHP Interpreter. Stefan Esser(@i0n1c) is the security researcher who originally found both CVEs, and was also the first one to talk about controlling the PHP Interpreter(dubbed ret2php) at SyScan 2010.

    This all starts back in 2004, when Esser found a Use After Free (#7) in unserialize(). This was part of the Hardened-PHP project, and no code was ever publicly released. In 2010, Esser found another use after free in SPLObjectStorage's unserialize(), which lead to a presentation at Syscan. Again, no code was released. Finally, CVE-2014-8142 was found and patched, but not patched correctly, which lead to CVE-2015-0231.

    Luckily, Stefan provided us a POC that seg faults the interpreter. The following code will produce a seg fault on vulnerable versions of PHP.

    Here's how it works: we update the value(s) associated with the "aaa" object by adding it again (with different values) within the same object. Next, the "ccc" object must point to the one of the values within the original "aaa" object.

    Now that we know how it works at a high level, let's try and find the culprit. We know to look in process_nested_data, and after a quick glance, a certain section stands out:

    Let's step through the script to identify what's actually happening here. We'll want a break on line 337 in var_unserializer.c (which is within the process_nested_data function).



    Let's go ahead and step through the code found here:

    Once we run the above script, continue past the first break point. Once in the second break point, run the following command
    printzv *(var_entries*)var_hash->first

    And we'll get an array of addresses, which are pointing to variables that have been parsed by unserialize(). We're interested in the fifth one (As our code uses R:5). Now that we know what address to watch, let's go ahead and step through this break point.


    Since we've called the suspect function, let's go ahead and re-check our address that we selected above:


    Success! However, let's make sure our address is still in the var_hash list, and then continue executing.



    And when we continue:


    Sweet! We can leak the data at the previous address. So, we can now leak the length of the supplied string. But that's not interesting. What about leaking arbitrary memory? Here's the code:

    And here's the output:





    What we're doing here is (hopefully) straightforward. We're creating our own ZVAL, which is the internal data struct that PHP uses. We define a few things for the pack() function to get our code execution. In order, they are:

    1. Type (unsigned int in our case)
    2. Address (The address we'd like to start the leak from)
    3. Length (How much memory we'd like to leak)
    4. # of References (0)
    5. Data Type (6, for String)

    Of course, these values would change if we weren't faking a string ZVAL. Our for loop does the actual overwriting of the freed memory, which leads us to the above output. I left the $i value larger than usually needed, to make sure it works "everywhere", but most of the machines I've tested on are fine with 2 instead of 5 iterations.

    Well, now that we can leak random data, how about upgrading to CVE-2015-0231? It's simple: Just replace "aaa" with "123". See the resulting output below:


    Excellent! Now we have a working local POC that can leak arbitrary memory, for both CVEs. Our next goal is to do this same thing, only remotely. Stay tuned for Part 2, where we do just that!