Send()-ing Myself Belated Christmas Gifts - GitHub.com’s Environment Variables & GHES Shell
Backstory
2023年12月初,我在研究GitHub Enterprise Server(GHES)时发现了一个潜在的小漏洞。直到圣诞节后,我才找到时间分析这个漏洞,当时我完全没想到它会有如此大的影响。
A Quick Primer on Ruby Reflections
与JavaScript类似,Ruby中几乎所有东西(如布尔值、字符串、整数)都是对象。Object包含了Kernel模块作为混入,使得Kernel模块中的方法可以被每个Ruby对象访问。值得注意的是,可以使用Kernel#send()进行反射(即间接方法调用):
|
|
如上所示,可以使用Kernel#send()动态调用方法,对任何对象执行反射。
Discovering the Vulnerability
在代码库中快速搜索后,我在Organizations::Settings::RepositoryItemsComponent(位于app/components/organizations/settings/repository_items_component.rb)中发现了一个未经验证的Kernel#send()调用:
|
|
在[1]处,repository.send(@repository_identifier_key)在identifier_for()方法中被调用,没有对@repository_identifier_key(在[2]处设置)进行任何先前的输入验证。这允许调用对象可访问的所有方法(包括私有或受保护的方法,以及从祖先类继承的任何其他方法)。
In Search of Impact
这不是仅限于从Object继承的方法——我们可以通过查看Repository对象可访问的方法来扩展候选方法的搜索。
关于"零参数任意方法调用"的假设:我们实际上可以调用需要参数的方法——只要它们有默认值!
Getting the Environment Variables
在Repository::GitDependency模块(位于packages/repositories/app/models/repository/git_dependency.rb)中,包含了危险方法nw_fsck():
|
|
这个nw_fsck()方法非常不起眼,但包含了丰富的信息。GitRPC::Native.spawn()返回一个包含传递给git进程的环境变量的Hash对象,而Repository::GitDependency#nw_fsck()将这个Hash返回给我们,使我们能够泄露传递给Rails的所有环境变量!
The Actual Impact
我无意中获得了总共1220个环境变量(约2MB),包含大量生产访问密钥。我立即停止测试,联系GitHub人员提醒他们这一事件,并在不久后提交了漏洞报告。
Getting Remote Code Execution (RCE)
环境变量列表包括ENTERPRISE_SESSION_SECRET,该密钥用于签名存储在会话cookie中的序列化数据。如先前在@iblue的GitHub Enterprise管理控制台远程代码执行中演示的那样,了解ENTERPRISE_SESSION_SECRET值允许攻击者签名任意序列化数据。
Ruby on Rails使用加密签名的序列化Ruby Hash实现会话存储。这个Hash使用Marshal.dump序列化为cookie,随后使用Marshal.load反序列化。如果攻击者可以构造有效签名,他们可以创建一个包含传递给Marshal.load的任意输入的会话cookie。根据Ruby文档对Marshal.load的说明,这可能导致代码执行。
Exploit Conditions
此漏洞影响GitHub.com和任何启用了GitHub Actions的GitHub Enterprise Server。攻击者还需要拥有组织所有者角色。
Suggested Mitigations
- 在Orgs::ActionsSettings::RepositoryItemsController类中针对允许列表验证rid_key参数,确保只能调用Repository类的预期方法
- 撤销并重新生成GitHub.com/任何可能已受损的GitHub Enterprise Server中使用的所有密钥
- 考虑使用功能所需的最小环境变量集来生成git进程
Detection Guidance
可以通过检查服务器的访问日志来检测此漏洞的利用情况,查找设置了异常rid_key参数值的所有对/organizations/<organization_name>/settings/actions/repository_items的请求。
Timeline
- 2023-12-26 供应商披露
- 2023-12-26 初始供应商联系
- 2023-12-26 在Github.com生产服务器上热修复
- 2023-12-28 向供应商发送RCE报告
- 2024-01-16 供应商补丁和公告发布
- 2024-05-06 公开发布
Closing Thoughts
遗憾的是,这个漏洞在一个非常不合时宜的时间(圣诞节后)被发现和利用。我要向所有在圣诞/新年节日期间工作的Hubbers表示诚挚的歉意和感激,因为这个错误报告为他们创建的工作量一定非常巨大。然而,看到他们快速修补这个漏洞,轮换所有密钥(一个非常痛苦的过程),以及运行并得出结论确认此漏洞先前未在野外被利用,令人印象深刻。