Tcache Attack中的house of spirit(基础)

附件下载:

链接:https://pan.baidu.com/s/1Obl1tx62mb6jnsuZ9D3mBg
提取码:udtl
–来自百度网盘超级会员V3的分享

前言

tcache中的house of spirit和fastbi中的house of spirit相似。

回顾一下fastbin_attack中的house of spirit:

House of Spirit的利用关键在于能够覆盖一个堆指针变量(指向malloc_data),让其指向可以控制的区域。

来看一下它的利用思路:

  1. 首先需要伪造一个堆块,伪造堆块时需要注意绕过之后的五个检测。
  2. 覆盖堆指针指向上一步伪造的堆块
  3. 释放堆块,将伪造的堆块放入fastbin的单链表里面(需要绕过检测)
  4. 申请堆块,将刚才释放的堆块申请出来,最终可以使得向目标区域中写入数据,以达到控制内存的目的。

下面是五个检测,需要绕过:

  1. fake chunk的ISMMAP位不能为1,因为free时,如果是mmap的chunk,会单独处理。
  2. fake chunk地址需要对齐,MALLOC_ALIGN_MASK
  3. fake chunk的size大小需要满足对应的fastbin的需求,同时也得对齐。
  4. fake chunk的next chunk的大小不能小于2*SIZE_SZ,同时也不能大于av->system_mem。
  5. fake chunk对应的fastbin链表头部不能是该fake chunk,即不能构成double free的情况。

tcache_house_of_spirit

由于tcache_put函数几乎没有检查,所以tcache中的house_of_spirit的检测机制相较于fastbin中的要少。因此构造fake tcache chunk内存时需要绕过的检查更加宽松,具体如下:

  • fake chunk的size在tcache的范围中(64位程序中是32字节到410字节),且其ISMMAP位不为1
  • fake chunk的地址对齐
  • 无需构造next chunk的size(无需构造fake_chunk)
  • 无需考虑double free的情况,因为free堆块到tcache中的时候不会进行这些检查

Demo

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//gcc -g -fno-stack-protector -z execstack -no-pie -z norelro test.c -o test
#include <stdio.h>
#include <stdlib.h>

int main()
{
malloc(1);
unsigned long long *a;
unsigned long long fake_chunks[10];
fprintf(stderr, "fake_chunks[1] 在 %p\n", &fake_chunks[1]);
fprintf(stderr, "fake_chunks[1] 改成 0x40 \n");
fake_chunks[1] = 0x40;
fprintf(stderr, "把 fake_chunks[2] 的地址赋给 a, %p.\n", &fake_chunks[2]);
a = &fake_chunks[2];
fprintf(stderr, "free 掉 a\n");
free(a);
fprintf(stderr, "再去 malloc(0x30),在可以看到申请来的结果在: %p\n", malloc(0x30));
fprintf(stderr, "Finish\n");
return 0;
}

image-20230815103917720

pwngdb调试

首先在代码第8行下断点,执行程序,观察内存情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
pwndbg> x/120gx 0x601000
0x601000: 0x0000000000000000 0x0000000000000251 #tcache_perthread_struct
......(省略内容为空)
0x601250: 0x0000000000000000 0x0000000000000021 #chunk1
0x601260: 0x0000000000000000 0x0000000000000000
0x601270: 0x0000000000000000 0x0000000000020d91 #top_chunk
......(省略内容为空)
0x6013b0: 0x0000000000000000 0x0000000000000000


pwndbg> info local
a = 0x0
fake_chunks = {9, 140737351874144, 140737488346824, 1, 1, 4196141, 140737351932320, 0, 4196064, 4195568}

pwndbg> x/16gx &fake_chunks
0x7fffffffde50: 0x0000000000000009 0x00007ffff7dd7660 #fake_chunk
0x7fffffffde60: 0x00007fffffffdec8 0x0000000000000001
0x7fffffffde70: 0x0000000000000001 0x000000000040072d
0x7fffffffde80: 0x00007ffff7de59a0 0x0000000000000000
0x7fffffffde90: 0x00000000004006e0 0x00000000004004f0
0x7fffffffdea0: 0x00007fffffffdf90 0x0000000000000000
0x7fffffffdeb0: 0x00000000004006e0 0x00007ffff7a05b97
0x7fffffffdec0: 0x0000002000000000 0x00007fffffffdf98

然后在第13行下断点,继续调试:

1
2
3
4
5
6
7
8
9
10
pwndbg> x/16gx &fake_chunks
0x7fffffffde50: 0x0000000000000009 0x0000000000000040
#修改这里
0x7fffffffde60: 0x00007fffffffdec8 0x0000000000000001
0x7fffffffde70: 0x0000000000000001 0x000000000040072d
0x7fffffffde80: 0x00007ffff7de59a0 0x0000000000000000
0x7fffffffde90: 0x00000000004006e0 0x00000000004004f0
0x7fffffffdea0: 0x00007fffffffdf90 0x00007fffffffde60
0x7fffffffdeb0: 0x00000000004006e0 0x00007ffff7a05b97
0x7fffffffdec0: 0x0000002000000000 0x00007fffffffdf98

继续执行,把fake_chunk_data的地址赋值到a指针,对代码第15行下断,继续调试:

1
2
3
4
5
6
7
8
9
10
11
12
pwndbg> x/16gx &fake_chunks
0x7fffffffde50: 0x0000000000000009 0x0000000000000040
0x7fffffffde60: 0x00007fffffffdec8 0x0000000000000001
0x7fffffffde70: 0x0000000000000001 0x000000000040072d
0x7fffffffde80: 0x00007ffff7de59a0 0x0000000000000000
0x7fffffffde90: 0x00000000004006e0 0x00000000004004f0
0x7fffffffdea0: 0x00007fffffffdf90 0x00007fffffffde60
0x7fffffffdeb0: 0x00000000004006e0 0x00007ffff7a05b97
0x7fffffffdec0: 0x0000002000000000 0x00007fffffffdf98
pwndbg> info local
a = 0x7fffffffde60
fake_chunks = {9, 64, 140737488346824, 1, 1, 4196141, 140737351932320, 0, 4196064, 4195568}

可以观察到,a此时指向fake_chunks_data。

接下来对fake_chunks进行free,下断之后执行观察:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
pwndbg> 
tcachebins
0x40 [ 1]: 0x7fffffffde60 ◂— 0x0
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty

pwndbg> x/120gx 0x601000
0x601000: 0x0000000000000000 0x0000000000000251 #tcache_perthread_struct
0x601010: 0x0000000000010000 0x0000000000000000
#tcachebins中的个数
......(省略为空)
0x601060: 0x00007fffffffde60 0x0000000000000000
#指向fake_chunk_data
......(省略为空)
0x601250: 0x0000000000000000 0x0000000000000021 #chunk1
0x601260: 0x0000000000000000 0x0000000000000000
0x601270: 0x0000000000000000 0x0000000000020d91 #top_chunk

pwndbg> x/16gx &fake_chunks
0x7fffffffde50: 0x0000000000000009 0x0000000000000040
0x7fffffffde60: 0x0000000000000000 0x0000000000000001
0x7fffffffde70: 0x0000000000000001 0x000000000040072d
0x7fffffffde80: 0x00007ffff7de59a0 0x0000000000000000
0x7fffffffde90: 0x00000000004006e0 0x00000000004004f0
0x7fffffffdea0: 0x00007fffffffdf90 0x00007fffffffde60
0x7fffffffdeb0: 0x00000000004006e0 0x00007ffff7a05b97
0x7fffffffdec0: 0x0000002000000000 0x00007fffffffdf98

代码第18行下断点,当我们执行malloc之后,就会控制栈上的地址,继续调试:

image-20230815111001995

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
pwndbg> x/120gx 0x601000
0x601000: 0x0000000000000000 0x0000000000000251 #tcache_perthread_struct
......(省略内容为空)
0x601250: 0x0000000000000000 0x0000000000000021 #chunk1
0x601260: 0x0000000000000000 0x0000000000000000
0x601270: 0x0000000000000000 0x0000000000020d91 #top_chunk

pwndbg> info local
a = 0x7fffffffde60
fake_chunks = {9, 64, 0, 1, 1, 4196141, 140737351932320, 0, 4196064, 4195568}

pwndbg> x/16gx &fake_chunks
0x7fffffffde50: 0x0000000000000009 0x0000000000000040 #我们现在可以控制这里
0x7fffffffde60: 0x0000000000000000 0x0000000000000001
0x7fffffffde70: 0x0000000000000001 0x000000000040072d
0x7fffffffde80: 0x00007ffff7de59a0 0x0000000000000000
0x7fffffffde90: 0x00000000004006e0 0x00000000004004f0
0x7fffffffdea0: 0x00007fffffffdf90 0x00007fffffffde60
0x7fffffffdeb0: 0x00000000004006e0 0x00007ffff7a05b97
0x7fffffffdec0: 0x0000002000000000 0x00007fffffffdf98

我们现在可以控制栈上的内存地址。

image-20230815111422841