1.first_fit

Source code demonstrates the use-after-free

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 int main()
 6 {
 7     fprintf(stderr, "This file doesn't demonstrate an attack, but shows the nature of glibc's allocator.\n");
 8     fprintf(stderr, "glibc uses a first-fit algorithm to select a free chunk.\n");
 9     fprintf(stderr, "If a chunk is free and large enough, malloc will select this chunk.\n");
10     fprintf(stderr, "This can be exploited in a use-after-free situation.\n");
11 
12     fprintf(stderr, "Allocating 2 buffers. They can be large, don't have to be fastbin.\n");
13     char* a = malloc(512);
14     char* b = malloc(256);
15     char* c;
16 
17     fprintf(stderr, "1st malloc(512): %p\n", a);
18     fprintf(stderr, "2nd malloc(256): %p\n", b);
19     fprintf(stderr, "we could continue mallocing here...\n");
20     fprintf(stderr, "now let's put a string at a that we can read later \"this is A!\"\n");
21     strcpy(a, "this is A!");
22     fprintf(stderr, "first allocation %p points to %s\n", a, a);
23 
24     fprintf(stderr, "Freeing the first one...\n");
25     free(a);
26 
27     fprintf(stderr, "We don't need to free anything again. As long as we allocate less than 512, it will end up at %p\n", a);
28 
29     fprintf(stderr, "So, let's allocate 500 bytes\n");
30     c = malloc(500);
31     fprintf(stderr, "3rd malloc(500): %p\n", c);
32     fprintf(stderr, "And put a different string here, \"this is C!\"\n");
33     strcpy(c, "this is C!");
34     fprintf(stderr, "3rd allocation %p points to %s\n", c, c);
35     fprintf(stderr, "first allocation %p points to %s\n", a, a);
36     fprintf(stderr, "If we reuse the first allocation, it now holds the data from the third allocation.\n");
37 }

operation result

checksec

 

A first application of a 512-byte memory

Then apply a piece of 256 bytes of memory b

At this time, the distribution of the heap

0x211 prev_inuse is shown here because the bit size field 512 = 0x200 0x10 byte fixed header plus stack plus the head portion is 1 i.e. 0x200 + 0x10 + 1 = 0x211

Similarly 0x111 = 0x100 + 0x10 + 1 = 0x111

 

32 the stack structure 64 are all 8 bytes in each field is 4 bytes

 1 struct malloc_chunk {    
 2 
 3   INTERNAL_SIZE_T      prev_size;  /* Size of previous chunk (if free).  */  
 4   INTERNAL_SIZE_T      size;       /* Size in bytes, including overhead. */  
 5 
 6   struct malloc_chunk* fd;         /* double links -- used only if free. */  
 7   struct malloc_chunk* bk;                                
 8 
 9   /* Only used for large blocks: pointer to next larger size.  */
10   struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */  
11   struct malloc_chunk* bk_nextsize;
12 };

 

这里要注意两块都大于0x70字节,即大于fastbin的最大size,否则释放后进入fastbin链表(linux中的快表)

这里释放后进入unsorted bin链表

在第一块512字节的内存中存放字符串“this is A”

存放字符串之前a内存

prev_size=0  size=0x211   数据部分为空

存放字符串之后a内存

然后释放内存a,进入unsorted bin链表

之后申请500字节的内存c

由于linux堆的分配机制,先到unsorted bin链表中寻找,从释放的a内存512字节中切割出500字节给c

所以c内存和a内存指向的地址相同

然后向c内存中写入字符串“this is C”

查看此时堆内存

可以看到和a内存相比,0x603018处字节由0x41(A的ascii码)变成了0x43(C的ascii码)

要注意的是,linux堆管理机制规定堆块的大小必须是 2 * SIZE_SZ 的整数倍。如果申请的内存大小不是 2 * SIZE_SZ 的整数倍,会被转换满足大小的最小的 2 * SIZE_SZ 的倍数。32 位系统中,SIZE_SZ 是 4;64 位系统中,SIZE_SZ 是 8

所以这里500+16=516字节被转换成了0x210=528字节  即a内存和c内存重合

此时a和c指向同一块内存,如果此后再显示a的内容,即输出了c的内容

 这种情况即造成了use-after-free

通过这个例子,可以很清楚的了解linux下堆的分配机制和堆的结构。

Guess you like

Origin www.cnblogs.com/pfcode/p/10989812.html