Hacktricks-skills aslr-bypass

How to check, disable, and bypass ASLR (Address Space Layout Randomization) on Linux systems. Use this skill whenever the user mentions ASLR, address randomization, memory layout, binary exploitation, CTF challenges involving memory addresses, or needs to work around ASLR for debugging or exploitation. This includes checking ASLR status, disabling it for testing, brute-forcing addresses, using information leaks, or exploiting fixed addresses like vsyscall/vDSO.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/binary-exploitation/common-binary-protections-and-bypasses/aslr/aslr/SKILL.MD
source content

ASLR Bypass Techniques

Address Space Layout Randomization (ASLR) randomizes memory addresses used by processes to make exploitation harder. This skill covers checking ASLR status, disabling it for testing, and various bypass techniques.

Quick Reference

TaskCommand
Check ASLR status
cat /proc/sys/kernel/randomize_va_space
Disable ASLR (temp)
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Enable ASLR (full)
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
Disable for one run
setarch \
arch` -R ./binary`

Understanding ASLR Values

  • 0: No randomization (everything static)
  • 1: Conservative (libraries, stack, mmap, VDSO randomized)
  • 2: Full (plus brk() memory randomized)

Bypass Techniques

1. Brute-Force (32-bit)

On 32-bit systems, entropy is limited:

  • Stack: ~11 bits effective (524,288 possible addresses)
  • Code/data: 16 bits
  • mmap/libraries: 16 bits

Approaches:

  • Use large NOP sleds and retry until execution lands on them
  • Add shellcode in environment variables for local exploits
  • Brute-force libc base addresses
  • For remote servers: time-based detection (e.g.,
    usleep(10)
    causes 10s delay when hit)

Use the script:

scripts/brute_force_stack.py
for automated stack brute-forcing

2. Brute-Force (64-bit)

64-bit has much higher entropy, but you can:

  • Fill stack with environment variables
  • Retry hundreds/thousands of times locally
  • Target specific stack addresses that occasionally contain NOPs

Use the script:

scripts/brute_force_stack.py
with appropriate architecture settings

3. Information from
/proc/[pid]/stat

When you have local access to the target machine,

/proc/[pid]/stat
reveals:

  • startcode
    /
    endcode
    : TEXT segment boundaries
  • startstack
    : Stack start address
  • start_data
    /
    end_data
    : BSS boundaries
  • kstkesp
    /
    kstkeip
    : Current ESP/EIP
  • arg_start
    /
    arg_end
    : Command line arguments
  • env_start
    /
    env_end
    : Environment variables

Use the script:

scripts/read_proc_stat.py
to parse and extract addresses

4. Using Information Leaks

If the challenge provides a leak:

Given libc leak:

from pwn import *

elf = context.binary = ELF('./vuln')
libc = elf.libc
p = process()

# Receive leak
p.recvuntil('at: ')
system_leak = int(p.recvline(), 16)

# Calculate libc base
libc.address = system_leak - libc.sym['system']

# Build payload
payload = flat(
    'A' * offset,
    libc.sym['system'],
    0x0,
    next(libc.search(b'/bin/sh'))
)

p.sendline(payload)
p.interactive()

ret2plt leak: Use buffer overflow to call a function and leak its GOT entry address

Format string leak: Use format string vulnerability to read GOT entries

5. Fixed Addresses (No Leak Needed)

vsyscall

The

vsyscall
page has a fixed address not subject to ASLR:

  • Address:
    0xffffffffff600000
    (x86_64)
  • Contains syscall stubs and a
    ret
    instruction
  • Can be used in ROP chains without leaking

Example gadget at

0xffffffffff600809
:
ret
instruction

vDSO

The

vDSO
(virtual dynamic shared object) may have predictable addresses depending on kernel configuration:

  • Check if kernel has
    CONFIG_COMPAT_VDSO
  • Address may not be randomized in some configurations

KASLR on ARM64 (Android)

On many ARM64 Android kernels, the linear map base is fixed:

PAGE_OFFSET = 0xffffff8000000000
PHYS_OFFSET = memstart_addr (from /proc/kallsyms)
Translation: virt = ((phys - PHYS_OFFSET) | PAGE_OFFSET)

Exploitation:

  1. grep memstart /proc/kallsyms
    to find
    memstart_addr
  2. Read 8 bytes at that address (little-endian) to get
    PHYS_OFFSET
  3. Calculate virtual addresses:
    virt = ((phys - PHYS_OFFSET) | 0xffffff8000000000)

This breaks KASLR for targets reachable via the direct map.

Scripts

Check ASLR Status

./scripts/check_aslr.sh

Toggle ASLR

./scripts/toggle_aslr.sh enable   # Set to 2 (full)
./scripts/toggle_aslr.sh disable  # Set to 0 (off)

Brute-Force Stack

./scripts/brute_force_stack.py ./binary --arch x86_64 --max-attempts 10000

Parse Process Stat

./scripts/read_proc_stat.py <pid>

When to Use Each Technique

ScenarioRecommended Approach
Local testing/debuggingDisable ASLR temporarily
32-bit binary, localBrute-force with NOP sled
32-bit binary, remoteTime-based detection (usleep)
64-bit binary, localBrute-force with env vars
Have info leakCalculate offsets from leak
No leak, x86_64Use vsyscall fixed addresses
Android ARM64Exploit fixed linear map
Local access to targetRead /proc/[pid]/stat

Important Notes

  • 64-bit brute-forcing is impractical for remote targets due to high entropy
  • Always test locally first before attempting remote exploitation
  • ASLR changes are temporary unless written to
    /etc/sysctl.conf
  • vsyscall/vDSO addresses vary by architecture and kernel version
  • KASLR bypass on Android requires kernel read primitive or root

References