Dance In Heap(二):一些堆利用的方法(上)
0×00 前面的话
在前面的文章里我们稍微有点啰嗦的讲解了堆中的一些细节,包括malloc、free的详细过程,以及一些检查保护机制,那在这篇文章里,我们就开始结合这些机制,以64位为例来看一看如何对堆进行攻击。本篇文章稍微讲解了一下UAF漏洞,然后根据源码分析了一下哪些地方使用了 unlink 宏,将unlink漏洞与其他的 chunk 释放操作做了一下区分并分析了unlink漏洞,最后讲解了另外一种利用 chunk 从 bin 中释放但不同于unlink的漏洞 unsortedbin attack。
本篇文章目录
0x01 Use After Free
0x02 Unlink
0x03 unsortedbin attack
0x04 小结
0×01 Use After Free
要学习堆中的漏洞,最基础不过的就是这个 UAF 了,UAF 漏洞原理很简单,就是在 free 掉 chunk 后,指向该 chunk 的指针还能正常使用
#include<stdio.h>
#include<stdlib.h>
struct shell {
void (*getshell)();
};
struct data {
int data;
};
void test_getshell(){
printf("I get the shell\n");
}
int main () {
struct shell *p;
p = (struct shell*)malloc(sizeof(struct shell));
p->getshell = test_getshell;
free(p);
struct data *q;
q = (struct data*)malloc(sizeof(struct data));
q->data = 1234;
p->getshell();
return 0;
}
编译运行一下
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x00000000000004d2 in ?? ()
我们可以看到 p 指向的函数地址被我们用1234给替换掉了,这就意味着我们能够利用这样一个漏洞控制 rip 寄存器,执行指令。
0×02 unlink
unlink漏洞想必大家都不陌生,在前面我们提到过,系统通过 unlink 宏将 free chunk 从链表中取出,但是我在这里强调一下,并非所有从链表中取出 chunk 的操作都利用到了 unlink 宏,要知道,我们在 malloc 时,也多次将 chunk 从 bin 中取出,我想结合部分源码(只截取了取出部分的代码)来强调一下 unlink 的使用状况。
在 malloc 操作中,我们多次进行了 bin 之间的转移,具体如下
从 fastbin 中取出 chunk
mfastbinptr* fb = &fastbin (av, idx);
victim = *fb;
*fb = victim->fd;
从 unsortedbin 中取出 chunk
victim = unsorted_chunks(av)->bk
bck = victim->bk;
unsorted_chunks(av)->bk = bck;
bck->fd = unsorted_chunks(av);
从 unsortedbin 向 smallbin 转移 chunk
if (in_smallbin_range(size)) {
victim_index = smallbin_index(size);
bck = bin_at(av, victim_index);
fwd = bck->fd;
从 unsortedbin 向 largebin 转移 chunk
mark_bin(av, victim_index);
victim->bk = bck;
victim->fd = fwd;
fwd->bk = victim;
bck->fd = victim;
从 smallbin 中取出 chunk
idx = smallbin_index(nb);
bin = bin_at(av,idx);
victim = last(bin);
bck = victim->bk;
bin->bk = bck;
bck->fd = bin;
从 largebin 中取出 chunk
unlink(victim, bck, fwd);
合并 fastbin 中 chunk 并加入到 unsortedbin 中(单向链表,bk指针需要获取)
prevsize = p->prev_size;
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));115
unlink(p, bck, fwd);
......
size += nextsize;
unlink(nextchunk, bck, fwd);
我们发现不仅仅在 free 时进行向前向后合并时使用 unlink 宏,在 malloc 时也会有零星的 unlink 使用,而且一定要注意,上面的除了6、7外,在进行取出 chunk 操作时,并没有进行 unlink,所以在对这一部分进行漏洞利用时,不需要考虑 unlink 的检查。
现在言归正传,来看看 unlink 漏洞。
#define unlink(P, BK, FD) {
FD = P->fd;
BK = P->bk;
if (__builtin_expect (FD->bk != P || BK->fd != P, 0))
malloc_printerr (check_action, "corrupted double-linked list", P);
else {
FD->bk = BK;
BK->fd = FD;
上面所示是 unlink 宏的主要实现,我们现在设想申请两个chunk,并利用第一个chunk溢出到第二个chunk的size位,将第一个chunk的 inuse 位改写为 free状态,这时候我们再free第二个chunk,此时系统通过第二个chunk的size检查第一个chunk,发现他是free状态,那么这时候就会使用unlink将第一块chunk从bin中释放出来并与第二块合并
a = malloc(0x20)
b = malloc(0x20) // b.size = 0x20 + chunk_header | inuse(0x01) == 0x31
a[0x20+4] = 0x30 // 覆盖 inuse 位
free(b) // 检查inuse位,发现 a 为 free,执行 unlink,合并两个 chunk
这时候其实a并没有在 bin 中,但是如果我们对 a 的前两个元素(即”fd”、”bk”)进行构造,那么就可以造成任意地址写入。
首先我们需要绕过检查,我们进行一个小小的计算
P->bk->fd == P // [P+0x18]+0x10 == P [P+0x18] == P-0x10
P->fd->bk == P // [P+0x10]+0x18 == P [P+0x10] == P-0x18
发现我们只需要在 b 的”fd”指针处放入 b-0×18,在”bk”指针处放入 b-0×10,即可绕过检查
执行完 unlink宏后,我们的b变成了这样
FD->bk = BK *P = P - 0x10(0x8)
BK->fd = FD *P = P - 0x18(0xc) // 这一步覆盖上一步
也就是说 现在 b 处存放着 b-0×18 的地址,这时候我们再向 b 写入数据也就是向 b-0×18 处写入数据了
--------|-------|
b | |----
--------|-------| |
····· | | |
--------|-------| |
b-0x18 | |<---
--------|-------|
这时候我们通过两次写入来造成任意地址写入,第一次写入0×18个字节,最后几位放入要写入的地址
--------|-------| |-------|
b |address|----> | 写入 |
--------|-------| |-------|
····· | |
--------|-------|
b-0x18 | AAAA |
--------|-------|
我们再次写入时,就是修改该地址处的数据了,比如修改got表什么的
0×03 unsortedbin attack
对 unsortedbin 的攻击主要利用从 unsortedbin 中取出 chunk 的操作来进行向任意位置写入一个不可控的指针,注意这里,从unsortedbin链表中取出chunk并不是使用unlink宏,所以不需要绕过 unlink 检查。首先我们需要创建两个 chunk 来避免 free 第一个 chunk 时将该 chunk 并入 top chunk,并且第一个 chunk 要足够大,确保其能进入到 unsortedbin中
p = malloc(0x400)
malloc(0x200)
然后将 p free掉,此时 p 进入到 unsortedbin中,然后改写其的 bk 指针,并malloc
free(p)
p[1] = 0xdeadbeef-0x10 // 任意地址 - 0x10
malloc(0x400)
我们看一下从 unsortedbin 中取出 chunk 的操作
victim = unsorted_chunks(av)->bk // victim为free掉的p
bck = victim->bk; // bck 为 任意地址 -0x10
unsorted_chunks(av)->bk = bck; // 调整链表
bck->fd = unsorted_chunks(av); // 任意地址 -0x10 + 0x10 = unsortedbin
这个漏洞自由度较小,不过可以用来修改一些阈值,例如更改libc中的max_fast,从而使得任意分配都使用fastbin来实现,为其他漏洞提供方案。
0×04 小结
在这次的文章中,我们简单的讲解了一下UAF漏洞,然后主要对从 bin 中释放 chunk 时的操作进行了漏洞利用,包括经典的 unlink,当然我们也结合源码分析了一下它的使用状况,以及非unlink式的chunk释放,unsortedbin attack。
Dance In Heap(二):一些堆利用的方法(上)的更多相关文章
- Binary Heap(二叉堆) - 堆排序
这篇的主题主要是Heapsort(堆排序),下一篇ADT数据结构随笔再谈谈 - 优先队列(堆). 首先,我们先来了解一点与堆相关的东西.堆可以实现优先队列(Priority Queue),看到队列,我 ...
- 第十章 优先级队列 (b2)完全二叉堆:插入与上滤
- 二叉堆(一)之 图文解析 和 C语言的实现
概要 本章介绍二叉堆,二叉堆就是通常我们所说的数据结构中"堆"中的一种.和以往一样,本文会先对二叉堆的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本 ...
- 二项堆(一)之 图文解析 和 C语言的实现
概要 本章介绍二项堆,它和之前所讲的堆(二叉堆.左倾堆.斜堆)一样,也是用于实现优先队列的.和以往一样,本文会先对二项堆的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本 ...
- 打印二叉堆(Java实现)
打印二叉堆:利用层级关系 我这里是先将堆排序,然后在sort里执行了打印堆的方法printAsTree() public class MaxHeap<T extends Comparable&l ...
- 二叉堆(二)之 C++的实现
概要 上一章介绍了堆和二叉堆的基本概念,并通过C语言实现了二叉堆.本章是二叉堆的C++实现. 目录1. 二叉堆的介绍2. 二叉堆的图文解析3. 二叉堆的C++实现(完整源码)4. 二叉堆的C++测试程 ...
- 二叉堆的实现(数组)——c++
二叉堆的介绍 二叉堆是完全二元树或者是近似完全二元树,按照数据的排列方式可以分为两种:最大堆和最小堆.最大堆:父结点的键值总是大于或等于任何一个子节点的键值:最小堆:父结点的键值总是小于或等于任何一个 ...
- 【BZOJ 1129】[POI2008]Per 二叉堆
这个东西读完题之后,就能知道我们要逐位计算贡献.推一下式子,会发现,这一位的贡献,是当前剩余的数字形成的序列的总数,乘上所剩数字中小于s上这一位的数的个数与所剩数字的总数的比.所以我们维护“当前剩余的 ...
- 数据结构 之 二叉堆(Heap)
注:本节主要讨论最大堆(最小堆同理). 一.堆的概念 堆,又称二叉堆.同二叉查找树一样,堆也有两个性质,即结构性和堆序性. 1.结构性质: 堆是一棵被完全填满的二叉树,有可能的 ...
随机推荐
- Linux 安装 tree命令
通过yum在线安装tree包 yum install tree -y
- jade和ejs两者的特点
jade特点 1超强的可读性 2灵活易用的缩进 3块扩展 4代码默认进过编码处理,以增强安全性 5编译及运行时的上下文错误报告 6命令行编译支持 7html5模式(使用 !!!5文档类型) 8可选的内 ...
- tornado中文教程
http://docs.pythontab.com/tornado/introduction-to-tornado/ch2.html#ch2-1 python的各种库的中文教程 http://docs ...
- 开发者工具删除元素Delete Element
开发者工具有个很好用的功能,通过删除元素,可以查看页面哪些元素比较特殊,同时也可以排除干扰.
- js多少时间之前
<?php $time = time()*1000; $end_time = strtotime("2018-01-01")*1000; $time_ago = $time ...
- Java 线程池的原理与实现学习(三)
一简介 线程的使用在java中占有极其重要的地位,jdk1.4及其之前的jdk版本,关于线程池的使用是极其简陋的.在jdk1.5之后这一情况有了很大的改观,Jdk1.5之后加入了java.util.c ...
- vim 翻页命令记录
vim命令: ctrl-f:往前翻一页(forward) ctrl-b:往后翻一页(backward) ctrl-d:往下翻半页(down) ctrl-u:往上翻半页(up)
- 模型表单ModleForm
官方文档网址 http://python.usyiyi.cn/documents/django_182/topics/forms/modelforms.html 模型表单的应用场景 如果你正在构建 ...
- 线程与threading模块
线程 进程内一个相对独立的.可调度的执行单元,是系统独立调度和分派CPU的基本单位.在单个进程中同时运行多个线程完成不同的工作,称为多线程. 同一进程内的多个线程是共享该进程的资源. 创建新的线程开销 ...
- SHUoj 字符串进制转换
字符串进制转换 发布时间: 2017年7月9日 18:17 最后更新: 2017年7月9日 21:17 时间限制: 1000ms 内存限制: 128M 描述 Claire Redfield ...