GCP - Token Persistance

Apoya a HackTricks

Tokens de Usuario Autenticados

Para obtener el token actual de un usuario, puedes ejecutar:

sqlite3 $HOME/.config/gcloud/access_tokens.db "select access_token from access_tokens where account_id='<email>';"

Consulta en esta página cómo usar este token directamente usando gcloud:

Para obtener los detalles para generar un nuevo token de acceso, ejecuta:

sqlite3 $HOME/.config/gcloud/credentials.db "select value from credentials where account_id='<email>';"

También es posible encontrar tokens de actualización en $HOME/.config/gcloud/application_default_credentials.json y en $HOME/.config/gcloud/legacy_credentials/*/adc.json.

Para obtener un nuevo token de acceso actualizado con el token de actualización, el ID de cliente y el secreto de cliente, ejecuta:

curl -s --data client_id=<client_id> --data client_secret=<client_secret> --data grant_type=refresh_token --data refresh_token=<refresh_token> --data scope="https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/accounts.reauth" https://www.googleapis.com/oauth2/v4/token

La validez de los tokens de actualización se puede gestionar en Admin > Security > Google Cloud session control, y por defecto está configurada para 16h, aunque se puede establecer para que nunca expire:

Flujo de autenticación

El flujo de autenticación al usar algo como gcloud auth login abrirá un aviso en el navegador y después de aceptar todos los alcances, el navegador enviará una solicitud como esta al puerto http abierto por la herramienta:

/?state=EN5AK1GxwrEKgKog9ANBm0qDwWByYO&code=4/0AeaYSHCllDzZCAt2IlNWjMHqr4XKOuNuhOL-TM541gv-F6WOUsbwXiUgMYvo4Fg0NGzV9A&scope=email%20openid%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/cloud-platform%20https://www.googleapis.com/auth/appengine.admin%20https://www.googleapis.com/auth/sqlservice.login%20https://www.googleapis.com/auth/compute%20https://www.googleapis.com/auth/accounts.reauth&authuser=0&prompt=consent HTTP/1.1

Luego, gcloud utilizará el estado y el código con un client_id codificado (32555940559.apps.googleusercontent.com) y client_secret (ZmssLNjJy2998hD4CTg2ejr2) para obtener los datos finales del token de actualización.

Ten en cuenta que la comunicación con localhost es en HTTP, por lo que es posible interceptar los datos para obtener un token de actualización; sin embargo, estos datos son válidos solo 1 vez, por lo que esto sería inútil, es más fácil simplemente leer el token de actualización del archivo.

Alcances de OAuth

Puedes encontrar todos los alcances de Google en https://developers.google.com/identity/protocols/oauth2/scopes o obtenerlos ejecutando:

curl "https://developers.google.com/identity/protocols/oauth2/scopes" | grep -oE 'https://www.googleapis.com/auth/[a-zA-A/\-\._]*' | sort -u

Es posible ver qué alcances la aplicación que gcloud utiliza para autenticarse puede soportar con este script:

curl "https://developers.google.com/identity/protocols/oauth2/scopes" | grep -oE 'https://www.googleapis.com/auth/[a-zA-Z/\._\-]*' | sort -u | while read -r scope; do
echo -ne "Testing $scope         \r"
if ! curl -v "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=32555940559.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A8085%2F&scope=openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fappengine.admin+$scope+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fsqlservice.login+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcompute+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Faccounts.reauth&state=AjvFqBW5XNIw3VADagy5pvUSPraLQu&access_type=offline&code_challenge=IOk5F08WLn5xYPGRAHP9CTGHbLFDUElsP551ni2leN4&code_challenge_method=S256" 2>&1 | grep -q "error"; then
echo ""
echo $scope
fi
done

Después de ejecutarlo, se verificó que esta aplicación admite estos alcances:

https://www.googleapis.com/auth/appengine.admin
https://www.googleapis.com/auth/bigquery
https://www.googleapis.com/auth/cloud-platform
https://www.googleapis.com/auth/compute
https://www.googleapis.com/auth/devstorage.full_control
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/userinfo.email

es interesante ver cómo esta aplicación soporta el drive scope, lo que podría permitir a un usuario escalar de GCP a Workspace si un atacante logra forzar al usuario a generar un token con este scope.

Ver cómo abusar de esto aquí.

Cuentas de Servicio

Al igual que con los usuarios autenticados, si logras comprometer el archivo de clave privada de una cuenta de servicio, podrás acceder a ella generalmente tanto tiempo como desees. Sin embargo, si robas el token de OAuth de una cuenta de servicio, esto puede ser aún más interesante, porque, incluso si por defecto estos tokens son útiles solo por una hora, si la víctima elimina la clave API privada, el token de OAuth seguirá siendo válido hasta que expire.

Metadatos

Obviamente, mientras estés dentro de una máquina que se ejecute en el entorno de GCP, podrás acceder a la cuenta de servicio adjunta a esa máquina contactando el endpoint de metadatos (ten en cuenta que los tokens de OAuth a los que puedes acceder en este endpoint suelen estar restringidos por scopes).

Remediaciones

Algunas remediaciones para estas técnicas se explican en https://www.netskope.com/blog/gcp-oauth-token-hijacking-in-google-cloud-part-2

Referencias

Support HackTricks

Last updated