ConvertFrom-Bearertoken

Nutzen Sie zur Analyse eines Bearer-Token auch Webseiten wie https://jwt.io oder https://jwt.ms? Offizielle decodieren diese beiden Seiten die übergebenen Buchstabenwürmer lokal per JavaScript. Sie könnten so ein Token aber natürlich auch genauso schnell ausleiten und hätten damit vielleicht sehr umfangreiche Rechte. Daher habe ich mir mal angeschaut, wie ich verschiedene Tokens einfach per PowerShell auseinander nehmen kann. Es sollte ja auch nur BASE64-codierte Strings sein.

Token Sicherheit

Ein Bearer-Token ist wie ein Flugticket oder ein Bahnticket. Es wurde von einer autorisierten Quelle ausgestellt, enthält einige Informationen zum Nutzer und dem Einsatzzweck und ist irgendwie gegen Fälschungen geschützt. Bem Papierticket der Bahn soll das Papier mit dem Silberrand einen Schutz gewähren. E-Tickets können mit dem Personalausweis geprüft werden. Der Passagier ist namentlich hinterlegt und die Fahrt/Flug-strecke und der Gültigkeitszeitraum sind aufgedruckt.

Bei einem Bearer-Token ist dies nicht viel anders. Der Inhaber ist meist über den UPN und teilweise noch weitete Gruppenmitgliedschaften und Berechtigungs-Informationen hinterlegt, Die Gültigkeit ist durch einen Start und Ende-Zeitpunkt vorgegeben und das ganze Token ist digital signiert, damit es nicht verändert werden kann.

Dennoch sollten Sie nie vergessen, dass dieses Ticket dem Besitzer während der Gültigkeit den Zugriff erlaubt. Es gibt erst einmal keine weitere Bindung mehr an das Endgerät oder die Verbindung

Daher sollten Sie ein Bearer-Token zumindest während der Gültigkeit genauso schützen wie jede anderen Zugangsdaten.

Woher bekomme ich ein Token?

Um die folgenden Schritte mit eigenen Tokens nachzuvollziehen, können Sie auf mehrere Wege an ein Token zur Analyse kommen:

  • PowerShell/MSAL
    Wenn Sie z.B. per PowerShell eine Anmeldung an Microsoft Graph unter Nutzung von MSAL, ADAL, MSADAL oder eigenen Code durchführen, dann haben Sie in der Regel ein Bearer-Token vom OAUTH-Server bekommen. Dieses Token senden Sie ja im Authorization-Header beim nächsten HTTP-Request wieder an den Service.
  • Graph Token
    So komme ich an ein Token zur Nutzung mit Graph
  • Fiddler
    Eine zweite Möglichkeit besteht im Belauschen einer Verbindung mittels Tools wie Fiddler. Fiddler schaltet sich als HTTP-Proxy in die Verbindung und erlaubt ihnen die HTTP-Requests und Antworten zu sehen
  • IIS Failed Request Tracing
    Auf auf dem Webserver können Sie z.B. bestimmte Requests mitschneiden. Sei es als Trace oder indem Sie den "Authorization"-Header mit in das IIS-Log schreiben lassen.

Es ist also gar nicht so schwer, so ein Bearer-Token als Benutzer oder Administrator abzugreifen. Nur auf dem Netzwerk selbst ist es kaum möglich, sofern Sie zwingend eine TLS-Verbindung, (TLS Security), am besten per TLS 1.2 Enforcement nutzen. Das Token ist letztlich aber einfach ein String im "Authorization"-Header. Es könnte aber auch sein, dass eine Anwendung solche Tokens auch in Das Payload, z.B. einer JSON-Datenstruktur überträgt.

Start mit "eyJ.." und dann?

Das Bearer-Token ist in allen Fällen die ich bisher untersucht habe, eine JSON-Datenstruktur und BASE64 codiert. Da das erste Zeichen ein "{" ist, startet damit auch ein Bearer-Token quasi immer mit einem "ey" als erste Zeichen.

Eine direkte BASE64 Decodierung wird aber nicht immer funktionieren, denn BASE64 codiert JSON-Tokens werden noch mit anderen Umsetzungen versehen, damit Sie gängige HTTP-Protokolle nicht stören. Legitime Zeichen für BASE64 sind eigentlich nur A-Za-z0-9+/ und am Ende zum Auffüllen das "=". Allerdings sind bei URLs die Zeichen "+","/" und =" gerade nicht erlaubt und werden durch "-","_" und "%3d" ersetzt.

Für unsere Decodierung bedeutet dies:

  • Trenne beim "."
    Ich habe gerade bei POP-Token gesehen, dass auch mehrere Tokens mit einem "." aneinander gehängt werden.
  • Prüfe den Anfang auf "eyJ"
    Der Anfang eines Bearer-Tokens ist ein "{" und muss in BASE64 dann ein "eyJ" sein.
  • Ersetze alle "-" durch "+", "_" durch "/" und "%3d" durch "="
    Damit drehen wir alle "HTTP-Ersetzungen wieder zurück
  • Runde mit "=" auf bis "Modulo 4 =0 "
    Wenn die Länge des Strings bekannt ist, kann ein BASE64-Encoder auch die Füllzeichen am Ende weglassen.

Die .NET-Klasse zum BASE64-Decodieren ist aber hier streng.

Decoding in Einzelschritten

Ich habe ein POP-Token von Exchange Online an meinen Exchange OnPremises Server bereitgestellt, welches natürlich schon lange abgelaufen ist. Im folgenden Skript ist es als "Parameter" direkt vorgegeben. Ansonsten akzeptiert das Skript natürlich den Text-String entweder als Parameter oder über die Pipeline. Die Decodierung ist relativ einfach zu verstehen.

Dies ist nur ein Ausschnitt und zeigt die eigentliche Decodierung:

Zeile Funktion

23-26

Ich prüfe, ob es sich überhaupt mal um eine BASE64-kodiertes Token handeln kann

28

Ersetze alle drei Zeichen die nicht im BASE64-Text vorkommen dürfen durch die korrekten Zeichen.

30-33

Wenn die Länge des String nicht durch 4 teilbar ist, muss ich "=" als Füllzeichen addieren

35

Nun konvertieren wir die Zeichen in ein binäres Byte-Array. Hier habe ich keine Fehlerbehandlung addiert.

37

Aus dem Byte-Array machen wir nun einen String

38

Der dann noch mit "ConvertFrom-JSON" in ein Powershell-Objekt konvertiert wird.

Wenn Sie das Beispielskript einfach so aufrufen, dann sollte der Code drei Abschnitts finden, von denen aber die Signatur nicht verarbeitet wird. Das erste JSON-Objekt hat nur die Properties "alg, kid und typ"

Das zweite Objekt ist deutlich größer und sie erkennen es wohl schon: Es enthält erneut ein Token. Durch die Funktion der Pipeline können wir dies einfach noch einmal decodieren, indem wir das Property "AT" noch einmal an das Skript senden:

Die einzelnen Felder habe ich nun nicht weiter decodiert. Das ist dann Aufgabe der Applikation. Felder wie "appid" erschließen sich selbst. Ansonsten gibt es Seiten, die die Bedeutung aufschlüsseln.

Interessant sind hier vielleicht noch die Felder "iat" (IssuedAt), "nbf" (NotBefore), "exp" (Expired), die in Sekunden seit 11.1.1970 gezählt werden und damit auch per Powershell einfach zu konvertieren sind.

PS C:> (Get-Date 01.01.1970).addseconds(1724880516)

Mittwoch, 28. August 2024 21:28:36

PS C:> (Get-Date 01.01.1970).addseconds(1724967216)
Donnerstag, 29. August 2024 21:33:36

Dieses Ticket war also etwas mehr als 24h gültig.

Das zweite Ticket, welches im Feld "PFT" gespeichert ist, ist auch schon abgelaufen.

Damit ist eigentlich auch klar, dass die Sicherheit des Tokens nicht weiter erforderlich ist, wenn es abgelaufen ist. Natürlich können Sie nun hier sehen, dass "Etwas" am 28. August 2024 ein Token für den Benutzer FCDEMO1 mit den Rechen "user_impersonation" zum Zugriff auf "api.spaces.skype.com" angefordert und erhalten hat. Das hat aber den gleichen Stellenwert, wie ein abgelaufener Zugfahrschein im Mülleimer.

Anders sieht es natürlich für noch gültige Tickets aus. Ob Sie diese aus "Decodier-Webseiten" einfach so auswerten lassen, müssen Sie selbst bewerten. https://jwt.io oder https://jwt.ms haben zumindest Ende April 2024 tatsächlich alle Tokens "lokal" im Browser decodiert und nicht nach extern ausgeleitet.

Das bedeutet aber nicht, dass dies immer so ist oder eine Malware sich nicht vielleicht in einem Browser-PlugIn versteckt oder die Informationen beim Kopieren über die Zwischenablage abgreift.

Das Skript

Das Skript zum Decodieren von Bearer-Tokens haben ich hier zum Download bereitgestellt. Wie bei PowerShell üblich, können Sie einfach den Quellcode anschauen, ob er das hält, was ich versprochen habe.

convertfrom-bearertoken.ps1.txt

Nach dem Download müssen Sie die Datei als PS1-Datei speichern und ggfls. noch über "Unlock-File" oder den Windows Explorer freischalten, da Sie ja aus dem Internet gekommen und nicht digital signiert ist.

Weitere Links