c - 尝试将“/bin//sh”推送到堆栈时,32 位 shellcode 会导致分段错误
问题描述
我正在学习 opensecuritytraining 课程“exploits 1”。目前,我正在尝试使用缓冲区溢出在 32 位 linux 系统上利用带有一些 shellcode 的简单 c 程序。c程序:
void main(int argc, char **argv)
{
char buf[64];
strcpy(buf,argv[1]);
}
我使用命令“tcc -g -o basic_vuln basic_vuln.c”编译了程序。然后,我编写了以下 shellcode。
section .text
global _start
_start:
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
mov al, 11
push ebx
push 0x68732f2f
push 0x6e69622f
mov ebx, esp
int 0x80
我通过键入“nasm -f elf shell.asm; ld -o shell shell.o”来编译它。当我尝试自己执行“shell”时,它可以工作并且我得到一个shell。接下来,我用 objdump 反汇编程序,编写了一个打印操作码的 perl 文件,然后将所述 perl 文件的输出以及 shellcode 之前的 39 个 nop 指令重定向到一个名为“shellcode”的文件,因此有效负载现在是 64 字节长,填充缓冲区。然后,我在 gdb 中打开 c 程序,并在 nop sled 中间选择一个地址,这将是新的返回地址(0xbffff540)。我将地址附加到“shellcode”文件中,并附加了 4 个字节来覆盖保存的帧指针。shellcode 如下所示:
现在,当我尝试在 c 程序的 gdb 中运行这个 shellcode 时,它会在地址 0xbffff575 处导致分段错误,它指向我的 shellcode 中的某个点 0x62,它是“/bin/sh”中的字符“b” ”。什么可能导致这种情况?
这是我的堆栈帧,确认我选择的返回地址确实返回到 nop 雪橇的中间。
解决方案
返回到您的 shellcode后main
,ESP 可能会指向该缓冲区的正上方。EIP 指向它的开始;这就是回归的意义。
一些push
指令可能会修改缓冲区末尾的机器代码,从而导致带有 EIP 的 SIGILL 指向您刚刚推送的字节。
可能最简单的解决方法是add esp, -128
一直越过缓冲区。或者sub esp, -128
去更高的堆栈。(-128
是您可以使用的最大幅度的 8 位立即数,避免使用sub esp, 128
or在机器代码中引入零1024
。如果您想将堆栈移动得更远,您当然可以在寄存器中构造一个更大的值。)
我没有测试这个猜测,但是你可以在 GDB 中通过si
从末尾main
到一步一步的指令单步进入你的 shellcode 来确认它。
在每条指令后使用disas
以查看反汇编。或使用layout reg
. 有关更多 GDB 调试技巧,请参阅https://stackoverflow.com/tags/x86/info的底部。
给定的解决方案更复杂,因为它显然设置了一个实际的argv
数组,而不是仅仅为char **argv
and传递 NULL 指针char **envp
。(在 Linux 上,它与指向空 NULL 终止数组的有效指针相同:http: //man7.org/linux/man-pages/man2/execve.2.html#NOTES)。
但关键区别在于它使用 jmp/call/pop 来获取指向已在内存中的字符串的指针。 那只是一个堆栈插槽而不是三个。(返回地址之前的有效载荷的结尾是数据,而不是指令,但是如果它进行太多推送并覆盖字符串而不是仅仅存储0
终止符,它将以不同的方式失败。实际上在推送的返回地址之前call
向后跳转修改缓冲区,但如果它确实覆盖了接近末尾的任何内容,它仍然会中断。)
@Margaret 对此进行了更详细的研究,并发现只有第三次推动才能打破任何东西。这是有道理的:前 2 个可能会覆盖包含新返回地址和保存的 EBP 值的有效负载部分。恰好编译器将main
' 的缓冲区与该缓冲区相邻。
如果您实际上使用tcc
not gcc
,那可能并不奇怪。GCC 会将其对齐 16,并且可能出于某种原因在缓冲区和堆栈帧的顶部之间留下了间隙。
推荐阅读
- java - 当我尝试在 SQLite Android Studio 上进行插入时出错
- java - 关于带有测试自动化的 IntelliJ 项目结构的问题
- android - 语法错误有人可以检查
- javascript - 根据选择的选项更改的下拉框 REACT
- flutter - flutter popUntil 从最后三个路由调用 initState
- mobile - jquery-one-page-nav 在移动设备上不起作用
- python - 如何使用 Selenium 在文本字段中插入值?
- wxpython - sizer 中的 WxWidgets 面板似乎无法正常工作
- performance - OpenMP 加速损失
- javascript - 每次路由页面时如何使用 res.render 发送数据?