遇到一个挺有意思的shellcode题,在此记录一下
题目分析
题目来源 NewStarCTF2024 bad_asm
题目中有两个限制
- shellcode通过read读入,意味着如果出现
\x00
则后续的shellcode都不会被读入 - 判断shellcode中是否出现
\x0f\x05
和\x0f\x34
意味着禁用了syscall和sysenter
执行shellcode之前会把除了rdi,rsi以外的寄存器清零
解题思路
如果直接shellcraft不仅会出现\x00
而且会有syscall导致特判不通过
写出不含有\x00
的shellcode很容易,问题在于如何绕过syscall检查
之后想到了可见字符shellcode,可见字符不含有\x0f
可以通过特判,但可见字符的shellcode用到了大量的内存寻址,而寄存器都归0导致要逐步恢复寄存器才可以去寻址,太麻烦了因此这个方法也pass掉
这题灵感也是来源于可见字符shellcode,可见字符shellcode是利用了大量的异或运算,把输入进去的可见字符异或成不可见字符构造shellcode,因此只需要在最后syscall的时候输入进被异或的字节,绕过特判后在调用shellcode的时候再异或回来即可
由于rdi指向的是shellcode,因此根据rdi寻址找到syscall被异或的位置即可
1 | mov al,0x6 |
这里syscall我写成\x0f\x03
最后把0x3与0x6进行异或运算成为0x5,之后就可以正常执行了
用al也是为了避免出现\x00
本题还有个坑,就是rbp和rsp被清零,导致push和pop不能用,因此在执行shellcode之前想办法分配rbp和rsp
1 | mov rsp,rsi |
rsi指向的是一块可写的区域,把rsi的值赋给栈顶并开辟0xa0大小的栈空间,此处直接add rsp,0xa0
会出现’\x00’
后续就正常执行即可
exp
1 | from pwn import* |
题目中虽说禁用了int 80,但是if里没有禁用\xcd\x50
,不知是否可以retfq转化成32位执行shellcode,理论上没问题