漏洞分析 | Ignite Realtime Openfire 路径遍历漏洞(CVE-2023-32315)

文章详细分析了IgniteRealtimeOpenfire服务器的认证绕过漏洞,涉及4.7.0至4.7.5版本,利用非标准unicodeuri解析重演CVE-2008-6508路径遍历。攻击者可构造恶意请求,绕过权限控制。修复方案和厂商已提供的安全更新也一并提及。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

漏洞概述

Ignite Realtime Openfire是Ignite Realtime社区的一款采用Java开发且基于XMPP(前称Jabber,即时通讯协议)的跨平台开源实时协作(RTC)服务器,它能够构建高效率的即时通信服务器,并支持上万并发用户数量。

近期,Openfire存在认证绕过漏洞,未经身份认证的远程攻击者可以构造恶意请求访问受限界面,最终上传恶意文件实现远程代码执行。

受影响版本

受影响版本:3.10.0 <= Openfire < 4.6.8,4.7.0 <= Openfire < 4.7.5

漏洞分析

问题关键在于Openfire内置的Jetty Web服务器支持对%u002e这类非标准unicode uri的解析,导致之前的路径穿越漏洞(CVE-2008-6508)再次出现。

这里我们采用打补丁前的最新版本(4.7.4)进行分析,具体链接如下:
https://codeload.github.com/igniterealtime/Openfire/zip/refs/tags/v4.7.4

先从xmppserver/src/main/webapp/WEB-INF/web.xml开始分析,这段配置定义了一个AuthCheck filter,用于排除对部分url的权限检查,包括登录/注销页面、系统设置及其子页面、静态资源文件等:

<filter>
    <filter-name>AuthCheck</filter-name>
    <filter-class>org.jivesoftware.admin.AuthCheckFilter</filter-class>
    <init-param>
        <param-name>excludes</param-name>
        <param-value>
            login.jsp,index.jsp?logout=true,setup/index.jsp,setup/setup-*,.gif,.png,error-serverdown.jsp,loginToken.jsp
        </param-value>
    </init-param>
</filter>

接着查看filter,xmppserver/src/main/java/org/jivesoftware/admin/AuthCheckFilter.java

这里的excludes就是AuthCheck filter配置的部分,然后就去调用testURLPassesExclude(),若返回true,则break,也就说明请求路径无需鉴权。

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
        throws IOException, ServletException
{
    ...
    // See if it's contained in the exclude list. If so, skip filter execution
    boolean doExclude = false;
    for (String exclude : excludes) {
        if (testURLPassesExclude(url, exclude)) {
            doExclude = true;
            break;
        }
    }
    if (!doExclude) {
        WebManager manager = new WebManager();
        manager.init(request, response, request.getSession(), context);
        boolean haveOneTimeToken = manager.getAuthToken() instanceof AuthToken.OneTimeAuthToken;
        User loggedUser = manager.getUser();
        boolean loggedAdmin = loggedUser == null ? false : adminManager.isUserAdmin(loggedUser.getUsername(), true);
        if (!haveOneTimeToken && !loggedAdmin && !authUserFromRequest(request)) {
            response.sendRedirect(getRedirectURL(request, loginPage, null));
            return;
        }
    }
    chain.doFilter(req, res);
}

显然,testURLPassesExclude()起到了关键作用。

public static boolean testURLPassesExclude(String url, String exclude) {
    ......
    if (exclude.endsWith("*")) {
        if (url.startsWith(exclude.substring(0, exclude.length()-1))) {
            // Now make sure that there are no ".." characters in the rest of the URL.
            if (!url.contains("..") && !url.toLowerCase().contains("%2e")) {
                return true;
            }
        }
    }
    ......
}

可以先尝试历史payload理清代码逻辑:
payload1:/setup/setup-/../../log.jsp
payload2:/setup/setup-/%2e%2e/%2e%2e/log.jsp

因为匹配到excludes存在的setup/setup-*,进入url检测,这里已经对”..”以及”%2e”进行了过滤,所以普通的路径遍历特征都会被拦截,但新版本中的Jetty Web服务器支持对%u002e这类非标准unicode uri的解析,也就又给攻击者提供了一种利用方式。

还是以4.7.4为例,我们来分析一下其解码逻辑:

<jetty.version>9.4.43.v20210629</jetty.version>

首先看org.eclipse.jetty.http.HttpURI#parse() ,这是Jetty中用于解析HTTP请求URI的方法。它的作用是将HTTP请求URI字符串解析为一个包含多个属性的Java对象,以便Jetty可以根据这些属性来处理HTTP请求,我们需要关注的是URI的路径部分是如何处理的:

if (!encodedPath && !dot)
{
    if (_param == null)
        _decodedPath = _path;
    else
        _decodedPath = _path.substring(0, _path.length() - _param.length() - 1);
}
else if (_path != null)
{
    // The RFC requires this to be canonical before decoding, but this can leave dot segments and dot dot segments
    // which are not canonicalized and could be used in an attempt to bypass security checks.
    String decodedNonCanonical = URIUtil.decodePath(_path);
    _decodedPath = URIUtil.canonicalPath(decodedNonCanonical);
    if (_decodedPath == null)
        throw new IllegalArgumentException("Bad URI");
}

这里给出了两个判断条件,第一,如果URI的路径部分既没有进行编码,也没有包含点或双点符号,则说明路径是正确的,可以直接使用;第二,如果URI的路径部分不为空,则需要对它进行解码和规范化操作,着重关注第二个条件,代码先使用了URIUtil.decodePath()方法对_path进行解码,得到解码后的路径字符串。然后,又使用URIUtil.canonicalPath()方法对解码后的路径字符串进行规范化,得到规范化后的路径字符串。最后,如果规范化后的路径字符串为null,则抛出IllegalArgumentException异常。

跟进org.eclipse.jetty.util.URIUtil#decodePath(),进一步分析%uxxxx的解码流程:

for (int i = offset; i < end; i++)
{
    char c = path.charAt(i);
    switch (c)
    {
        case '%':
            if (builder == null)
            {
                builder = new Utf8StringBuilder(path.length());
                builder.append(path, offset, i - offset);
            }
            if ((i + 2) < end)
            {
                char u = path.charAt(i + 1);
                if (u == 'u')
                {
                    // 解码%uxxxx形式的Unicode字符
                    builder.append((char)(0xffff & TypeUtil.parseInt(path, i + 2, 4, 16)));
                    i += 5;
                }
                else
                {
                    // 解码%xx形式的ASCII字符
                    builder.append((byte)(0xff & (TypeUtil.convertHexDigit(u) * 16 + TypeUtil.convertHexDigit(path.charAt(i + 2)))));
                    i += 2;
                }
            }
            else
            {
                throw new IllegalArgumentException("Bad URI % encoding");
            }
            break;
        ......
    }
}

主要的解码逻辑写在了for循环里,它会遍历整个路径字符串,并对编码字符进行解码。其中,builder用于存储解码后的路径字符串,如果遇到%,会检查builder是否为null,如果是的话,就说明还没有解码过任何字符,需要先将%前面的字符拷贝到builder中,这样做的目的是保证解码后的uri路径完整。然后,再根据后面的字符决定unicode/ascii解码,得到解码后的路径字符串,最后由org.eclipse.jetty.util.URIUtil#canonicalPath()进行规范处理。以绕过的payload为例,处理流程如下:

/setup/setup-/%u002e%u002e/%u002e%u002e/log.jsp
-> /setup/setup-/../../log.jsp
-> /log.jsp

此外,CVE-2021-34429的绕过逻辑也与之类似
https://github.com/eclipse/jetty.project/security/advisories/GHSA-vjv5-gp2w-65vm

漏洞复现

通过以上分析,攻击者仅需向受害站点发送满足漏洞触发条件的unicode uri再拼接Openfire管理后台敏感路径,即可进行权限绕过。

最常见的利用方式当然是新建账户进而接管后台:

接着修改开源插件,https://github.com/igniterealtime/openfire-fastpath-plugin

添加恶意代码并打包为jar后上传,即可实现getshell。

修复方案

目前厂商已提供升级版本和缓解措施:
https://github.com/igniterealtime/Openfire/security/advisories/GHSA-gw42-f939-fhvm

产品支持

网宿云WAF已第一时间支持对该漏洞利用攻击的防护,并持续挖掘分析其他变种攻击方式和各类组件漏洞,第一时间上线防护规则,缩短防护“空窗期”。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值