0%

House Of Atum-原理

House Of Atum

在 libc-2.31 之前,tcache 还没有 key 值保护,因此实现 Double free 是很简单的事情

甚至可以把同一个 chunk 连续释放8次,使其进入 fastbin(同时它自身还会存留在 tcache 中)

利用场景:

  • glibc < 2.31(没有 key 检查)
  • double free

glibc2.31下的Tcache检查

对于每一个 tcache 中的 chunk,增加了一个 key 指针,用于指向所属的 tcache 结构体:

1
2
3
4
5
typedef struct tcache_entry
{
struct tcache_entry *next; // 链表指针,对应chunk中的fd字段
struct tcache_perthread_struct *key; // 指向所属的tcache结构体,对应chunk中的bk字段
} tcache_entry;

当 chunk 被放入时会设置 key 指针:

1
2
3
4
5
6
7
8
9
10
11
12
static __always_inline void
tcache_put(mchunkptr chunk, size_t tc_idx)
{
tcache_entry *e = (tcache_entry *)chunk2mem(chunk);

e->key = tcache; // 设置所属的tcache

e->next = tcache->entries[tc_idx]; // 单链表头插法
tcache->entries[tc_idx] = e;

++(tcache->counts[tc_idx]); // 计数增加
}

ptmalloc 使用了一种更机智的方法,在不影响效率的前提下,完成了对double 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
size_t tc_idx = csize2tidx(size);
// 只要tcache不为空,并且这个chunk属于tcache管辖范围,那么这个chunk就有可能已经在tcache中了,所以需要double free检查
if (tcache != NULL && tc_idx < mp_.tcache_bins)
{
tcache_entry *e = (tcache_entry *)chunk2mem(p);
/*
如果是double free,那么put时key字段被设置了tcache,就会进入循环被检查出来
如果不是,那么key字段就是用户数据区域,可以视为随机的,只有1/(2^size_t)的可能行进入循环,然后循环发现并不是double free
*/
if (__glibc_unlikely(e->key == tcache)) // 剪枝
{
tcache_entry *tmp;
LIBC_PROBE(memory_tcache_double_free, 2, e, tc_idx);
for (tmp = tcache->entries[tc_idx]; tmp; tmp = tmp->next)
if (tmp == e)
malloc_printerr("free(): double free detected in tcache 2");
}

if (tcache->counts[tc_idx] < mp_.tcache_count) // 通过检查,放入tcahce中
{
tcache_put(p, tc_idx);
return;
}
}

简单来说:

  • 在 free chunk 被放入 tcache 时,程序会设置一个 key 值
  • 每次程序把 new free chunk 放入 tcache 前,都会检查一下它是否携带有 key 值
  • 注意:key 值原本的位置是用户数据区(可以认为是随机值),有极小的概率会触发检查报错

House Of Atum 利用姿势

House Of Atum 通常在那些限制节点数量的题目中使用(在可利用节点小于7个的情况下将某个 free chunk 放入 fastbin)

  • 以下案例展示把同一个 chunk 连续释放8次的情况:
1
2
3
4
for i in range(7):
dele(1,'n')

dele(1,'n')
  • 连续释放7次后:
1
2
3
4
5
6
7
tcachebins
0x50 [ 7]: 0x564499ecc2b0 ◂— 0x564499ecc2b0
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
  • 释放第8次后:
1
2
3
4
5
6
7
8
pwndbg> bin
tcachebins
0x50 [ 7]: 0x564499ecc2b0 ◂— 0x0
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x564499ecc2a0 ◂— 0x0
  • 现在该 chunk 同时存在于 tcache 和 fastbin 中
  • 构造好堆风水,覆盖伪造的 chunk->fd
  • 实现堆重叠并修改 chunk presize/size

版本对 House Of Atum 的影响

libc 版本必须小于 2.31