了解这种缓冲区溢出漏洞利用

逆向工程 C 开发 缓冲区溢出
2021-07-06 06:42:01

几天前,我从 opensecuritytraining.info 中获取了这段代码来测试缓冲区溢出漏洞:

#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;
}

注入shellcode之前的第一个测试是在不知道密码的情况下尝试执行go_shell函数,溢出main函数的返回地址并将其指向go_shell的位置。

据我了解堆栈划分如下:

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

所以如果我在 password_buffer 中存储 68 个字节加上 go_shell 的地址,它应该覆盖返回地址并执行所需的函数。

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

这里的问题是我需要用 76 字节的垃圾加上 4 字节的地址来填充缓冲区,以实际覆盖返回地址并将 %eip 指向 go_shell。我不明白的是那些额外的 8 个字节来自哪里?

这是注入 74 A (0x41) + if (!strcmp(password,secret)) 行断点中的地址之前的 GDB 输出:

EBP:
0xbffff4a8: 0x41414141  0x0804851c

AAAA + memory_address

并继续 go_shell 执行(断点在 void go_shell(){ ):

EIP 现在指向最后被覆盖的返回地址:

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

任何帮助理解这一点?

问候。

1个回答

如果您查看 authorize() 的反汇编,我相信您会发现编译器正在推送和恢复更多的寄存器,而不仅仅是 EBP 或对齐堆栈。我建议您在处理各种溢出时始终查看 disassemly。编译器和反编译器,如果你使用一个,隐藏了很多细节。反汇编从不说谎,让您无需借助动态分析即可进行预测。当您刚开始时,我强烈支持使用静态方法进行学习。

无论如何,是否有更多寄存器、堆栈金丝雀、堆栈对齐或其他东西,authorize() 的反汇编将揭示您问题的答案。

供您参考,这是使用 GCC 4.7.3 和 -O2 的 authorize() 函数的汇编。

推 ebx
sub esp, 58h
lea ebx, [esp+5Ch+密码]
mov [esp+5Ch+arg0], "Escriba la contrase"
调用_printf
mov [esp+5Ch+arg0], ebx
调用_gets
mov eax, 秘密
mov [esp+5Ch+arg0], ebx
mov [esp+5Ch+arg1], eax
调用_strcmp
测试 eax, eax
设置
添加 esp, 58h
movzx eax, al
流行音乐
返回

您会注意到它不使用 push 来移动参数,ebp 未用作堆栈帧并且编译器对齐堆栈,因为堆栈更改的总和为 0x60;返回值错位 4,将 ebx 再推 4,然后 sub esp,0x58 结果为 0x60。