Episodes
Wednesday Dec 06, 2006
buffer overflow
Wednesday Dec 06, 2006
Wednesday Dec 06, 2006
A security problem in OS -- buffer overflow. In computer security and programming, a buffer overflow, or buffer overrun, is a programming error which may result in a memory access exception and program termination, or in the event of the user being malicious, a breach of system security. A buffer overflow is an anomalous condition where a process attempts to store data beyond the boundaries of a fixed length buffer. The result is that the extra data overwrites adjacent memory locations. The overwritten data may include other buffers, variables and program flow data. Buffer overflows may cause a process to crash or produce incorrect results. They can be triggered by inputs specifically designed to execute malicious code or to make the program operate in an unintended way. As such, buffer overflows cause many software vulnerabilities and form the basis of many exploits. Sufficient bounds checking by either the programmer or the compiler can prevent buffer overflows. An open source computer security project which provides information about security vulnerabilities and aids in penetration testing and IDS signature development is Metasploit Project. The contents hereafter is copied from www.governmentsecurity.org A buffer overflow problem is based in the memory where the program stores it's data. Why's that, you ask. Well because what buffer overflow do is overwrite expecific memory places where should be something you want, that will make the program do something that you want. Well some of you right now are thinking "WOW, I know how buffer overflow works", but you still don't know how to spot them. Let's follow a program and try to find and fix the buffer overflow ------ Partial code below-------- main(int argc, char **argv) { char *somevar; char *important; somevar = (char *)malloc(sizeof(char)*4); important = (char *)malloc(sizeof(char)*14); strcpy(important, "command"); /*This one is the important variable*/ stcrpy(somevar, argv[1]); ..... Code here .... } .... Other functions here .... ------- End Of Partial Code ------ So let's say that important variable stores some system command like, let's say "chmod o-r file", and since that file is owned by root the program is run under root user too, this means that if you can send commands to it, you can execute ANY system command. So you start thinking. How the hell can I put something that I want in the important variable. Well the way is to overflow the memory so we can reach it. But let's see variables memory addresses. To do that you need to re-written the code. Check the following code. --------- Partial Code ------------ main (int argc, char **argv) { char *somevar; char *important; somevar=(char *)malloc(sizeof(char)*4); important=(char *)malloc(sizeof(char)*14); printf("%p\n%p", somevar, important); exit(0); rest of code here } --------- End of Partial Code -------- Well we added 2 lines in the source code and left the rest unchanged. Let's see what does two lines do. The printf("%p\n%p", somevar, important); line will print the memory addresses for somevar and important variables. The exit(0); will just keep the rest of the program running after all you don't want it for nothing, your goal was to know where is the variables are stored. After running the program you would get an output like, you will probably not get the same memory addresses: 0x8049700 <----- This is the address of somevar 0x8049710 <----- This is the address of important As we can see, the important variable is next somevar, this will let us use our buffer overflow skills, since somevar is got from argv[1]. Now, we know that one follow the other, but let's check each memory address so we can have the precise notion of the data storage. To do this let's re-write the code again. -------- Partial code --------- main(int argc, char **argv) { char *somevar; char *important; char *temp; /* will need another variable */ somevar=(char *)malloc(sizeof(char)*4); important=(char *)malloc(sizeof(char)*14); strcpy(important, "command"); /*This one is the important variable*/ stcrpy(str, argv[1]); printf("%p\n%p\n", somevar, important); printf("Starting To Print memory address:\n"); temp = somevar; /* this will put temp at the first memory address we want */ while(temp < important + 14) { /* this loop will be broken when we get to the last memory address we want, last memory address of important variable */ printf("%p: %c (0x%x)\n", temp, *temp, *(unsigned int*)temp); temp++; } exit(0); rest of code here } ------ End Of partial Code ------ Now let's say that the argv[1] should be in normal use send. So you just type in your prompt: $ program_name send You'll get an output like: 0x8049700 0x8049710 Starting To Print memory address: 0x8049700: s (0x616c62) 0x8049701: e (0x616c) 0x8049702: n (0x61) <---- each of this lines represent a memory address 0x8049703: d (0x0) 0x8049704: (0x0) 0x8049705: (0x0) 0x8049706: (0x0) 0x8049707: (0x0) 0x8049708: (0x0) 0x8049709: (0x19000000) 0x804970a: (0x190000) 0x804970b: (0x1900) 0x804970c: (0x19) 0x804970d: (0x63000000) 0x804970e: (0x6f630000) 0x804970f: (0x6d6f6300) 0x8049710: c (0x6d6d6f63) 0x8049711: o (0x616d6d6f) 0x8049712: m (0x6e616d6d) 0x8049713: m (0x646e616d) 0x8049714: a (0x646e61) 0x8049715: n (0x646e) 0x8049716: d (0x64) 0x8049717: (0x0) 0x8049718: (0x0) 0x8049719: (0x0) 0x804971a: (0x0) 0x804971b: (0x0) 0x804971c: (0x0) 0x804971d: (0x0) $ Nice isn't it? You can now see that there exist 12 memory address empty between somevar and important. So let's say that you run the program with a command line like: $ program_name send------------newcommand You'll get an output like: 0x8049700 0x8049710 Starting To Print memory address: 0x8049700: s (0x646e6573) 0x8049701: e (0x2d646e65) 0x8049702: n (0x2d2d646e) 0x8049703: d (0x2d2d2d64) 0x8049704: - (0x2d2d2d2d) 0x8049705: - (0x2d2d2d2d) 0x8049706: - (0x2d2d2d2d) 0x8049707: - (0x2d2d2d2d) 0x8049708: - (0x2d2d2d2d) 0x8049709: - (0x2d2d2d2d) 0x804970a: - (0x2d2d2d2d) 0x804970b: - (0x2d2d2d2d) 0x804970c: - (0x2d2d2d2d) 0x804970d: - (0x6e2d2d2d) 0x804970e: - (0x656e2d2d) 0x804970f: - (0x77656e2d) 0x8049710: n (0x6377656e) <--- memory address where important variable starts 0x8049711: e (0x6f637765) 0x8049712: w (0x6d6f6377) 0x8049713: c (0x6d6d6f63) 0x8049714: o (0x616d6d6f) 0x8049715: m (0x6e616d6d) 0x8049716: m (0x646e616d) 0x8049717: a (0x646e61) 0x8049718: n (0x646e) 0x8049719: d (0x64) 0x804971a: (0x0) 0x804971b: (0x0) 0x804971c: (0x0) 0x804971d: (0x0) Hey cool, newcommand got over command. Now it does something you want, instead of something he was supposed to do. NOTE: Remember sometimes those spaces between somevar and important can have other variables instead of being empty, so check their values and send them to the same address, or the program can crash before getting to the variable that you modified. Now let's think a little. Why does this happen? As you can see in the source code somevar is declared before important, this will make, most of the times, that somevar will be first in memory. Now, let's check how each one is got. Somevar gets it's value from argv[1], and important gets it from strcpy() function, but the real problem is that important value is assign first so when you assign value to somevar that is before it important can be overwritten. This program could be patched against this buffer overflow switching those two lines, becoming : strcpy(somevar, argv[1]); strcpy(important, "command"); If this was the way that the program was done even if you give an argument that would get into the memory address of important, it will be overwritten by the true command, since after getting somevar, is assign the value command to important. This kind of buffer overflow, is a heap buffer overflow. Like you probably has seen they are really easy to do in theory but, in the real world, it's not really easy to do them, after all the example I gave was a really dumb program right? It's a real pain in the ass to find those important variables, and also to overflow that variable you need to be able to write to one that is in a lower memory address, most of times all this conditions