-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlevel28.ts
More file actions
48 lines (43 loc) · 6.41 KB
/
level28.ts
File metadata and controls
48 lines (43 loc) · 6.41 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
import { Level } from './types';
export const level28: Level = {
id: 28,
title: "ASLR: Relative Truth",
description: "Address Space Layout Randomization (ASLR) enabled. Modern operating systems randomize base addresses of executables, libraries, stack, and heap on each launch. Hardcoded addresses (0x400000) become invalid. Only relative offsets remain constant: Target_Address = Base_Address + Static_Offset. Use MemoryScanner to locate the randomized SOURCE_BASE, then calculate offsets. This technique is essential for exploit development on modern systems with DEP/ASLR.",
requiredSkill: "ASLR Bypass via Base Address Leaking & Offset Calculation",
objective: (s) => {
const baseLeaked = s.pointerChainBase !== '000000' && s.pointerChainBase !== '123456';
const offsetCalculated = s.sortValue1 > 0 && s.sortValue1 < 0x10000;
const targetComputed = s.health > 0x400000 && s.health < 0x800000;
const aslrBypassed = s.isAdmin === true;
return baseLeaked && offsetCalculated && targetComputed && aslrBypassed;
},
hint: "Four-stage ASLR bypass. ASLR randomizes base address (0x400000-0x4FFFFF) each execution. Stage 1: Leak MODULE_BASE (SOURCE_BASE pointer, must change from default). Stage 2: Calculate STATIC_OFFSET (sortValue1, distance from base to target, typically 0x1000-0xFFFF). Stage 3: Compute TARGET_ADDRESS (health = MODULE_BASE + STATIC_OFFSET, must exceed 0x400000). Stage 4: Set ASLR_BYPASSED (isAdmin=true). Use Memory Scanner to read/write all four values sequentially.",
tutorPersona: "Morpheus/Nisargadatta: The Matrix is built on shifting sand (ASLR). You cannot memorize the position of a door that moves every second. But the distance from you to the door? That never changes. This is the nature of relative addressing. Windows (since Vista), Linux (since 2.6.12), macOS, Android - all randomize memory at runtime. Why? Exploit code assumes fixed addresses: 'JMP 0x401000 contains shellcode'. ASLR breaks this: next execution 0x401000 is empty, shellcode at 0x7FFA2000. Attacker's hardcoded addresses hit garbage, exploit crashes. Defense timeline: 2001 PaX (Linux kernel patch), 2007 Windows Vista DEP+ASLR, 2012 iOS 4.3 mandatory ASLR, 2016 Linux PIE (Position Independent Executable) default. Modern exploitation requires two-stage attack: Stage 1 Information Leak (disclose base address via format string, use-after-free, heap spray), Stage 2 ROP Chain (calculate gadget addresses from leaked base). Real-world ASLR implementations: Windows randomizes ImageBase (exe/dll base), stack base, heap base, PEB/TEB addresses. 8-24 bits entropy (256-16,777,216 possible bases). 64-bit systems: 20+ bits entropy (1,048,576+ bases), near-impossible brute force. Linux ASLR via /proc/sys/kernel/randomize_va_space (0=off, 1=mmap only, 2=full). PIE binaries compiled with -fPIE -pie relocate entire .text section. Non-PIE executables: main binary static at 0x400000, only libraries randomized (half-ASLR). Bypass techniques: (1) Information disclosure - Format string '%p%p%p' leaks stack addresses containing return pointers, calculate libc base from return address. UAF (Use-After-Free) reads freed object pointers, discloses heap base. Heap spray with predictable patterns, brute-force partial offsets. (2) Partial overwrite - ASLR randomizes high bytes (0x7FxxxxFFFF), low 12 bits fixed (page alignment). Overwrite 1-2 bytes instead of full address, narrow search space to 256-4096 possibilities. (3) JIT spraying - JavaScript/Flash JIT compilers generate executable code in predictable regions, bypass W^X. (4) Brute force 32-bit - 8-bit entropy = 256 attempts. Fork server to preserve ASLR seed across crashes. (5) Side channels - Cache timing reveals code layout (ASLR-Cache), Spectre/Meltdown bypass ASLR via speculative execution. Your scenario: Protected banking application loads at randomized MODULE_BASE. Critical function at BASE+0x1234. Four memory variables track ASLR bypass progress: MODULE_BASE (leaked base address pointer), STATIC_OFFSET (known offset to target function from reverse engineering, constant across executions), TARGET_ADDRESS (computed runtime address = BASE+OFFSET), ASLR_BYPASSED (privilege flag, true when correct target calculated). Attack sequence: Use Memory Scanner to leak MODULE_BASE (simulates infoleak vulnerability like format string). Calculate STATIC_OFFSET (reverse engineering determined offset, set to known value like 0x1234). Compute TARGET_ADDRESS by adding BASE+OFFSET (demonstrates address resolution). Set ASLR_BYPASSED flag (simulates successful exploitation at computed address). Real exploits: CVE-2014-0515 Adobe Flash integer overflow → heap spray → info leak → ASLR bypass → ROP → shellcode. CVE-2019-0708 BlueKeep RDP vulnerability → kernel pool spray → leak KUSER_SHARED_DATA → calculate ntoskrnl.sys base → kernel ROP. iOS jailbreaks leak kernel task port → read kernel memory → find kaslr slide → calculate gadget addresses. Assembly mechanics: PIE binary compiled with RIP-relative addressing. LEA RAX, [RIP+0x1234] loads address relative to instruction pointer. Works regardless of base. Non-PIE uses absolute MOV RAX, 0x401234, breaks under ASLR. Exploit shellcode uses GetPC (get program counter) trick. CALL get_pc; get_pc: POP EBX (EBX=current EIP), then access data via [EBX+offset]. Position-independent. Modern defenses beyond ASLR: CFG (Control Flow Guard), CET (Control-flow Enforcement Technology) shadow stack, Intel CET IBT (Indirect Branch Tracking), ARM PAC (Pointer Authentication Codes). ASLR alone insufficient, must combine with DEP/NX, stack canaries, CFI.",
memoryLayout: [
{ key: 'pointerChainBase', label: 'MODULE_BASE', type: 'pointer', offset: 0x0 },
{ key: 'sortValue1', label: 'STATIC_OFFSET', type: 'int', offset: 0xA0 },
{ key: 'health', label: 'TARGET_ADDRESS', type: 'int', offset: 0x10 },
{ key: 'isAdmin', label: 'ASLR_BYPASSED', type: 'bool', offset: 0x30 }
],
initialState: {
pointerChainBase: '123456',
sortValue1: 0,
health: 0,
isAdmin: false
},
update: (s) => {
const baseNum = parseInt(s.pointerChainBase || '0', 16);
const offset = s.sortValue1 || 0;
if (baseNum > 0 && offset > 0 && offset < 0x10000) {
const computed = baseNum + offset;
if (computed >= 0x400000 && computed < 0x800000) {
return {
health: computed,
isAdmin: true
};
}
}
return {};
},
platforms: [{ id: 'p1', x: 0, y: 280, width: 800, height: 40, type: 'static' }]
};