在缓冲区溢出 return 地址被不正确的地址覆盖,但它仍然有效

In buffer overflow return address is overwritten with incorrect address but it still works

我正在尝试使缓冲区溢出,这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int check_authentication(char *password) {

   char password_buffer[16];
   int auth_flag = 0;
   strcpy(password_buffer, password);
   if(strcmp(password_buffer, "brillig") == 0)
     auth_flag = 1;
   if(strcmp(password_buffer, "outgrabe") == 0)
     auth_flag = 1;

   return auth_flag; 

}




int main(int argc, char *argv[]) {

   if(argc < 2) {
      printf("Usage: %s <password>\n", argv[0]);
      exit(0);
    }
    if(check_authentication(argv[1])) {
      printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
      printf(" Access Granted.\n");
      printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
    } 

    else {
      printf("\nAccess Denied.\n");
    }
}

从命令行提供的密码将与 "brilling" 和 "outgrabe" 进行比较,如果用户输入匹配其中任何一个,将授予访问权限,否则将被拒绝。据我所知,如果提供的密码大于 16,return 地址将被覆盖,但是当我输入 "A" 17 时,它不会被覆盖。而不是 auth_flag 被覆盖并且是 65(十六进制中的 0x41,即 A)。我不明白为什么变量被覆盖而不是 return 地址。我正在用这个编译

gcc -fno-stack-protector -z execstack -g -o test test.c

希望大家帮帮忙。谢谢

一旦输入的 (password) 字符串包含超过 15(不是 16,需要终止 null)字符,使用 strcpy() 将调用 undefined behaviour.

  • 在此之前(除非发生这种情况),您的程序没有问题。
  • 在那之后,你无法预测任何事情

因此,在您的程序显示 UB 之后,您不能指望它以期望的方式运行。它可以做任何预期或意外的事情。是否覆盖auth_flag,无法确定。

也许值得一提的是,变量的内存分配不一定按任何特定顺序(出现)发生。您的编译器可以按照它认为合适的任何顺序自由分配内存。

正如 Sourav Ghosh 所说,您的程序调用了未定义的行为。

实际上,这意味着您需要深入研究生成的代码以查看堆栈的使用方式。

由于这在很大程度上取决于您的环境(机器、OS、编译器版本等),因此我们几乎无法为您调试它。 在 my 环境中,authenticated flag 存储在 ebp-12,而 buffer 存储在 ebp-28。 ebp-28 被传递给 strcmp,这意味着溢出将导致 authenticated 被覆盖。 更长的字符串最终会破坏 return 地址:“1234567890123456000000000000” 在我这里触发段错误。

推荐的起点可以是编译为汇编:

gcc -fno-stack-protector -z execstack -g -S test.c 

生成 test.s,这将向您展示堆栈的外观。 您还可以使用反汇编器查看二进制文件(想到 objdumpida pro),如果从源代码编译不是您负担得起的设施;-)。

编辑: 从你的 pastebin,这是我收集的:

显然存在某种形式的堆栈保护:

 movl    %gs:20, %eax
 [...]
 movl    -12(%ebp), %edx
 xorl    %gs:20, %edx
 je      .L5
 call    __stack_chk_fail

如果 -12(%ebp) 的位置不再是 %gs:20(例如,您的堆栈已损坏),则调用 __stack_chk_fail

附带说明一下,如果想要绕过身份验证的真正攻击者可以控制您的 "authenticated" 标志的值,他们甚至不会费心尝试删除 return 地址它的美丽。