0.前导知识
0-1.unsortedbin泄露libc地址
通过查阅相关资料可以知道,对于libc-2.23.so而言,当unsortedbin中只有一个freed chunk时,这个freed chunk的fd和bk指针都指向libc中的一个地址(一般是<main_arena+88>),这个偏移也可以算出是0x3c4b78。
0-2.hook函数
像malloc、free、realloc这类函数在执行前会先检查对应的hook函数,如果hook函数为空,则继续执行对应的函数,如果不为空,则跳转到hook中的值对应的地址位置执行。(例如hook函数中如果存的是one_gatget的地址则执行one_gatget)
0-3.realloc修改栈的原理
realloc在判断__realloc_hook前会先进行一系列push,这个操作可以改变栈结构,如果我们从realloc+offset位置开始执行,则可以改变push的次数从而调整栈布局。
1.例子
1-1.题目说明
- Ubuntu版本:16.04
- ELF:heap
- libc版本:2.23
1-2.详解
惯例查看保护:
试运行,发现是典型的菜单题。
在IDA中查看四个函数,如下:
不难看出4个函数的功能。
漏洞存在于del函数,del函数在释放内存后没有置空指针,因此造成了指针悬挂,存在UAF。在试验中也证明了在free chunk后依然能通过show函数或者edit函数访问到到对应的内存。因此提供了libc地址泄露的条件和fd指针修改的条件。
如图,先申请一个0x70大小的内存(实际会分配0x80的chunk),再释放掉它:
发现之后调用show函数依然能正常进行(因为0x80大小的堆块释放后归入fastbin,它的后面没有freed chunk,因此fd指针为空,所以show返回为空):
同样也能正常调用edit函数进行修改:
查看此时的bins情况,发现freed chunk的fd指针已经被修改了:
基于这种思路,我们可以利用这个来泄露libc地址和伪造chunk。
思路如下:1.先通过unsortedbin来泄露libc上的地址;
2.利用泄露的地址根据偏移算出libc基地址,进而算出其他函数的地址(比如__malloc_hook);
3.通过edit函数修改已被释放的fastbin中freed chunk的fd为fake_chunk的地址;
4.申请两个同样大小的堆块拿到fake_chunk,再计算偏移覆盖__malloc_hook为目标地址。
fake_chunk的寻找可以利用下面的方法(这里找的是__malloc_hook附近的):
计算出距离__malloc_hook的偏移:
(x86_64)libc-2.23.so中的one_gatget如下:
之后经过一系列操作,试了四个one_gatget后发现都打不通(
原因就是one_gatget的条件都没法达成。
通过查阅一系列资料后发现了一种方法仍然能使用one_gatget来get shell,那就是利用realloc来调整栈布局。
具体思路是:
1.前面一样,但是__malloc_hook里的地址由原来的one_gatget改为realloc+offset;
2.由于__realloc_hook和__malloc_hook相邻,因此我们能在之前修改__malloc_hook时一并修改__realloc_hook;
3.__realloc_hook修改为one_gatget的地址。
这样流程就是:
运行malloc前先检查__malloc_hook,发现不为空,跳转执行__malloc_hook里的地址处(realloc+offset),通过realloc里的一系列push调整栈布局为one_gatget能执行的条件,之后检查__realloc_hook,发现不为空,跳转执行one_gatget,最终获取shell。
至于此处offset的计算,我目前不知道有什么好的方法,只能从0开始试,后来发现为8时刚好可以。(用的是第二个one_gatget)
最终成功获取了shell:
1-3.exp
完整的exp如下:
1 | from pwn import * |