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 之间的转移,具体如下

  1. 从 fastbin 中取出 chunk

    mfastbinptr* fb = &fastbin (av, idx);
    victim = *fb;
    *fb = victim->fd;
  2. 从 unsortedbin 中取出 chunk

    victim = unsorted_chunks(av)->bk
    bck = victim->bk;
    unsorted_chunks(av)->bk = bck;
    bck->fd = unsorted_chunks(av);
  3. 从 unsortedbin 向 smallbin 转移 chunk

    if (in_smallbin_range(size)) {
    victim_index = smallbin_index(size);
    bck = bin_at(av, victim_index);
    fwd = bck->fd;
  4. 从 unsortedbin 向 largebin 转移 chunk

    mark_bin(av, victim_index);
    victim->bk = bck;
    victim->fd = fwd;
    fwd->bk = victim;
    bck->fd = victim;
  5. 从 smallbin 中取出 chunk

    idx = smallbin_index(nb);
    bin = bin_at(av,idx);
    victim = last(bin);
    bck = victim->bk;
    bin->bk = bck;
    bck->fd = bin;
  6. 从 largebin 中取出 chunk

    unlink(victim, bck, fwd);
  7. 合并 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(二):一些堆利用的方法(上)的更多相关文章

  1. Binary Heap(二叉堆) - 堆排序

    这篇的主题主要是Heapsort(堆排序),下一篇ADT数据结构随笔再谈谈 - 优先队列(堆). 首先,我们先来了解一点与堆相关的东西.堆可以实现优先队列(Priority Queue),看到队列,我 ...

  2. 第十章 优先级队列 (b2)完全二叉堆:插入与上滤

  3. 二叉堆(一)之 图文解析 和 C语言的实现

    概要 本章介绍二叉堆,二叉堆就是通常我们所说的数据结构中"堆"中的一种.和以往一样,本文会先对二叉堆的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本 ...

  4. 二项堆(一)之 图文解析 和 C语言的实现

    概要 本章介绍二项堆,它和之前所讲的堆(二叉堆.左倾堆.斜堆)一样,也是用于实现优先队列的.和以往一样,本文会先对二项堆的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本 ...

  5. 打印二叉堆(Java实现)

    打印二叉堆:利用层级关系 我这里是先将堆排序,然后在sort里执行了打印堆的方法printAsTree() public class MaxHeap<T extends Comparable&l ...

  6. 二叉堆(二)之 C++的实现

    概要 上一章介绍了堆和二叉堆的基本概念,并通过C语言实现了二叉堆.本章是二叉堆的C++实现. 目录1. 二叉堆的介绍2. 二叉堆的图文解析3. 二叉堆的C++实现(完整源码)4. 二叉堆的C++测试程 ...

  7. 二叉堆的实现(数组)——c++

    二叉堆的介绍 二叉堆是完全二元树或者是近似完全二元树,按照数据的排列方式可以分为两种:最大堆和最小堆.最大堆:父结点的键值总是大于或等于任何一个子节点的键值:最小堆:父结点的键值总是小于或等于任何一个 ...

  8. 【BZOJ 1129】[POI2008]Per 二叉堆

    这个东西读完题之后,就能知道我们要逐位计算贡献.推一下式子,会发现,这一位的贡献,是当前剩余的数字形成的序列的总数,乘上所剩数字中小于s上这一位的数的个数与所剩数字的总数的比.所以我们维护“当前剩余的 ...

  9. 数据结构 之 二叉堆(Heap)

    注:本节主要讨论最大堆(最小堆同理). 一.堆的概念     堆,又称二叉堆.同二叉查找树一样,堆也有两个性质,即结构性和堆序性.     1.结构性质:     堆是一棵被完全填满的二叉树,有可能的 ...

随机推荐

  1. css 透明度使用

    设置元素整体透明度: div{ opacity: 0.5; } 设置背景色透明度 div{ background: rgba(0,0,0,0.5); }

  2. 十分钟了解HTTP协议

    概念 HTTP(Hypertext Transfer Protocol,超文本传输协议)是TCP/IP协议的应用(封装). HTTP协议是单向通讯,无状态,主要应用于B/S模型的网络软件,客户端一(多 ...

  3. 大数据学习——scala数组

    package com import scala.collection.mutable.ArrayBuffer /** * Created by Administrator on 2019/4/8. ...

  4. 组合数学之Polya计数 TOJ1116 Let it Bead

    1116: Let it Bead  Time Limit(Common/Java):1000MS/10000MS     Memory Limit:65536KByteTotal Submit: 7 ...

  5. HUST——1103Party(拓扑排序+个人见解)

    1103: Party Time Limit: 2 Sec  Memory Limit: 64 MB Submit: 11  Solved: 7 Description N students were ...

  6. [luoguP2770] 航空路线问题(最小费用最大流)

    传送门 模型 求最长两条不相交路径,用最大费用最大流解决. 实现 为了限制经过次数,将每个点i拆成xi,yi. 1.从xi向yi连一条容量为1,费用为1的有向边(1<i<N), 2.从x1 ...

  7. [CODEVS1911] 孤岛营救问题(分层图最短路)

    传送门 吐槽:神tm网络流... 用持有的钥匙分层,状态压缩,用 2 进制表示持有的钥匙集合. dis[i][j][k] 表示持有的钥匙集合为 k,到达点 (i, j) 的最短路径. 分层图的最短路听 ...

  8. 严格次小生成树[BJWC2010] (树链剖分,倍增,最小生成树)

    题目链接 Solution 有几点关键,首先,可以证明次小生成树一定是由最小生成树改变一条边而转化来. 所以需要枚举所有非最小生成树的边\((u,v)\).并且找到 \(u\) 到 \(v\) 的边中 ...

  9. python ATM大作业之alex思路

    一 ATM alex想了一个思路,就是定义一个函数,这个函数可以实现所有的atm的功能:取款,转账,消费等等. 为了实现这个想法,alex构建了一个两级字典,厉害了.我发现,厉害的人都喜欢用字典.这里 ...

  10. 方格取数(hdu 1565)

    Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数 ...