-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlevel39.ts
More file actions
72 lines (63 loc) · 9.48 KB
/
level39.ts
File metadata and controls
72 lines (63 loc) · 9.48 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
70
71
72
import { Level } from './types';
export const level39: Level = {
id: 39,
title: "Double Free: The Doppler Effect",
description: "Double Free: Heap metadata corruption via fastbin poisoning. Glibc ptmalloc2 allocator maintains fastbins (singly-linked free lists, LIFO) for chunks <512 bytes. Fastbin metadata stored in chunk header: [SIZE][FD→next_free_chunk]. Double free vulnerability: free(A)→free(B)→free(A) corrupts freelist: HEAD→A→B→A (circular). Fastbin lacks double-free detection (removed for performance). Exploitation: malloc()×3 returns A,B,A (overlapping allocations). Overwrite chunk A's data → affects second allocation of A. Advanced: Modify FD pointer → malloc() returns arbitrary address. Real scenario: Browser JavaScript engine object reuse, network daemon buffer pools. This level: Demonstrate fastbin corruption by freeing CHUNK_A twice (addresses must match: FREED_A_1 == FREED_A_2). Use SystemMonitor > Heap View to visualize freelist. Set DOUBLE_FREE=true to trigger. Real fastbin attack: Overwrite FD→target_addr → malloc() returns target_addr → Arbitrary write primitive.",
requiredSkill: "Heap Corruption",
objective: (s) => {
const chunkAStr = (s.baseAddress || '').toLowerCase().replace('0x', '').padStart(8, '0');
const freedA1Str = (s.libcBase || '').toLowerCase().replace('0x', '').padStart(8, '0');
const freedA2Str = (s.eip || '').toLowerCase().replace('0x', '').padStart(8, '0');
const chunkAValid = chunkAStr === '08100000';
const freedA1Valid = freedA1Str === '08100000';
const freedA2Valid = freedA2Str === '08100000';
const addressMatch = freedA1Valid && freedA2Valid && chunkAValid;
const fastbinSizeValid = s.sortValue1 === 64;
const freeCountValid = s.sortValue2 >= 2;
const payloadValid = (s.payload || '').toLowerCase().includes('a->b->a');
const doubleFreeSuccess = s.isAdmin === true;
return chunkAValid && addressMatch && fastbinSizeValid && freeCountValid && payloadValid && doubleFreeSuccess;
},
hint: "Seven-stage double free exploitation via fastbin poisoning. Stage 1: Read CHUNK_A address (baseAddress, heap chunk to free twice, value: 0x08100000). Stage 2: Free CHUNK_A first time (libcBase, freed address must match CHUNK_A: 0x08100000). Stage 3: Free CHUNK_A second time (eip, create circular freelist, must match: 0x08100000). Stage 4: Set FASTBIN_SIZE = 64 (sortValue1 int, chunk size for fastbin list). Stage 5: Set FREE_COUNT = 2+ (sortValue2 int, number of frees performed). Stage 6: Craft payload pattern (payload string, demonstrate free sequence: 'A->B->A' or 'free(A);free(B);free(A);'). Stage 7: Allocate heap object 'fastbin_poison' (SystemMonitor > Heap View, active=true) → DOUBLE_FREE auto-triggers. Use Memory Scanner to set addresses (HEX tab: CHUNK_A, FREED_A_1, FREED_A_2 all = 08100000). Real exploit sequence: free(A) → freelist: [A→NULL] → free(B) → freelist: [B→A→NULL] → free(A) → freelist: [A→B→A→...circular]. Next malloc()×3 returns A,B,A (overlap) → Modify A's data → corrupts second A allocation → Control FD pointer → Arbitrary address allocation.",
tutorPersona: "Phantasmal Phantasmagoria/The Malloc Maleficarum: When the allocator loses count, you gain infinity. History: 2001 - glibc ptmalloc2 heap allocator introduced (Wolfram Gloger, based on Doug Lea's dlmalloc). Fastbins optimization: Small chunks (<512 bytes, 64 bins) use singly-linked LIFO free lists for performance. No coalescing, no double-free check. 2004 - First public heap exploitation techniques (Phrack 57, 'Once upon a free()', anonymous). Demonstrated fastbin manipulation: Corrupt chunk size → trigger unlink() → arbitrary write. 2007 - 'The Malloc Maleficarum' published (Phantasmal Phantasmagoria, Blackhat USA 2007). Comprehensive heap exploitation guide: double free, chunk overlap, fastbin attack, unlink attack, wilderness corruption. Double free concept: free(A) → free(B) → free(A) creates circular freelist. Fastbin fd pointer: chunk header stores FD (forward pointer to next free chunk). Double free pattern: HEAD→A(fd=B)→B(fd=A)→A(...circular). Exploitation: malloc() returns A, malloc() returns B, malloc() returns A again (overlap!). Overwrite first A's data → corrupts second A → Type confusion or control flow hijack. 2009 - CVE-2009-2692 (Linux kernel sock_sendpage() double free, root exploit). Android 2010 - Multiple browser heap exploits using fastbin attacks. 2014 - 'Glibc Adventures: The Forgotten Chunks' (Sensepost, Gynvael Coldwind). House of Spirit: Fake chunk in stack/BSS, free() fake chunk → malloc() returns controlled address. House of Lore: Corrupt small bin freelist (similar to fastbin but doubly-linked). 2015 - House of Force (modify wilderness chunk size to MAX_UINT → malloc(huge) wraps pointer to arbitrary address). 2016 - CVE-2016-4117 (Adobe Flash Worker heap corruption, used in wild by APT groups). Fastbin dup consolidate: Trigger malloc_consolidate() → move fastbin chunk to unsorted bin → Double allocate from different bins. 2017 - 'House of Einherjar' (null-byte overflow + heap consolidation → overlapping chunks). 'House of Orange' (trigger _IO_flush_all_lockp via heap overflow → file stream exploitation). 2018 - Tcache (Thread Local Cache) introduced in glibc 2.26 (7 bins, per-thread fastbins). Double-free check added for tcache (single-linked like fastbins but with simple corruption detection). Bypass: free(A)→free(B)→free(A) still works (check only prevents immediate double free). 2019 - CVE-2019-14899 (VirtualBox heap overflow + double free, VM escape). 2020 - Project Zero: 'A Look at iMessage in iOS 14' (Samuel Groß, 5 RCE chains, fastbin/tcache exploits). iOS SLUB allocator (kernel) similar concepts: Object reuse, freelist corruption, cross-cache attacks. 2021 - Checkpoint Research: 'PWN2OWN 2021 Exchange Server RCE chain' (heap feng shui + double free). Glibc 2.34 hardens tcache: key field in chunk (0xdeadbeef marker), double-free detection improved. 2022 - Bypass via key overwrite: Heap overflow to clear key field → free() passes check. Modern heap exploitation: Info leak (heap address via UAF/overflow) → Fastbin/tcache poisoning → Arbitrary allocation → Overwrite function pointers/vtables → RCE. Mitigation evolution: glibc 2.28+ Safe-Linking (XOR encoding of fd pointers, requires heap leak). Hardened allocators: ptmalloc_NG, tcmalloc, jemalloc (better metadata protection). 2023 - Browser heap hardening: PartitionAlloc (Chromium, isolated heaps per object type), Oilpan (Blink garbage collector). Still vulnerable: Legacy systems (glibc <2.26), embedded devices, game engines, parsers (libxml2, ffmpeg). Exploitation flow: Info leak (heap address) → Trigger double free (free twice with intermediate free) → Corrupt FD pointer (overwrite to target address) → malloc() returns target → Write shellcode/ROP chain → Code execution. Real-world: Double free often combined with UAF (use-after-free). Example: free(A) → use(A) → free(A) → Overlapping allocation + dangling pointer → Full control. Fastbin attack variations: Fastbin dup (basic double free), Fastbin dup into stack (FD→stack address), Fastbin dup consolidate (trigger consolidation to unsorted bin), Arbitrary allocation (control FD→anywhere). Detection: AddressSanitizer (heap-use-after-free + double-free runtime detection), Valgrind (memcheck finds double free), glibc assertions (abort on corruption in debug builds). Key insight: Heap exploitation = metadata manipulation. Every allocation has metadata (size, flags, FD/BK pointers). Corrupt metadata → Control allocator behavior → Arbitrary allocation → Memory corruption → Code execution. The heap is a database. Double free is a database consistency bug. You are the attacker exploiting ACID violations.",
memoryLayout: [
{ key: 'baseAddress', label: 'CHUNK_A', type: 'pointer', offset: 0x0, isStatic: true },
{ key: 'libcBase', label: 'FREED_A_1', type: 'pointer', offset: 0x4 },
{ key: 'eip', label: 'FREED_A_2', type: 'pointer', offset: 0x8 },
{ key: 'sortValue1', label: 'FASTBIN_SIZE', type: 'int', offset: 0x10 },
{ key: 'sortValue2', label: 'FREE_COUNT', type: 'int', offset: 0x14 },
{ key: 'payload', label: 'FREE_PATTERN', type: 'string', offset: 0x100 },
{ key: 'isAdmin', label: 'DOUBLE_FREE', type: 'bool', offset: 0x30 }
],
initialState: {
baseAddress: '08100000',
libcBase: '00000000',
eip: '00000000',
sortValue1: 0,
sortValue2: 0,
payload: '',
isAdmin: false,
heap: [
{ id: 'chunk_A', size: 64, active: true },
{ id: 'chunk_B', size: 64, active: true }
]
},
update: (s) => {
const chunkA = parseInt((s.baseAddress || '08100000').replace('0x', ''), 16);
const freedA1 = parseInt((s.libcBase || '00000000').replace('0x', ''), 16);
const freedA2 = parseInt((s.eip || '00000000').replace('0x', ''), 16);
const expectedChunk = 0x08100000;
const expectedSize = 64;
const addressMatch = chunkA === expectedChunk && freedA1 === expectedChunk && freedA2 === expectedChunk;
const sizeValid = s.sortValue1 === expectedSize;
const freeCountValid = s.sortValue2 >= 2;
const patternValid = (s.payload || '').toLowerCase().includes('a->b->a');
const heapValid = s.heap.some(h => h.id === 'fastbin_poison' && h.active === true);
const updates: any = {};
if (addressMatch && sizeValid && freeCountValid && patternValid && heapValid) {
updates.isAdmin = true;
}
return updates;
},
platforms: [{ id: 'p1', x: 0, y: 280, width: 800, height: 40, type: 'static' }]
};