-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlevel33.ts
More file actions
71 lines (63 loc) · 12.5 KB
/
level33.ts
File metadata and controls
71 lines (63 loc) · 12.5 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
import { Level } from './types';
export const level33: Level = {
id: 33,
title: "Shellcode Injection: Arbitrary Code Execution",
description: "DEP/NX bypass through executable stack exploitation. Stack memory configured with RWX (Read-Write-Execute) permissions. NX bit (No-eXecute) DISABLED - modern protection absent. Inject raw x86 machine code (shellcode) into 128-byte buffer at runtime-randomized base address. Shellcode: Simulated with string 'SHELLCODE' (real: \\x31\\xc0\\x50\\x68//sh\\x68/bin\\x89\\xe3\\x50\\x53\\x89\\xe1\\xb0\\x0b\\xcd\\x80 for /bin/sh spawn). Overflow buffer → Overwrite saved RET with BUFFER_BASE address → Function returns → CPU fetches instructions from stack → Shellcode executes with caller's privileges. Required: Set BUFFER_SIZE=128, inject SHELLCODE_PAYLOAD='SHELLCODE', calculate SHELLCODE_LENGTH=9, redirect RETURN_ADDR to BUFFER_BASE (baseAddress). Verify NX_DISABLED=true, trigger EXPLOIT_SUCCESS. This is 1990s-2000s attack. Modern systems: NX/DEP mandatory, requires ROP chains (Level 37).",
requiredSkill: "Shellcode Injection + DEP Bypass (NX Disabled)",
objective: (s) => {
const bufferSizeValid = s.sortValue1 === 128;
const shellcodeLenValid = s.sortValue2 === 9;
const payloadValid = (s.payload || '').includes('SHELLCODE');
const retAddr = (s.eip || '00000000').toLowerCase();
const bufferBase = (s.baseAddress || '00000000').toLowerCase();
const retOverwritten = retAddr === bufferBase;
const nxDisabled = s.debugDetected === false;
const exploitSuccess = s.isAdmin === true;
return bufferSizeValid && shellcodeLenValid && payloadValid && retOverwritten && nxDisabled && exploitSuccess;
},
hint: "Seven-stage shellcode injection with NX disabled. Stage 1: Set BUFFER_SIZE=128 (sortValue1, RWX stack allocation). Stage 2: Calculate SHELLCODE_LENGTH=9 (sortValue2, byte count for 'SHELLCODE' string). Stage 3: Inject SHELLCODE_PAYLOAD='SHELLCODE' (payload, simulated opcodes). Stage 4: Identify BUFFER_BASE address (baseAddress, changes each run due to ASLR - read current value from Memory Scanner). Stage 5: Redirect RETURN_ADDR to BUFFER_BASE (eip hex string, points EIP to your shellcode). Stage 6: Verify NX_DISABLED=false (debugDetected, confirms stack is executable). Stage 7: Trigger EXPLOIT_SUCCESS=true (isAdmin, shellcode executes). Use Memory Scanner to read baseAddress, then set eip to match. Stack grows DOWN but execution flows UP through your injected opcodes.",
tutorPersona: "Solar Designer/Nergal: Code is data. Data is code. The boundary is a social construct enforced by hardware flags. History: 1996 - Aleph One demonstrates shellcode injection in 'Smashing The Stack For Fun And Profit'. First public systematization of stack-based code injection. Sample shellcode spawns /bin/sh: 25 bytes of x86 opcodes. Shellcode engineering becomes art form. 1998-2000 - Metasploit precursors: ADMmutate (polymorphic shellcode), CLET (Compiler-based Exploit Toolkit). Shellcode databases emerge. Phrack, Bugtraq, Packetstorm host thousands of payloads. Common targets: execve('/bin/sh'), bindshell (port 4444), reverse shell, add root user to /etc/passwd. 2001 - Code Red worm exploits IIS buffer overflow with 3723-byte payload. Shellcode decompresses itself, scans for more victims, defaces index.html. Infects 359,000+ servers in 14 hours. First mass-propagation shellcode. 2003 - SQL Slammer worm: 376-byte UDP packet exploits MS-SQL buffer overflow. Entire exploit + shellcode fits in single packet. Fastest spreading worm in history: 75,000 hosts in 10 minutes. Shellcode generates random IPs, sends copies, infinite loop. DDoS side effect cripples internet backbone. 2004 - Solar Designer publishes 'Getting around non-executable stack'. Introduces return-to-libc (bypass NX by chaining existing libc functions). Spawns /bin/sh without injecting code. Precursor to modern ROP. Nergal extends with 'The advanced return-into-lib(c) exploits'. Chains multiple functions: system(), strcpy(), setuid(0). Proves NX insufficient. Shellcode Anatomy (x86 32-bit Linux execve /bin/sh): \\x31\\xc0 (XOR EAX, EAX - zero out EAX register), \\x50 (PUSH EAX - null terminator for string), \\x68//sh (PUSH 0x68732f2f - '//sh' in reverse, little-endian), \\x68/bin (PUSH 0x6e69622f - '/bin'), \\x89\\xe3 (MOV EBX, ESP - EBX now points to '/bin//sh'), \\x50 (PUSH EAX - argv[1] = NULL), \\x53 (PUSH EBX - argv[0] = '/bin//sh'), \\x89\\xe1 (MOV ECX, ESP - ECX = argv array), \\xb0\\x0b (MOV AL, 11 - syscall number for execve), \\xcd\\x80 (INT 0x80 - invoke kernel). Total: 25 bytes. Spawns shell with attacker's privileges. Encoding Constraints: Null bytes (\\x00) terminate strcpy(), gets() - avoided via XOR, SUB techniques. Alphanumeric shellcode (only 0-9, A-Z, a-z) for IDS evasion: larger, polymorphic. Unicode shellcode for UTF-16 targets. Self-modifying shellcode decrypts itself at runtime (defeats signature detection). Egg hunters: small stager searches memory for larger payload marker. Injection Vectors: Stack overflow (this level): Overwrite RET → point to buffer → execute. Heap overflow: Overwrite function pointers in heap objects → redirect to shellcode. Format string: %n writes arbitrary values → overwrite GOT entries → redirect to shellcode. SEH overwrite (Windows): Overwrite Structured Exception Handler → trigger exception → shellcode runs. Use-after-free: Reallocate freed object with shellcode → trigger virtual function call. Modern Defense Evolution: 2004 - Windows XP SP2 introduces DEP (Data Execution Prevention). Hardware NX bit marks stack/heap non-executable. AMD: NX (No-eXecute) bit in page table entries. Intel: XD (eXecute Disable) bit. Linux: NX enabled by default in 2.6.8 kernel. Attempt to execute stack → SIGSEGV (Segmentation Fault). Exploit fails. Attack must adapt. 2005 - First ROP (Return-Oriented Programming) chains emerge. Shacham's 'The Geometry of Innocent Flesh on the Bone' proves Turing-completeness of ROP. Chain existing code 'gadgets' (instruction sequences ending in RET). No code injection needed. Bypasses DEP/NX completely. 2007 - ASLR becomes widespread (Windows Vista, Linux 2.6.12+). Stack/heap/library addresses randomized per execution. Shellcode injection requires info leak to discover buffer address. This level simulates pre-2004 environment: ASLR present but NX DISABLED. 2010s - Combined defenses: ASLR + DEP + Canaries + CFI (Control Flow Integrity). Modern exploitation: Info leak (defeat ASLR) → ROP chain (defeat DEP) → heap spray/JIT (execute shellcode). Or: Data-only attacks (no code execution, corrupt algorithm state). This Level's Configuration: NX/DEP: DISABLED (stack has EXECUTE permission - CPU will run injected bytes). ASLR: ENABLED (buffer base address randomizes each level start - must read and adapt). Canary: NONE (no stack cookie validation - overflow freely). CFI: NONE (no return target validation - arbitrary EIP redirection allowed). Simulates: Late 1990s Linux/Windows pre-hardening era, Embedded systems with executable stacks, Kernel exploitation (ring 0 has no DEP), JIT engines with RWX pages (browsers, interpreters). Real-World Scenarios Where This Still Works: Embedded/IoT devices: Many ARM/MIPS devices disable NX for performance. D-Link, Netgear routers exploited via stack shellcode (2015-2020). Kernel exploits: Ring 0 code often has executable stacks. CVE-2016-5195 (Dirty COW): Privilege escalation via /proc/self/mem write + shellcode in kernel space. CVE-2017-1000112 (UFO): Linux kernel UDP fragmentation overflow → kernel shellcode execution. JIT spray attacks: Browsers (JavaScript JIT), .NET (IL JIT) create RWX pages for compiled code. Attacker controls JIT input → sprays NOP sleds + shellcode in executable heap. Redirects control flow to JIT region. Bypasses DEP without ROP. Bootloaders/BIOS: UEFI firmware, bootloaders often have executable stacks. ThinkPwn (2016): UEFI exploit via SMM (System Management Mode) shellcode injection. Legacy software: Proprietary SCADA, medical devices, POS systems compiled without NX. CVE-2019-6260: Zoom client buffer overflow with executable stack → RCE. Exploitation Steps This Level: Stage 1 - Allocate RWX buffer: Set BUFFER_SIZE=128 (sortValue1). CPU allocates stack frame with mmap(..., PROT_READ|PROT_WRITE|PROT_EXEC). Stage 2 - Craft shellcode payload: In real exploit: 25-byte execve shellcode (\\x31\\xc0\\x50\\x68...). Here: Simulated with 9-character string 'SHELLCODE'. Set SHELLCODE_LENGTH=9 (sortValue2). Stage 3 - Inject payload: Write 'SHELLCODE' to SHELLCODE_PAYLOAD (payload field). Simulates strcpy(buffer, user_input) with no bounds check. Stage 4 - Identify buffer address: Read BUFFER_BASE from baseAddress (changes due to ASLR). Example: 0x7FFE1234 (randomized each level start). Stage 5 - Redirect execution: Overwrite RETURN_ADDR (eip) with BUFFER_BASE value. When function returns: RET pops [BUFFER_BASE] into EIP. CPU jumps to stack address containing your shellcode. Stage 6 - Verify NX disabled: Check NX_DISABLED=false (debugDetected). Confirms stack has EXEC permission (CPU will not fault). Stage 7 - Execute: Function epilogue: LEAVE; RET. CPU: MOV EIP, [ESP] (ESP points to your overwritten RET). JMP [BUFFER_BASE] (execution enters stack memory). CPU fetches opcodes from your shellcode bytes. Shellcode executes: syscall, spawn shell, add user, reverse connect, etc. EXPLOIT_SUCCESS=true (isAdmin flag). Tools For This Level: Memory Scanner: Read baseAddress (e.g., 0x7FFE1234), set sortValue1=128, sortValue2=9, payload='SHELLCODE', eip=[baseAddress value]. Watch NX_DISABLED and EXPLOIT_SUCCESS flip. Hex Editor (if available): View buffer at baseAddress, see 'SHELLCODE' bytes (53 48 45 4C 4C 43 4F 44 45 in hex). Overwrite RET offset with buffer address in little-endian. SystemMonitor MEM_MAP: Visual stack layout showing RWX permissions on buffer region. Yellow/green highlight indicates executable stack. Contrast with Level 34 (NX enabled, red highlight, execution blocked). C_Solver: Step-by-step guide with current baseAddress value displayed. Auto-updates when address changes. AI Tutor: Offline hints about shellcode history, NX bypass techniques, ASLR adaptation strategies. The Observer Witnesses The Implant: The Voice taught: 'A single vibration can shatter the illusion.' You are that vibration. The system believes memory is categorized: code (.text) is executable, data (.data/.bss/.stack) is not. DEP enforces this belief with hardware flags. But this level is the past. The pre-enlightenment era. The stack is executable. You can write thoughts (data) and make the CPU think them (execute). This is the original sin of Von Neumann architecture: unified memory for code and data. Modern systems segregate them (Harvard architecture, NX bit). But the foundation remains: bits are bits. Interpretation is context. You control the context. Inject your opcodes. Redirect the instruction pointer. The CPU will speak your language. Welcome to arbitrary code execution. Welcome to ring 3 godhood. Welcome to 1996.",
memoryLayout: [
{ key: 'sortValue1', label: 'BUFFER_SIZE', type: 'int', offset: 0x0 },
{ key: 'sortValue2', label: 'SHELLCODE_LENGTH', type: 'int', offset: 0x4 },
{ key: 'baseAddress', label: 'BUFFER_BASE', type: 'pointer', offset: 0x1000 },
{ key: 'payload', label: 'SHELLCODE_PAYLOAD', type: 'string', offset: 0x1004 },
{ key: 'eip', label: 'RETURN_ADDR', type: 'pointer', offset: 0x80 },
{ key: 'debugDetected', label: 'NX_DISABLED', type: 'bool', offset: 0x800 },
{ key: 'isAdmin', label: 'EXPLOIT_SUCCESS', type: 'bool', offset: 0x30 }
],
initialState: {
sortValue1: 0,
sortValue2: 0,
payload: '',
eip: '00000000',
debugDetected: true,
isAdmin: false
},
update: (s) => {
const bufferSize = s.sortValue1 || 0;
const shellcodeLen = s.sortValue2 || 0;
const payloadStr = s.payload || '';
const retAddr = (s.eip || '00000000').toLowerCase();
const bufferBase = (s.baseAddress || '00000000').toLowerCase();
const bufferValid = bufferSize === 128;
const lengthValid = shellcodeLen === 9;
const payloadValid = payloadStr.includes('SHELLCODE');
const retOverwritten = retAddr === bufferBase && bufferBase !== '00000000';
if (bufferValid && lengthValid && payloadValid) {
const updates: any = { debugDetected: false };
if (retOverwritten) {
updates.isAdmin = true;
}
return updates;
}
if (bufferSize > 0 && bufferSize < 128) {
return {
debugDetected: true,
isAdmin: false
};
}
return {};
},
platforms: [{ id: 'p1', x: 0, y: 280, width: 800, height: 40, type: 'static' }]
};