I\'m experimenting with buffer overflows and try to overwrite the return address of the stack with a certain input of fgets
This is the code:
void fo
You did not count with memory aligment. I changed the code a litte bit to make it easier to find the right spot.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int **x;
int z;
void foo()
{
fprintf(stderr, "You did it.\n");
}
void bar()
{
char buf[2];
//puts("Input:");
//fgets(buf, 70, stdin);
x = (int**) buf;
for(z=0;z<8;z++)
printf("%d X=%x\n", z, *(x+z));
*(x+3) = foo;
printf("Your input: %d %s\n", strlen(buf), buf);
}
int main(int argc, char **argv)
{
printf("Foo: %x\n", foo);
printf("Main: %x\n", main);
bar();
return 0;
}
With a smaller buffer, 2 in my example, I found the return address 24 bytes away (x+3, for 8 byte pointers; 64 bits, no debug, no optimization...) from the beginning of the buffer. This position can change depending on the buffer size, architecture, etc. In this example, I manage to change the return address of bar to foo. Anyway you will get a segmentation fault at foo return, as it was not properly set to return to main.
I added x and z as global vars to not change the stack size of bar. The code will display an array of pointer like values, starting at buf[0]. In my case, I found the address in main in the position 3. That's why the final code has *(x+3) = foo. As I said, this position can change depending on compilation options, machine etc. To find the correct position, find the address of main (printed before calling bar) on the address list.
It is important to note that I said address in main, not the address of main, bacause the return address was set to the line after the call to bar and not to the beginning of main. So, in my case, it was 0x4006af instead of 0x400668.
In your example, with 20 bytes buffer, as far as I know, it was aligned to 32 bytes (0x20).
If you want to do the same with fgets, you have to figure out how to type the address of foo, but if you are running a x86/x64 machine, remember to add it in little enddian. You can change the code to display the values byte per byte, so you can get them in the right order and type them using ALT+number. Remember that the numbers you type while holding ALT are decimal numbers. Some terminals won't be friendly handling 0x00.
My output looks like:
$ gcc test.c -o test
test.c: In function ‘bar’:
test.c:21: warning: assignment from incompatible pointer type
$ ./test
Foo: 400594
Main: 400668
0 X=9560e9f0
1 X=95821188
2 X=889350f0
3 X=4006af
4 X=889351d8
5 X=0
6 X=0
7 X=95a1ed1d
Your input: 5 ▒▒`▒9
You did it.
Segmentation fault
void bar() { char buf[20]; puts("Input:"); fgets(buf, 24, stdin); printf("Your input:.\n", strlen(buf)); }
... This works and causes a segmentation fault...
The compiler is probably replacing fgets
with a safer variant that includes a check on the destination buffer size. If the check fails, the the prgram unconditionally calls abort()
.
In this particular case, you should compile the program with -U_FORTIFY_SOURCE
or -D_FORTIFY_SOURCE=0
.