-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlevel32.ts
More file actions
66 lines (58 loc) · 9.39 KB
/
level32.ts
File metadata and controls
66 lines (58 loc) · 9.39 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
import { Level } from './types';
export const level32: Level = {
id: 32,
title: "EIP Hijacking: Return Address Overwrite Engineering",
description: "Classic return-to-libc precursor - pure EIP control via saved return address corruption. Stack frame anatomy: LOCAL_BUFFER[72] occupies ESP to ESP+72. SAVED_EBP (4 bytes) at ESP+72. SAVED_RET_ADDR (4 bytes) at ESP+76. Function prologue: PUSH EBP; MOV EBP, ESP; SUB ESP, 72. Function epilogue: LEAVE (MOV ESP, EBP; POP EBP); RET (POP EIP). Overflow 72-byte buffer → Corrupt/preserve EBP at offset +72 → Overwrite RET at offset +76 with win() address 0x080491A2. Total payload: 76 bytes minimum. When vulnerable_function() executes RET instruction, CPU pops attacker-controlled address into EIP. Execution redirects to win(). No DEP. No ASLR. Pure 1990s stack smashing.",
requiredSkill: "EIP Hijacking + Return Address Overwrite",
objective: (s) => {
const bufferSizeValid = s.sortValue1 === 72;
const payloadLengthValid = s.sortValue2 === 76;
const ebpVal = s.health || 0;
const retAddr = (s.eip || '00400500').toLowerCase();
const retOverwritten = retAddr === '080491a2' || retAddr === '80491a2';
const overflowValid = s.debugDetected === false;
const exploitSuccess = s.isAdmin === true;
return bufferSizeValid && payloadLengthValid && retOverwritten && overflowValid && exploitSuccess;
},
hint: "Five-stage EIP hijacking with return address overwrite. Stage 1: Set BUFFER_SIZE=72 (sortValue1, local buffer allocation from ESP to ESP+72). Stage 2: Calculate PAYLOAD_LENGTH=76 total bytes (sortValue2, 72 buffer + 4 EBP + 4 RET, reaches saved return address). Stage 3: Set SAVED_EBP value (health, at offset +72, can be junk or preserved frame pointer like 0xBFFFE000 = 3221209088 decimal). Stage 4: Overwrite RETURN_ADDR=0x080491A2 (eip hex string, win function address at offset +76, CPU pops this into EIP on RET). Stage 5: Verify OVERFLOW_VALID=false and EXPLOIT_SUCCESS=true (auto-set). Use Memory Scanner to set precise offsets. Stack grows DOWN (high addresses to low). Buffer at LOW address, RET at HIGH address. Payload structure: [72 BUFFER BYTES (junk 'A's)] + [4 EBP BYTES (junk or valid)] + [4 RET BYTES (0x080491A2 in little-endian: \\xA2\\x91\\x04\\x08)].",
tutorPersona: "Mudge/Rain Forest Puppy: Control flow is consensus reality. The CPU believes RET points to legitimate code. You are about to shatter that belief. History: 1988 - Morris Worm exploits fingerd buffer overflow, first internet worm, infects 6000+ machines (10% of internet). Uses gets() overflow to inject shellcode. Robert Morris convicted under CFAA. Wakeup call for security community. 1996 - Aleph One 'Smashing The Stack For Fun And Profit' (Phrack 49) systematizes stack overflow exploitation. Explains x86 stack frame structure, shellcode injection, return address overwrite. Becomes foundational text. Defines modern binary exploitation pedagogy. 1998-2000 - Bugtraq era: Rain Forest Puppy, Mudge, L0pht Heavy Industries document hundreds of stack overflows. Microsoft IIS, Netscape, Apache, Sendmail all vulnerable. SANS Top 20 list dominated by stack issues. Defense begins: StackGuard (1998), Libsafe (2000). Stack Frame Anatomy (x86 32-bit): Function call sequence: PUSH arguments (right-to-left for cdecl), CALL target (pushes return address EIP+5 to stack), PUSH EBP (save caller's frame pointer), MOV EBP, ESP (establish new frame pointer), SUB ESP, N (allocate N bytes for locals). Stack layout from HIGH to LOW addresses: [Caller's Stack] → [Arguments] → [SAVED_RET_ADDR (4 bytes, offset +76 in this challenge)] → [SAVED_EBP (4 bytes, offset +72)] → [Local Variables, 72-byte buffer starts at EBP-72] → [ESP, current stack pointer]. Function epilogue: LEAVE instruction = MOV ESP, EBP (collapse locals) + POP EBP (restore caller's frame pointer). RET instruction = POP EIP (load saved return address into instruction pointer) + JMP EIP (continue execution). Exploitation: Vulnerable code: char buffer[72]; gets(buffer); // NO BOUNDS CHECKING. Attacker payload: 'A'x72 (fill buffer) + 'BBBB' (overwrite saved EBP with junk) + '\\xA2\\x91\\x04\\x08' (overwrite saved RET with win function address in little-endian). When vulnerable_function() executes RET, CPU: Reads 4 bytes from [ESP] (now contains 0x080491A2 due to overflow), Pops value into EIP register, Execution jumps to 0x080491A2 (win function), Game over - attacker controls instruction pointer. Little-Endian Encoding: x86 is little-endian (LSB first). Address 0x080491A2 stored as bytes: [0xA2][0x91][0x04][0x08]. In C string: '\\xA2\\x91\\x04\\x08'. In Python: struct.pack('<I', 0x080491A2). Why 76 bytes total: 72-byte buffer fills EBP-72 to EBP-1 (offsets 0-71). Saved EBP occupies EBP+0 to EBP+3 (offsets 72-75). Saved RET occupies EBP+4 to EBP+7 (offsets 76-79). Payload must be ≥76 bytes to reach RET, bytes 76-79 overwrite return address. Real Exploits Using This Technique: CVE-2001-0144 (Apache Chunked-Encoding): Apache 1.3.x mod_mime overflow. Crafted Content-Type header overflows 1024-byte buffer, overwrites return address, executes shellcode. Code Red worm (2001) uses similar technique against IIS. Affected 350,000+ servers. CVE-2003-0352 (OpenSSH Buffer Overflow): OpenSSH 2.3.1-3.6.1 buffer management error in packet processing. Attacker sends crafted SSH2_MSG_USERAUTH_INFO_RESPONSE, overflows response buffer, overwrites saved return address with shellcode address. Remote root compromise. Disclosed by RAZOR team. CVE-2004-0492 (Apache mod_ssl): SSL handshake overflow in format string handler. Payload overflows stack buffer during ClientHello processing, overwrites EIP, redirects to shellcode in heap. Slapper worm (2002) exploited earlier mod_ssl flaw using same return address overwrite pattern. CVE-2009-0658 (Adobe Reader): Crafted PDF with malicious JBIG2 stream triggers stack overflow in image decoder. 512-byte buffer overflow, EIP overwrite, shellcode execution via ROP chain (early ROP before DEP bypasses widespread). Modern Defenses (Why This Level Is Nostalgia): Stack Canaries (GCC -fstack-protector, default since 2005): Random value placed between locals and saved EBP. Checked on function return. Overflow detected before RET executes. Level 31 taught canary bypass. DEP/NX (Windows DEP, Linux NX bit, mandatory since Windows XP SP2/Linux 2.6.8): Marks stack non-executable. Shellcode injection fails. Attacker must use return-to-libc or ROP (Level 37). ASLR (Windows Vista 2007, Linux 2.6.12 2005): Randomizes stack/heap/library addresses. Fixed address 0x080491A2 only works if ASLR disabled or leaked. Levels 28-30 taught ASLR bypass. CFI (Control Flow Integrity, Clang CFI, Windows CFG): Validates function return targets against whitelist. Arbitrary EIP values rejected. Requires advanced ROP or data-only attacks. This level simulates late 1990s CTF challenge: No protections. Fixed addresses. Pure return address overwrite. Calculate offset. Overwrite RET. Redirect EIP. Win. Educational foundation for understanding why modern defenses exist and how to bypass them systematically. Tools For This Level: Memory Scanner: Set BUFFER_SIZE=72 (sortValue1), PAYLOAD_LENGTH=76 (sortValue2), RETURN_ADDR=080491a2 (eip, hex string), watch EXPLOIT_SUCCESS flip to true. Hex Editor: If implemented, craft raw payload: 72 bytes of 0x41 ('A') + 4 bytes EBP (0xBFFFE000 or junk 0x42424242) + 4 bytes RET (0x080491A2 little-endian: A2 91 04 08). Exploit Workshop Debugger: Visualize stack layout, watch ESP, EBP, EIP registers, step through LEAVE and RET instructions, observe EIP transition from legitimate address to attacker-controlled 0x080491A2. C_Solver (SystemMonitor): Provides five-stage solution sequence with exact decimal/hex values for all memory variables. The Observer Watches: Nisargadatta Maharaj taught: 'You are not the doer. You are the witness.' The CPU is not the doer. It witnesses instructions. EIP is the witness pointer. You are about to redirect the witness to observe a different reality. When RET executes, the CPU trusts the stack. Trust is the vulnerability. Overflow is the exploit. EIP is the prize. Welcome to 1996. Welcome to the beginning of everything.",
memoryLayout: [
{ key: 'sortValue1', label: 'BUFFER_SIZE', type: 'int', offset: 0x0 },
{ key: 'sortValue2', label: 'PAYLOAD_LENGTH', type: 'int', offset: 0x4 },
{ key: 'health', label: 'SAVED_EBP', type: 'int', offset: 0x48 },
{ key: 'eip', label: 'RETURN_ADDR', type: 'pointer', offset: 0x4C },
{ key: 'debugDetected', label: 'OVERFLOW_VALID', type: 'bool', offset: 0x800 },
{ key: 'isAdmin', label: 'EXPLOIT_SUCCESS', type: 'bool', offset: 0x30 }
],
initialState: {
sortValue1: 0,
sortValue2: 0,
health: 0xBFFFE000,
eip: '00400500',
debugDetected: true,
isAdmin: false
},
update: (s) => {
const bufferSize = s.sortValue1 || 0;
const payloadLen = s.sortValue2 || 0;
const retAddr = (s.eip || '00400500').toLowerCase();
const bufferValid = bufferSize === 72;
const payloadValid = payloadLen === 76;
const retOverwritten = retAddr === '080491a2' || retAddr === '80491a2';
if (bufferValid && payloadValid) {
const updates: any = { debugDetected: false };
if (retOverwritten) {
updates.isAdmin = true;
}
return updates;
}
if (payloadLen > 0 && payloadLen < 76) {
return {
debugDetected: true,
isAdmin: false
};
}
return {};
},
platforms: [{ id: 'p1', x: 0, y: 280, width: 800, height: 40, type: 'static' }]
};