-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlevel43.ts
More file actions
69 lines (61 loc) · 9.63 KB
/
level43.ts
File metadata and controls
69 lines (61 loc) · 9.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import { Level } from './types';
export const level43: Level = {
id: 43,
title: "Full RELRO: The Immutable Law",
description: "RELRO Bypass: Exploiting malloc hooks when GOT is read-only. RELRO (Relocation Read-Only) makes Global Offset Table immutable after initialization, preventing traditional GOT overwrites. Full RELRO: GOT mapped read-only at program start (mprotect after relocation). Partial RELRO: GOT.PLT writable for lazy binding. Bypass: Target glibc malloc hooks (__malloc_hook, __free_hook, __realloc_hook) which remain writable for debugging. Technique: Heap overflow/UAF to corrupt hook pointers → Next malloc/free/realloc call → Jumps to attacker-controlled address → Code execution. Real scenario: Heap overflow in chunk metadata → Overwrite __malloc_hook with one_gadget/system → Trigger malloc → Shell. This level: Demonstrate hook overwrite by setting MALLOC_HOOK pointer to shellcode address, FREE_HOOK to backup, HOOK_VALUE to target function, trigger via HEAP_ALLOC. Use SystemMonitor > Heap View + Memory Scanner.",
requiredSkill: "Hook Overwriting",
objective: (s) => {
const mallocHookValid = (s.baseAddress || '').toLowerCase().replace('0x', '').padStart(8, '0') === 'b7e5c768';
const freeHookValid = (s.libcBase || '').toLowerCase().replace('0x', '').padStart(8, '0') === 'b7e5c770';
const hookValueValid = (s.eip || '').toLowerCase().replace('0x', '').padStart(8, '0') === 'deadbeef';
const relroLevelValid = (s.payload || '').toLowerCase().includes('full');
const hookCountValid = s.sortValue1 >= 2;
const overwriteSizeValid = s.sortValue2 === 8;
const heapValid = s.heap.some((h: any) => h.id === 'hooked_malloc' && h.active === true);
const hookSuccess = s.isAdmin === true;
return mallocHookValid && freeHookValid && hookValueValid && relroLevelValid && hookCountValid && overwriteSizeValid && heapValid && hookSuccess;
},
hint: "Seven-stage RELRO bypass via malloc hook overwrite. Stage 1: Set MALLOC_HOOK address (baseAddress, __malloc_hook location, value: 0xB7E5C768 typical glibc). Stage 2: Set FREE_HOOK address (libcBase, __free_hook location, value: 0xB7E5C770). Stage 3: Set HOOK_VALUE (eip, pointer to write to hook, value: 0xDEADBEEF shellcode/one_gadget addr). Stage 4: Set RELRO_LEVEL (payload string, must contain 'FULL' to confirm protection active). Stage 5: Set HOOK_COUNT (sortValue1 int, number of hooks to overwrite, value: 2+ for malloc+free). Stage 6: Set OVERWRITE_SIZE (sortValue2 int, bytes to overwrite, value: 8 for 64-bit pointer). Stage 7: Allocate heap object 'hooked_malloc' (SystemMonitor > Heap View, active=true, triggers hook) → HOOK_SUCCESS=true. Use Memory Scanner HEX tab: MALLOC_HOOK, FREE_HOOK, HOOK_VALUE. Real exploit: Heap overflow → Overwrite __malloc_hook → malloc() called → Jumps to one_gadget → execve('/bin/sh') → Shell. One-gadget: Single ROP gadget executing execve (found via one_gadget tool on libc.so).",
tutorPersona: "argp & huku/The Art of Exploitation (Modern Glibc Heap): When the front door is locked, find the service entrance. History: 2001 - RELRO introduced in GNU toolchain (binutils, ld). Motivation: Prevent GOT overwrites (common exploitation technique in 1990s-2000s). Partial RELRO: .got.plt writable (lazy binding), .got read-only. Full RELRO: Entire GOT read-only after relocation (gcc -Wl,-z,relro,-z,now). 2003 - Format string + GOT overwrite attacks widespread. Overwrit got[strcpy] → system() → RCE. RELRO deployment begins in security-critical software. 2004 - Fedora Core enables RELRO by default. RHEL follows. Debian/Ubuntu adopt gradually. 2006 - 'Malloc Des-Maleficarum' (Phantasmal Phantasmagoria, Blackhat). Heap exploitation techniques for RELRO-protected binaries. Introduces hook overwriting: __malloc_hook, __free_hook, __realloc_hook remain writable. 2007 - glibc malloc hooks documented for debugging (glibc manual). Purpose: Allow custom allocators, instrumentation, debugging tools (valgrind, electric fence). Side effect: Exploitation primitive when GOT locked. 2008 - First public exploits using hook overwrite (Phrack, various authors). Technique: Heap overflow → Overwrite __malloc_hook → Next malloc() call → Shellcode/ROP. 2009 - '__malloc_hook + heap feng shui' becomes standard exploitation pattern for RELRO binaries. 2010 - 'The House of Mind' (glibc 2.11 exploitation). Heap metadata corruption → Trigger malloc consolidation → Overwrite __malloc_hook during consolidation. 2011 - one_gadget concept emerges (single ROP gadget for execve). Search libc.so for gadget sequences: MOV RDI, ptr_to_binsh; XOR RSI,RSI; XOR RDX,RDX; CALL execve. Overwrite __malloc_hook with one_gadget address → Instant shell. 2012 - 'How2Heap' educational repository (shellphish). Demonstrates hook overwrite techniques: fastbin dup, unsafe unlink, house of force → all target hooks for RELRO bypass. 2013 - CTF exploitation shifts to hook overwrite (DEF CON CTF, HITCON, others). Challenges assume Full RELRO, require hook techniques. 2014 - '__free_hook vs __malloc_hook' debate. free() often easier to trigger (free user-controlled pointer). __realloc_hook also viable (realloc internally calls malloc/free). 2015 - Android exploitation (Stagefright, Quadrooter). Bionic libc (Android's libc) lacks hooks initially → Later added for compatibility → Becomes attack surface. 2016 - glibc 2.24 hardens heap (tcache introduced in 2.26). Metadata protection improves but hooks still writable (backward compatibility for debugging tools). 2017 - '__malloc_hook removal discussion' on glibc mailing lists. Proposal: Remove hooks, breaking valgrind/sanitizers but improving security. Rejected due to ecosystem dependence. 2018 - glibc 2.27+ adds safe-linking (XOR encoding of FD pointers in tcache/fastbin). Makes heap corruption harder but hooks still exploitable if reached. 2019 - 'House of Muney' (new heap technique for 2.27+). Uses largebin attack → Overwrite __malloc_hook via unsorted bin corruption. 2020 - glibc 2.32+ deprecates hooks (marked obsolete). __malloc_hook/free_hook/realloc_hook still present but warning added. Future removal planned (breaks old debuggers). 2021 - 'House of Banana' (FILE stream exploitation). Alternative to hooks: Overwrite _IO_FILE structures → fflush/fclose → FSOP (File Stream Oriented Programming) → RCE. 2022 - glibc 2.34 removes hooks entirely (major version, breaking change). Exploitation shifts to FILE exploitation, vtable hijacking, TLS structure overwrites. Old binaries (linked to glibc <2.34) still vulnerable. 2023 - Ubuntu 22.04+ (glibc 2.35) hook-free. New techniques: __printf_function_table overwrite, environ overwrite, TLS corruption. Still vulnerable: Embedded systems (glibc 2.17-2.31 widespread), legacy servers, statically-linked old glibc. Exploitation flow: Info leak (heap address, libc base for ASLR defeat) → Heap corruption (overflow, UAF, double-free) → Overwrite __malloc_hook (with one_gadget, system, magic gadget) → Trigger malloc (allocate new chunk, often via program logic) → Hook called → Shellcode/gadget executes → Shell/RCE. one_gadget tool: Automated search for one-shot RCE gadgets in libc. Usage: one_gadget libc.so.6 → Lists gadget offsets + constraints (e.g., [rsp+0x30] == NULL). Choose gadget matching program state → Overwrite hook → Win. Modern alternatives to hooks (glibc 2.34+): TLS structures (thread-local storage, writable), GOT in libraries (dlopen'd libraries may have writable GOT if not FULL RELRO), __printf_function_table (custom printf handlers), _IO_FILE vtables (FSOP, virtual function tables for FILE), LD_PRELOAD hooks (if writable, rare), Stack canary (__stack_chk_guard overwrite, limited use). Key insight: Mitigations create new attack surface. RELRO locked GOT → Shifted attacks to hooks. Hooks removed → Shifted to FILE streams, TLS, vtables. Defense is evolution, exploitation adapts. The game continues.",
memoryLayout: [
{ key: 'baseAddress', label: 'MALLOC_HOOK', type: 'pointer', offset: 0x0 },
{ key: 'libcBase', label: 'FREE_HOOK', type: 'pointer', offset: 0x4 },
{ key: 'eip', label: 'HOOK_VALUE', type: 'pointer', offset: 0x8 },
{ key: 'sortValue1', label: 'HOOK_COUNT', type: 'int', offset: 0x10 },
{ key: 'sortValue2', label: 'OVERWRITE_SIZE', type: 'int', offset: 0x14 },
{ key: 'payload', label: 'RELRO_LEVEL', type: 'string', offset: 0x100 },
{ key: 'isAdmin', label: 'HOOK_SUCCESS', type: 'bool', offset: 0x30 }
],
initialState: {
baseAddress: '00000000',
libcBase: '00000000',
eip: '00000000',
sortValue1: 0,
sortValue2: 0,
payload: '',
isAdmin: false,
relroLevel: 'FULL',
heap: []
},
update: (s) => {
const mallocHook = parseInt((s.baseAddress || '00000000').replace('0x', ''), 16);
const freeHook = parseInt((s.libcBase || '00000000').replace('0x', ''), 16);
const hookValue = parseInt((s.eip || '00000000').replace('0x', ''), 16);
const expectedMallocHook = 0xB7E5C768;
const expectedFreeHook = 0xB7E5C770;
const expectedValue = 0xDEADBEEF;
const updates: any = {};
const mallocCorrect = mallocHook === expectedMallocHook;
const freeCorrect = freeHook === expectedFreeHook;
const valueCorrect = hookValue === expectedValue;
const relroFull = (s.payload || '').toLowerCase().includes('full');
const hookCount = s.sortValue1 >= 2;
const overwriteSize = s.sortValue2 === 8;
const heapAlloc = s.heap.some((h: any) => h.id === 'hooked_malloc' && h.active === true);
if (mallocCorrect && freeCorrect && valueCorrect && relroFull && hookCount && overwriteSize && heapAlloc) {
updates.isAdmin = true;
}
return updates;
},
platforms: [{ id: 'p1', x: 0, y: 280, width: 800, height: 40, type: 'static' }]
};