我试图让缓冲区溢出,这是我的代码:
#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");
}
}
命令行提供的密码将与&#34; brilling&#34;进行比较。和&#34; outgrabe&#34;如果用户输入与其中任何一个匹配,则将授予访问权限,否则将被拒绝。据我所知,如果提供的密码将大于16,将覆盖返回地址,但是当我输入&#34; A&#34; 17它没有被覆盖。而不是auth_flag被覆盖并且是65(十六进制中的0x41,即A)。我无法弄清楚为什么变量被覆盖而不是返回地址。我正在用这个
进行编译gcc -fno-stack-protector -z execstack -g -o test test.c
希望你们能提供帮助。感谢。
答案 0 :(得分:3)
正如Sourav Ghosh所说,你的程序会调用未定义的行为。
实际上,这意味着您需要深入了解生成的代码以查看堆栈的使用方式。
由于这在很大程度上依赖于您的环境(机器,操作系统,编译器版本等),因此我们无法为您调试它。
在 my 环境中,authenticated
标志存储在ebp-12中,而缓冲区存储在ebp-28中。 ebp-28传递给strcmp,这意味着溢出将导致authenticated
被覆盖。
较长的字符串最终将粉碎返回地址:&#34; 1234567890123456000000000000&#34;在我的位置触发了一个段错误。
建议的起点可能是汇编为汇编:
gcc -fno-stack-protector -z execstack -g -S test.c
生成test.s,它将显示堆栈的外观。
您还可以使用反汇编程序查看二进制文件(objdump
和ida 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
(例如,您的堆栈已损坏)。
作为旁注,如果想要绕过身份验证的真正的攻击者可以控制您的身份验证&#34;旗帜,他们甚至懒得尝试删除返回地址以获得它的美丽。
答案 1 :(得分:0)
一旦输入(password
)字符串包含超过15
(不是16
,需要终止null)charcater,使用strcpy()
将调用undefined behaviour。
因此,在您的程序显示UB之后,您不能指望它以所需的方式运行。它可以做任何事情,每一个预期或意外。是否覆盖 auth_flag
无法确定。
也许,值得一提的是,变量的内存分配不一定以任何特定的顺序(外观)进行。您的编译器可以按照它认为合适的任何顺序自由分配内存。