Tcache Attack之dup/spirit/poisoning

tcache dup

和fastbin double free有点像,但是在2.27-ubuntu1.4中。加强了对double free的检查。

直接拿个how2heap中的吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//gcc -g z1r01.c -o z1r01
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

int main()
{
int *a = malloc(8);

free(a);
free(a);

void *b = malloc(8);
void *c = malloc(8);
printf("Next allocated buffers will be same: [ %p, %p ].\n", b, c);

assert((long)b == (long)c);
return 0;
}

这个程序创建了一个0x20大小的chunk,接着两次free,再创建两个0x20的chunk。

在第10行下个断点吧。

继续n吧,释放第一次a,直接进了tcachebin

继续n。指向了自己的data部分

malloc之后可以看见,里面存放的变成了1,b的地址就是0x55555555b260。

再一次malloc之后,可以看到已经变成了0。c的地址也是data部分。

b和c的地址就是data部分,指向的同一个地址

tcache house of spirit

和fastbin的很相似,但是fastbin的这种利用方法需要绕过很多检查,而tcache的2.27的这个版本的put的函数并没有什么检查,只需要size满足就可以了,看一下how2heap的吧。

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
//gcc -g z1r02.c -o z1r02
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

int main()
{
setbuf(stdout, NULL);

malloc(1);

unsigned long long *a;
unsigned long long fake_chunks[10];

printf("fake_chunk addr is %p\n", &fake_chunks[0]);

fake_chunks[1] = 0x40;

a = &fake_chunks[2];

free(a);

void *b = malloc(0x30);
printf("malloc(0x30): %p\n", b);

assert((long)b == (long)&fake_chunks[2]);
}

在第17行下个断点吧。看一下fake_chunk的地址

n吧。将[1]改为0x40可以看成size=0x40

继续执行下去。a = &fake_chunks[2];,将fake_chunk[2]的地址传给a,接着就free(a),可以看到tcache中存放着fake_chunk的data地址。将fake_chunk看成了一个正常的chunk

继续n吧。fake_chunk就会被看成正常的chunk给启用的。b的地址为fake_chunk的地址。

tcache poisoning

tcache poisoning主要是修改tcache中next的成员。2.27的tcache没有对next进行检查,将next的地址给替换掉即可完成利用。

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
//gcc -g z1r03.c -o z1r03
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>

int main()
{
setbuf(stdin, NULL);
setbuf(stdout, NULL);

size_t target;
printf("target is : %p.\n", (char *)&target);

intptr_t *a = malloc(128);
intptr_t *b = malloc(128);

free(a);
free(b);

b[0] = (intptr_t)&target;

malloc(128);
intptr_t *c = malloc(128);
printf("malloc_point is target: %p\n", c);

assert((long)&target == (long)c);
return 0;
}

定义了一个target变量,并输出target的地址,创建了两个大小为128chunk分别给a,b这两个指针,接着释放a和b,将b改为target的地址。malloc(128),再次申请128大小给c接着输出c的地址。

gdb一下吧,断点下在15行。

在28行下个断点,a和b的地址和大小都可以看见。

21行断一下,可以看到b–>a。

继续执行。b的fd已经变改成了目的地址,接下来申请同大小的时候,将会申请到b的地址。再申请时则会申请到目的地址。

接下来n一下。0x90只有1个了,剩下了目的地址。

继续n。目的地址被申请