In my attempt to understand buffer overflows I have written the sample C/C++ program. The program asks you for a password and then displays two different messages depending on if you get the password correct or not. I opened the code up and disassembled it to find a point that I could jump to so I could override getting the password right or not. I wrote a quick python script that filled the buffer with "A"s and then the return address back to where I want the code to execute.
This method works perfectly in the GDB debugger, but when I run the same thing outside the debugger, I get a segmentation fault. Does anyone know why that would be?
Here is the code:
#include <stdio.h>
#include <string.h>
int checkpw();
int main(int argc, char* argv[])
{
int r = checkpw();
if(r==0)
{
printf("Congrats, you have been granted access to the program");
}
else
{
printf("That is the incorret password. Please exit immediately.");
}
return 0;
}
int checkpw()
{
char buffer[10];
gets(buffer);
return strcmp(buffer,"password");
}
I compiled the code with this line g++ -z execstack -g -fno-stack-protector main.cpp -o main
This produces these two disassembled code segments, the first for the main
function...
0x00000000004005bd <+0>: push %rbp
0x00000000004005be <+1>: mov %rsp,%rbp
0x00000000004005c1 <+4>: sub $0x20,%rsp
0x00000000004005c5 <+8>: mov %edi,-0x14(%rbp)
0x00000000004005c8 <+11>: mov %rsi,-0x20(%rbp)
0x00000000004005cc <+15>: callq 0x400601 <checkpw()>
0x00000000004005d1 <+20>: mov %eax,-0x4(%rbp)
0x00000000004005d4 <+23>: cmpl $0x0,-0x4(%rbp)
0x00000000004005d8 <+27>: jne 0x4005eb <main(int, char**)+46>
0x00000000004005da <+29>: mov $0x4006b8,%edi
0x00000000004005df <+34>: mov $0x0,%eax
0x00000000004005e4 <+39>: callq 0x400480 <printf@plt>
0x00000000004005e9 <+44>: jmp 0x4005fa <main(int, char**)+61>
0x00000000004005eb <+46>: mov $0x4006f0,%edi
0x00000000004005f0 <+51>: mov $0x0,%eax
0x00000000004005f5 <+56>: callq 0x400480 <printf@plt>
0x00000000004005fa <+61>: mov $0x0,%eax
0x00000000004005ff <+66>: leaveq
0x0000000000400600 <+67>: retq
And now the checkpw()
function...
0x0000000000400601 <+0>: push %rbp
0x0000000000400602 <+1>: mov %rsp,%rbp
0x0000000000400605 <+4>: sub $0x10,%rsp
0x0000000000400609 <+8>: lea -0x10(%rbp),%rax
0x000000000040060d <+12>: mov %rax,%rdi
0x0000000000400610 <+15>: callq 0x4004c0 <gets@plt>
0x0000000000400615 <+20>: lea -0x10(%rbp),%rax
0x0000000000400619 <+24>: mov $0x400728,%esi
0x000000000040061e <+29>: mov %rax,%rdi
0x0000000000400621 <+32>: callq 0x4004a0 <strcmp@plt>
0x0000000000400626 <+37>: leaveq
0x0000000000400627 <+38>: retq
Prior to running the debugger, I enter this command into the terminal python -c 'print "AAAAAAAAAAAAAAAA\x40\xdf\xff\xff\xff\x7f\x00\x00\xda\x05\x40\x00\x00\x00\x00\x00"' > /tmp/input1
which creates a file full of "A"s and more importantly write over the return address to the start of the code that prints that I have access to the program. \xda\x05\x40\x00\x00\x00\x00\x00
This works perfectly. I run gdb main
and then inside the debugger I type run < /tmp/input1
and "Congrats, you have been granted access to the program" is printed to the screen.
So my attempt to do it outside the debugger fails. I run this command from the terminal...
python -c 'print "AAAAAAAAAAAAAAAA\x40\xdf\xff\xff\xff\x7f\x00\x00\xda\x05\x40\x00\x00\x00\x00\x00"' | ./main
and I receive a segment fault.