9

some days ago I took this piece of code from opensecuritytraining.info to test a buffer overflow exploitation:

#include <stdio.h>

char *secret = "pepito";

void go_shell(){
    char *shell = "/bin/sh";
    char *cmd[] = { "/bin/sh", 0 };
    printf("¿Quieres jugar a un juego?...\n");
    setreuid(0);
    execve(shell,cmd,0);
}

int authorize(){
    char password[64];
    printf("Escriba la contraseña: ");
    gets(password);
    if (!strcmp(password,secret))
        return 1;
    else
        return 0;
}

int main(){
    if (authorize()){
        printf("Acceso permitido\n");
        go_shell();
    } else{
        printf("Acceso denegado\n");
    }
    return 0;
}

The first test before injecting a shellcode was trying to execute the go_shell function without knowing the password, overflowing the return address of main function and pointing it to the location of go_shell.

As far as I understand the stack is divided as below:

[STACK] {Return_address}{EBP}{password_buffer(64)}...

So If I store in password_buffer 68 bytes plus the address of go_shell it should overwrite the return address and execute the desired function.

[STACK] {4bytes (Location of go_shell)}{EBP(4 Bytes of junk)}{password_buffer(64)(64 bytes of junk)}...

The problem here is that I need to fill the buffer with 76 bytes of junk plus 4 bytes of the address to actually override the return address and point %eip to go_shell. What I don't understand is where do those additional 8 bytes come from?

This is the GDB output before injecting 74 A (0x41) + the address in a breakpont at line if (!strcmp(password,secret)):

EBP:
0xbffff4a8: 0x41414141  0x0804851c

AAAA + memory_address

And continuing to go_shell execution (Breakpoint at void go_shell(){ ):

EIP now points to the last return address overwrited:

(gdb) x/2x $eip
0x804851c <go_shell>:   0x83e58955  0x45c728ec

Any help understanding this?

Regards.

0

1 Answer 1

13

If you look at the disassembly of authorize() I'm sure you'll find that the compiler is pushing and restoring more registers than just EBP or aligning the stack. I would recommend that you always look at the disassemly when dealing with overflows of various kinds. The compiler and decompiler, if you use one, hides a lot of details. The disassembly never lies and allows you to make a prediction without resorting to dynamic analysis. I'm a strong proponent of learning with static methods when you're just starting out.

Anyways, whether there's more registers, a stack canary, stack alignment or something else, the disassembly of authorize() will reveal the answer to your question.

For your reference this is the dissembly of the authorize() function using GCC 4.7.3 with -O2.

push    ebx
sub     esp, 58h
lea     ebx, [esp+5Ch+password]
mov     [esp+5Ch+arg0], "Escriba la contrase"
call    _printf
mov     [esp+5Ch+arg0], ebx
call    _gets
mov     eax, secret
mov     [esp+5Ch+arg0], ebx
mov     [esp+5Ch+arg1], eax
call    _strcmp
test    eax, eax
setz    al
add     esp, 58h
movzx   eax, al
pop     ebx
retn

You'll notice that it doesn't use push to move arguments, ebp is unused as a stack frame and the compiler aligns the stack since sum of stack changes is 0x60; return value misaligns by 4, push ebx by 4 more, then sub esp, 0x58 results in 0x60.

2
  • Awesome explanation, thank you very much.
    – Nucklear
    Commented Oct 13, 2013 at 10:49
  • Since your response I was trying to figure out what happens in the memory but I don't get it. This is a preview of the memory before and after injecting the payload pastebin.com/raw.php?i=ajCqxvGJ Could you develop your last explanation? Regards.
    – Nucklear
    Commented Oct 14, 2013 at 14:22

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.