调用execl启动shell后立即执行_exit的one-gadget是否可利用?
结论
该one-gadget并非完全无法利用。核心原理是:execl调用成功后会直接替换当前进程的整个地址空间,原程序中后续的_exit代码根本不会执行。你遇到的调用后直接退出的问题,本质是当前参数不满足条件导致execl执行失败返回,才会走到后续的退出逻辑。
可行利用方案
- 方案1:补齐
execl参数使其调用成功
该gadget对应的execl传参为execl("/bin/sh", "sh", "-c", [ESP+param_2], NULL),你看到的-c requires an argument报错就是因为[ESP+param_2]指向的内存不是合法的字符串参数。只要你在触发gadget前控制该内存地址的内容为合法命令(比如填入exec /bin/sh),就能让execl成功执行,直接获得稳定的交互式shell,完全不会触发后续的_exit。 - 方案2:拆分gadget作为通用代码片段使用
如果你无法控制[ESP+param_2]的取值,也可以不调用完整的gadget。该gadget内置了多个通过ESI寄存器偏移获取字符串地址的指令(可直接拿到/bin/sh、-c、sh的常量地址),你可以提取这些指令作为独立的ROP片段,自行构造execve或execl的调用链,完全避开末尾的_exit逻辑。 - 方案3:截断执行流绕过后续退出逻辑
如果你一定要调用完整gadget且能完全控制栈布局,也可以在execl返回(即调用失败)的场景下,通过栈溢出覆盖返回地址的方式,把CALL _Exit的目标替换为其他你需要执行的gadget地址,但该方案收益较低,优先推荐使用前两种方案。
补充说明
你在gdb测试中第二次执行直接得到$提示符,就是因为此时参数满足了execl的执行条件,没有走到后续退出逻辑的结果,无调试器的正常环境下只要满足参数要求也能复现该效果。
内容的提问来源于stack exchange,提问作者Lior Levin
相关产品推荐
相关产品推荐

