如何从 Kubernetes 节点权限提升至集群管理员权限?
我有幸参加了去年的 KubeCon 并分享议题,议题的其中一个攻防案例讲述了如何从一个边缘业务的开发者权限逐步提升至 Kubernetes 集群管理员权限;其中最后一步的手法,是描述关于节点上利用 DaemonSet 和 Pod 上的 ServiceAccount token 进行提权,那一年我在补天上的议题也简述了这个手法。在今年的 KubeCon 欧洲上,这样的攻击手法被命名为了"蹦床"。快速过完国外的这篇 slide 之后,深感他们研究的细致和用心,对比我去年的形色匆匆熬夜赶稿,他们倾注了更多的时间和资源,完成了我的很多遗憾和不甘;也让我重拾了这块研究的很多记忆
我有幸参加了去年的 KubeCon 并分享议题,议题的其中一个攻防案例讲述了如何从一个边缘业务的开发者权限逐步提升至 Kubernetes 集群管理员权限;其中最后一步的手法,是描述关于节点上利用 DaemonSet 和 Pod 上的 ServiceAccount token 进行提权,那一年我在补天上的议题也简述了这个手法。在今年的 KubeCon 欧洲上,这样的攻击手法被命名为了"蹦床"。快速过完国外的这篇 slide 之后,深感他们研究的细致和用心,对比我去年的形色匆匆熬夜赶稿,他们倾注了更多的时间和资源,完成了我的很多遗憾和不甘;也让我重拾了这块研究的很多记忆
AppSheet 中的 SSRF 漏洞 - Google VRP
Webhook 中的 SSRF
我研究了 AppSheet 的功能,发现了一个名为 Workflows 的部分(今天被“AppSheet Bots”取代)。AppSheet Workflow 通过定义特定规则实现了应用程序行为的自动化。例如 - 当用户在表中创建新行时发送电子邮件通知。定义这些规则有多种选项。其中一个选项是在规则触发器上调用 webhook。这听起来很有希望,所以我研究了这个功能
我创建了一个新的工作流,规则如下:当表中的数据发生变化时调用 webhook。我尝试做的第一件事就是调用元数据 API。但是,我遇到了第一个问题。没有创建 GET 请求的选项,而这是获取元数据所必需的(至少我是这么认为的)。我只能使用 POST、DELETE 和 PATCH 发出请求。经过一段时间的思考和谷歌搜索,我想到了一个主意,那就是使用重定向从 POST 创建 GET 请求。
在 HTTP重定向文档中,我发现某些重定向类型“可能会或可能不会”将 HTTP 方法更改为 GET。我用一些 HTTP 客户端和库进行了测试,实际上,它们都将方法更改为 GET。这正是我需要的。
因此,在我拥有的域名上,我创建了一个 301 重定向(使用 Location 标头):
Webhook 中的 SSRF
我研究了 AppSheet 的功能,发现了一个名为 Workflows 的部分(今天被“AppSheet Bots”取代)。AppSheet Workflow 通过定义特定规则实现了应用程序行为的自动化。例如 - 当用户在表中创建新行时发送电子邮件通知。定义这些规则有多种选项。其中一个选项是在规则触发器上调用 webhook。这听起来很有希望,所以我研究了这个功能
我创建了一个新的工作流,规则如下:当表中的数据发生变化时调用 webhook。我尝试做的第一件事就是调用元数据 API。但是,我遇到了第一个问题。没有创建 GET 请求的选项,而这是获取元数据所必需的(至少我是这么认为的)。我只能使用 POST、DELETE 和 PATCH 发出请求。经过一段时间的思考和谷歌搜索,我想到了一个主意,那就是使用重定向从 POST 创建 GET 请求。
在 HTTP重定向文档中,我发现某些重定向类型“可能会或可能不会”将 HTTP 方法更改为 GET。我用一些 HTTP 客户端和库进行了测试,实际上,它们都将方法更改为 GET。这正是我需要的。
因此,在我拥有的域名上,我创建了一个 301 重定向(使用 Location 标头):
http://<MY_DOMAIN>/<ROUTE>到http://169.254.169.254/<ROUTE>
预期的行为是 AppSheet HTTP 客户端将 POST 方法更改为 GET:
POST http://<MY_DOMAIN>/<ROUTE>到GET http://169.254.169.254/<ROUTE>
我在具有以下设置的 webhook 中使用了此重定向(请求指向旧式元数据 API):
发布 http://<我的域>/computeMetadata/v1beta1/instance/service-accounts/default/token
我保存了工作流程并通过在 AppSheet 应用程序的表中添加新行来触发操作。
几分钟后,我打开应用程序日志并找到了 webhook 调用的记录。日志显示了来自元数据服务器的响应主体。响应中包含 AppSheet 应用程序的访问令牌。
CVE-2022-0778
发现的漏洞会BN_mod_sqrt()在解析椭圆曲线密钥时触发 OpenSSL 函数中的无限循环。这意味着恶意制作的 X.509 证书可以对任何未打补丁的服务器实施 DoS 攻击。
该漏洞的核心在于解析压缩格式的点的 EC 密钥:解析此类密钥时,OpenSSL 将尝试扩展压缩点,尝试计算p定义曲线的素数的平方根模数。但是,在任何地方都不会检查素数p,即使在要求素数的情况下也不会BN_mod_sqrt();因此,实现中的错误将导致无限循环,因为p不是预期的素数
函数BN_mod_sqrt()实现了求模平方根的Tonelli-Shanksa算法,即给定一个整数和一个素数p,返回一个值r使得r^2 == a (mod p)。
通过分析修补漏洞的提交i,我们发现罪魁祸首是寻找最小索引的循环b^(2^i)==1 (mod p),其中b已经在算法中定义过。
发现的漏洞会BN_mod_sqrt()在解析椭圆曲线密钥时触发 OpenSSL 函数中的无限循环。这意味着恶意制作的 X.509 证书可以对任何未打补丁的服务器实施 DoS 攻击。
该漏洞的核心在于解析压缩格式的点的 EC 密钥:解析此类密钥时,OpenSSL 将尝试扩展压缩点,尝试计算p定义曲线的素数的平方根模数。但是,在任何地方都不会检查素数p,即使在要求素数的情况下也不会BN_mod_sqrt();因此,实现中的错误将导致无限循环,因为p不是预期的素数
函数BN_mod_sqrt()实现了求模平方根的Tonelli-Shanksa算法,即给定一个整数和一个素数p,返回一个值r使得r^2 == a (mod p)。
通过分析修补漏洞的提交i,我们发现罪魁祸首是寻找最小索引的循环b^(2^i)==1 (mod p),其中b已经在算法中定义过。
Oracle Access Manager 预授权 RCE(CVE-2021-35587 分析)
您可能知道,Oracle Access Manager (OAM) 是一款流行的 SSO 产品,被 Oracle、VMware、华为、高通等多家大公司使用……
这个漏洞是我和Peterjson在分析和构建另一个超级 0day(现在还没有修复 ;))的 PoC 时偶然发现的。
访问入口点并利用漏洞非常容易,因此建议立即应用补丁!它可能使攻击者能够访问 OAM 服务器,创建具有任何权限的任何用户,或者只是在受害者的服务器中执行代码。
您可能知道,Oracle Access Manager (OAM) 是一款流行的 SSO 产品,被 Oracle、VMware、华为、高通等多家大公司使用……
这个漏洞是我和Peterjson在分析和构建另一个超级 0day(现在还没有修复 ;))的 PoC 时偶然发现的。
访问入口点并利用漏洞非常容易,因此建议立即应用补丁!它可能使攻击者能够访问 OAM 服务器,创建具有任何权限的任何用户,或者只是在受害者的服务器中执行代码。
日志、监控和故障排除
您可以随时监控系统的资源使用情况、正常运行时间和会话的负载杠杆率
用于lscpu查看系统的 CPU 使用情况和其他详细信息。
系统事件和进程的踪迹通常以日志的形式保存在/var/log目录中。日志分为两类:1. 通过 保存的基本系统日志journald,默认情况下,这些日志会在启动时被清除(可以配置为持久保存)。2.rsyslog默认情况下持久保存并组织在文件夹内的日志/var/log/。Linux 中的日志记录机制主要遵循syslog系统消息、事件、安全事件、邮件和作业日志的标准协议,而其他程序可能遵循或不遵循syslog相同的格式
您可以随时监控系统的资源使用情况、正常运行时间和会话的负载杠杆率
用于lscpu查看系统的 CPU 使用情况和其他详细信息。
系统事件和进程的踪迹通常以日志的形式保存在/var/log目录中。日志分为两类:1. 通过 保存的基本系统日志journald,默认情况下,这些日志会在启动时被清除(可以配置为持久保存)。2.rsyslog默认情况下持久保存并组织在文件夹内的日志/var/log/。Linux 中的日志记录机制主要遵循syslog系统消息、事件、安全事件、邮件和作业日志的标准协议,而其他程序可能遵循或不遵循syslog相同的格式
os.path.join工作原理
我们想提醒大家注意os.path.join在某些情况下函数的使用不安全。即使用户输入已被过滤,并且“ ..”字符串已被删除以防止路径遍历,在第二个参数中仍有可能使用所需目录的绝对路径。
通常,即使有可能上传恶意文件以获取任意远程代码执行,也需要完全重新启动 Python Web 应用程序才能获取此新代码。不幸的是,对于 VMware 来说,这次WSGIScriptAliashttpd 配置中的别名意味着脚本不会被缓存,并且会在每次用户请求 URL 时加载到内存中并执行/logupload。
考虑到这一点,我们决定log_upload_wsgi.py用自己的恶意代码覆盖原始脚本。我们只有一次尝试上传有效的 Python 脚本的机会,否则我们将破坏 Web 应用程序。我们用 Python 语言创建了一个 WSGI Web Shell,并尝试将其上传到/etc/httpd/html/wsgi_log_upload/名为log_upload_wsgi.pyfilename 的文件夹中
我们想提醒大家注意os.path.join在某些情况下函数的使用不安全。即使用户输入已被过滤,并且“ ..”字符串已被删除以防止路径遍历,在第二个参数中仍有可能使用所需目录的绝对路径。
通常,即使有可能上传恶意文件以获取任意远程代码执行,也需要完全重新启动 Python Web 应用程序才能获取此新代码。不幸的是,对于 VMware 来说,这次WSGIScriptAliashttpd 配置中的别名意味着脚本不会被缓存,并且会在每次用户请求 URL 时加载到内存中并执行/logupload。
考虑到这一点,我们决定log_upload_wsgi.py用自己的恶意代码覆盖原始脚本。我们只有一次尝试上传有效的 Python 脚本的机会,否则我们将破坏 Web 应用程序。我们用 Python 语言创建了一个 WSGI Web Shell,并尝试将其上传到/etc/httpd/html/wsgi_log_upload/名为log_upload_wsgi.pyfilename 的文件夹中