# RDS Database Enumeration

> Techniques for enumerating AWS RDS instances, snapshots, subnet groups, and security configurations to identify exposed databases and misconfigurations.

- **URL:** https://hackindex.io/platforms/aws/enumeration/rds/rds-database-enumeration
- **Path:** AWS > Enumeration > RDS
- **Up:** [RDS](https://hackindex.io/platforms/aws/enumeration/rds.md)
- **Published:** 2026-05-24
- **Updated:** 2026-05-24

RDS hosts managed relational databases on AWS. During enumeration, identify which instances exist, whether they are reachable, and where credentials are stored. Start with instance listing to understand network exposure. Then check snapshots, subnet placement, and parameter groups.

## List DB Instances

```bash
aws rds describe-db-instances --profile $PROFILE --region $REGION --query 'DBInstances[*].{ID:DBInstanceIdentifier,Engine:Engine,Version:EngineVersion,Public:PubliclyAccessible,Encrypted:StorageEncrypted,Endpoint:Endpoint.Address,Port:Endpoint.Port,Status:DBInstanceStatus}' --output table
```

Key fields: `PubliclyAccessible` and `Endpoint.Address`. A publicly accessible instance with a security group open to `0.0.0.0/0` is directly reachable from the internet. Check the `Status` column: `available` means the instance is running. Note the engine and version. Older engine versions may have known CVEs worth noting for vulnerability discovery. The endpoint address is the hostname for direct connection. If `PubliclyAccessible` is `false`, the instance sits inside a VPC. Reaching it requires network access via a bastion, VPN, or a compromised EC2 instance in the same subnet. Instances with `Encrypted: false` indicate storage encryption is off. That matters if you later access snapshots or backups.

## Snapshots

Snapshots are point-in-time copies of the database. They can be shared across AWS accounts, including publicly. A public snapshot is a direct path to a full database copy without needing credentials to the live instance. List manual and automated snapshots:

```bash
aws rds describe-db-snapshots --profile $PROFILE --region $REGION --query 'DBSnapshots[*].{ID:DBSnapshotIdentifier,DB:DBInstanceIdentifier,Engine:Engine,Status:Status,Encrypted:Encrypted,Public:SnapshotType}' --output table
```

**Check for public snapshots**

```bash
aws rds describe-db-snapshots --profile $PROFILE --region $REGION --include-public --query 'DBSnapshots[?SnapshotType==`public`]'
```

Public RDS snapshots can be restored by any AWS account. They frequently contain full database dumps with credentials and application data. To exploit a public snapshot, restore it into an attacker-controlled account and connect directly. The restore takes a few minutes. The resulting instance has no credential barrier beyond AWS account access. This is a high-impact finding when the snapshot belongs to a production database.

## Cluster Snapshots (Aurora)

Aurora uses a cluster-based architecture. Snapshots apply at the cluster level rather than per instance. The same public-sharing risk applies. Check for public cluster snapshots using the cluster-specific API call below.

```bash
aws rds describe-db-cluster-snapshots --profile $PROFILE --region $REGION --include-public --query 'DBClusterSnapshots[?SnapshotType==`public`]'
```

## DB Subnet Groups

The output reveals the VPC ID, subnet IDs, and availability zones for each RDS deployment. Use subnet IDs to cross-reference routing tables and network ACLs. A subnet that routes to an internet gateway may expose the database even if `PubliclyAccessible` is false. Check ACL rules to confirm the actual exposure. Subnet group membership reveals which EC2 instances share the same network segment. Those instances can reach the database without crossing a security group boundary.

```bash
aws rds describe-db-subnet-groups --profile $PROFILE --region $REGION
```

## Parameter Groups

Parameter groups store DB engine configuration. Some parameters expose attack surface. On MySQL, check for settings that allow outbound connections or enable UDF loading. Log-related parameters reveal whether query activity is captured, which affects OPSEC. Get the parameter group name from the `describe-db-instances` output and run this for each instance:

```bash
aws rds describe-db-parameters --db-parameter-group-name $PARAM_GROUP --profile $PROFILE --region $REGION
```

For MySQL/MariaDB, `general_log` and `slow_query_log` settings indicate whether query logging is active. `log_output=FILE` means logs go to the filesystem. If both are off, query activity on the database is not captured at the engine level. For PostgreSQL, check `log_statement` and `log_connections`. Also look at `max_connections` to understand usage patterns. A database near its connection limit is a potential denial-of-service condition worth noting.

## Master Credentials Location

RDS master passwords are not stored in the RDS API. They are typically in:

- Secrets Manager (`aws secretsmanager list-secrets`)
- SSM Parameter Store (`aws ssm describe-parameters`)
- Environment variables of the application (Lambda, ECS, EC2 user data)

Check all three. Secret names in Secrets Manager often follow a pattern like `/rds/instance-name/password` or include the instance identifier. In SSM, RDS credentials frequently appear as `SecureString` parameters. Application environment variables sometimes contain credentials in plaintext. This is common in older ECS task definitions and Lambda configurations that predate Secrets Manager adoption. See [Secrets Manager and SSM Parameter Store Enumeration](https://hackindex.io/platforms/aws/enumeration/secrets/secrets-manager-and-ssm-parameter-store-enumeration).

## Security Group Check

Get the security group IDs from the `describe-db-instances` output. Run this for each group. Look for rules with `IpRanges` containing `0.0.0.0/0` or `::/0`, which allow inbound access from anywhere. Also check for rules scoped to another security group. Those reveal which EC2 instances or services are permitted to connect.

```bash
aws ec2 describe-security-groups --group-ids $SG_ID --profile $PROFILE --region $REGION --query 'SecurityGroups[*].IpPermissions'
```

Port `3306` (MySQL), `5432` (PostgreSQL), `1433` (MSSQL), `1521` (Oracle) open to `0.0.0.0/0` means direct internet access to the database. When you find an open port, attempt a connection with a database client to confirm reachability. Without credentials you cannot authenticate, but you confirm the path exists. Note the engine and port. Then pivot to Secrets Manager, SSM, and application environment variables before attempting any brute-force. A database exposed to the internet with a weak or default password is a critical finding.
