【安全漏洞】Emissary 的SSRF漏洞(CVE-2021-32639)发现过程

导语:通过在Emissary项目上运行标准的CodeQL查询集,我发现了之前报告的任意文件泄露(CVE-2021-32093)。


通过在Emissary项目上运行标准的CodeQL查询集,我发现了之前报告的任意文件泄露(CVE-2021-32093),但也发现了新的漏洞:

不安全的反序列化漏洞 (CVE-2021-32634);

服务器端请求伪造漏洞(CVE-2021-32639);

原始代码注入CVE (CVE-2021-32096)是由社区贡献的CodeQL查询标记的;

到目前为止,还可以通过默认的CodeQL查询发现反映的跨站点脚本漏洞(CVE-2021-32092)。

代码注入 (CVE-2021-32096)

起初我尝试在Emissary 5.9.0代码库上使用CodeQL脚本注入查询时,却没有得到任何结果。

在阅读源代码获取漏洞细节后,我确信我的查询正确地建模了javax.script.ScriptEngine.eval()接收,并且该源代码已经由默认的CodeQL JAX-RS库建模。然而,我意识到从不受信任的数据到脚本注入接收器的流不是“直接的”流。你可以通过查看代码流的方式来理解其原因。

用户数据进入应用程序的 JAX-RS 终端是:

getOrCreateConsole(request) 将调用 RubyConsole.getConsole() ,它会转到:

此代码启动一个运行 RubyConsole.run() 方法的新线程(因为它实现了 Java Runnable 接口):

但是,由于此时 stringToEval 为 null,因此该方法几乎会立即使用 wait() 方法暂停线程。

稍后,在 rubyConsolePost 中,我们可以找到以下代码:

这里是不受信任数据(request.getParameter(CONSOLE_COMMAND_STRING))进入应用程序并流入RubyConsole.evalAndWait()方法的地方。但是,evalAndWait()方法是:

没有对RubyConsole.eval()方法的实际调用,Ruby脚本在该方法中被计算,因此如果跟踪受感染的请求参数,你将在该方法中结束并到达受感染的跟踪的末尾。用户控制的命令只被分配给stringToEval字段,这似乎就到此为止了。然而,如果你仔细观察,你还会看到这个方法正在调用notifyAll()方法,这意味着这个方法将有效地激活被暂停的线程,该线程将依次运行以下表达式:

当rubyConsolePost方法被调用时,RubyConsole.run()会以一个null stringToEval执行,然后进入wait状态。

当调用 evalAndWait(commandString) 时,stringToEval 获取用户控制的脚本,然后恢复 RubyConsole.run() 方法,该方法将评估现在分配的 stringToEval。

因此,没有静态代码分析工具可以有效跟踪的直接数据流。不过,通过使用CodeQL感染步骤对Javawait/notify模式建模,我应该能够发现这个漏洞。

在此代码模式中,你可以看到两种不同类型的块:调用notify的同步块和调用wait的同步块。当同步发生在同一个对象上时,我想将notify块中的写入与wait块上相同字段的读取连接起来。这意味着我需要一个额外的污点步骤来连接这些原本断开连接的节点,以便 CodeQL 的污点跟踪可以桥接这种逻辑断开连接:

启用这个额外的感染步骤后,我成功地报告了这个漏洞:

令人惊叹的是,这个查询不是由GitHub CodeQL工程师开发的,而是由几个CodeQL社区成员贡献和改进的:

https://github.com/github/codeql/pull/2850;

https://github.com/github/codeql/pull/5349;

https://github.com/github/codeql/pull/5802;

这个社区贡献的查询正在进入标准查询集,并将很快提供给所有运行 GitHub 代码扫描的开源项目。

我还向 CodeQL 存储库贡献了我的notify/wait模式感染步骤,这可能很快就会为所有 CodeQL 用户启用同步字段之间的类似数据流分析!

任意文件泄露 (CVE-2021-32093)

CodeQL 发现了默认配置下的任意文件泄露,因此我不会评论此漏洞的详细信息,因为它已经在 SonarSource文章中进行了描述。

不安全的反序列化 (CVE-2021-32634)

CodeQL 默认查询还报告了三个不安全的反序列化操作。

第一个位于 WorkSpaceClientEnqueueAction REST 终端:

可以通过对 /WorkSpaceClientEnqueue.action 的经过身份验证的 POST 请求访问此终端。正如你在源代码中所读到的,表单参数 WorkSpaceAdapterWORK_BUNDLE_OBJ (tpObj) 在第 52 行被解码和反序列化。

幸运的是,这是一个身份验证后的漏洞,由于SonarSource报告修复了跨站请求伪造(CSRF)漏洞,因此无法通过CSRF代表已登录用户利用该漏洞。

CodeQL 还报告了另外两个当前未在代码中执行的不安全反序列化操作。然而,它们可能会在未来的版本中启用。

第一个起源于MoveToAction类,它没有被Jersey服务器公开。

MoveToAction:


MoveToAdapter:

PayloadUtil:

第二个方法来源于WorkSpaceAdapter类的inboundEnque方法。该漏洞需要调用inboundEnque(),但目前尚未执行该调用。

WorkspaceAdapter:


WorkspaceAdapter:

WorkspaceAdapter:


服务器端请求伪造 (CVE-2021-32639)

在CodeQL中发现这个漏洞得益于另一个社区的贡献。报告此漏洞的查询最初是由@lucha-bc和@porcupineyhair贡献的,并且已经被提升为任何CodeQL扫描使用的默认规则集。

该查询报告了两个服务器端请求伪造 (SSRF) 漏洞。第一个影响 RegisterPeerAction REST 终端。例如,以下请求将导致多个请求发送到位于 http://attacker:9999 的攻击者控制的服务器。

需要注意的重要一点是,一些伪造的请求是发送到 /emissary/Heartbeat.action 终端的未经身份验证的请求:

但是,也有经过身份验证的请求发送到攻击者控制的服务器上的 /emissary/RegisterPeer.action 终端:

SSRF 漏洞通常用于访问内部服务器或扫描内部网络,但在这种情况下,我想到了不同的漏洞利用场景。由于 SSRF 漏洞导致 Emissary 使用的 Apache HTTP 客户端发送一个带有摘要身份验证标头的经过身份验证的请求,因此从理论上讲,我可以诱使客户端切换到基本身份验证,从而泄漏服务器凭证。

要使用 Apache HTTP 客户端发送经过身份验证的请求,需要在凭据提供程序上设置凭据,然后配置 HTTP 客户端以使用该凭据提供程序:


可以看到凭据是从 Jetty 用户领域读取的,用于连接到需要凭据的任何主机和任何端口。这些凭证在凭证提供程序 (CRED_PROV) 中设置,该提供程序后来被配置为主要 Emissary 客户端 (CLIENT) 的默认凭证提供程序。

配置没有指定应该使用什么身份验证方案,这让我相信身份验证方案是根据服务器响应决定的。如果我礼貌地要求客户端使用基本身份验证,那么所有迹象都表明服务器凭据可能会以明文形式(base64 编码)发送。

为此,我设置了一个请求基本身份验证的 Web 服务器,然后使用 SSRF 漏洞使 Emissary 服务器连接到我的恶意服务器。 Emissary HTTP客户端很高兴地从摘要身份验证切换到基本身份验证,并将凭据发送给我。以下是我的服务器显示服务器凭证的输出:


同样,AddChildDirectoryAction 终端也容易受到 SSRF 的攻击。对 /AddChildDirectory.action 终端的 POST 请求将触发对攻击者控制的主机的额外请求:

除了修复 SSRF 漏洞之外,NSA还通过只允许摘要身份验证方案来防止身份验证方法的混淆。

反射的跨站点脚本 (CVE-2021-32092)

CodeQL在自动查找SonarSource研究人员报告的大多数漏洞和几个新的关键漏洞方面做得很好,但是它没有报告SonarSource研究人员最初报告的跨站脚本(XSS)漏洞。我检查了查询集,发现没有针对这个特定XSS实例的查询。

然后我开始与 CodeQL 团队合作,对 JAX-RS 终端上的 XSS 漏洞进行相当全面的分析。这个 XSS 检测现在也包含在主 CodeQL 存储库中!

在 REST 终端上准确检测 XSS 并不是一项简单的任务,因为它们中的大多数将默认为 application/json 响应内容类型,这对 XSS 是安全的。因此,我需要 CodeQL 来检测用户控制的数据(无论是反射的还是持久的)在没有正确编码的 HTTP 响应中使用,而且还需要检测此类响应的内容类型已更改为任何 XSS 友好类型。这可以通过以下几种方式实现:

通过使用 ResponseBuilder.type() 显式设置响应内容类型;

通过使用 @Produces 注释来注释封闭方法;

通过使用 @Produces 注释来注释封闭类;

在与 CodeQL 团队一起进行这些查询改进时,我意识到我们对 Spring REST 终端的 XSS 查询也没有考虑响应内容类型,这可能导致许多误报,例如,带有应用程序/json内容类型的响应被标记为可利用的。因此,我们还实现了所需的改进,以使Spring XSS查询达到JAX-RS现在拥有精确度。

安全学习资料

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容