Apache OFBiz 路径遍历致权限绕过漏洞分析(CVE-2024-25065)

漏洞描述

Apache OFBiz是一个著名的电子商务平台,提供了创建基于最新 J2EE/ XML规范和技术标准,构建大中型企业级、跨平台、跨数据库、跨应用服务器的多层、分布式电子商务类WEB应用系统的框架。

Apache OFBiz 中存在路径遍历漏洞,漏洞原因在于未充分验证用户输入的 contextPath 参数,未授权的攻击者可以通过构造恶意请求绕过认证,进而访问系统中的文件。

本文首发于先知社区https://xz.aliyun.com/t/14017

本人就是先知作者

影响版本

Apache OFBiz < 18.12.12

环境搭建

这里我们下载的版本为18.12.05。

配置gradle目录后,执行build。

7134f8f5ac20240408223422

完成后会在build/lib目录下生成ofbiz.jar文件。

75c168b67120240408224135

然后我们添加JAR Application,就可以直接调试项目。

079f4fb55b20240408224200

7ae5e99a8c20240408224219

漏洞原理分析

查看漏洞代码

public static boolean hasBasePermission(GenericValue userLogin, HttpServletRequest request) {
        Security security = (Security) request.getAttribute("security");
        if (security != null) {
            ServletContext context = request.getServletContext();
            String serverId = (String) context.getAttribute("_serverId");
            // get a context path from the request, if it is empty then assume it is the root mount point
            String contextPath = request.getContextPath();
            if (UtilValidate.isEmpty(contextPath)) {
                contextPath = "/";
            }
            ComponentConfig.WebappInfo info = ComponentConfig.getWebAppInfo(serverId, contextPath);
            if (info != null) {
                return hasApplicationPermission(info, security, userLogin);
            } else {
                if (Debug.infoOn()) {
                    Debug.logInfo("No webapp configuration found for : " + serverId + " / " + contextPath, module);
                }
            }
        } else {
            if (Debug.warningOn()) {
                Debug.logWarning("Received a null Security object from HttpServletRequest", module);
            }
        }
        return true;
    }

根据名称我们可以知道hasBasePermission的方法,是用于检查用户是否具有访问Web应用部分的基本权限的校验方法。方法中首先通过request.getAttribute("security");从请求中获取安全管理器,当安全管理器不为空时再获取当前Web应用的上下文和服务器ID,获取请求的contextPath为空就设置为根路径。

然后就是使用服务器ID和上下文路径从ComponentConfig中获取对应的Web应用信息ComponentConfig.getWebAppInfo(serverId, contextPath);。当如果获取到了Web应用信息,则调用hasApplicationPermission方法检查用户是否有权访问该应用。如果没有找到对应的Web应用配置信息,则进行信息日志记录。如果从请求中获取不到Security对象,则记录一条警告日志。

以下的分析我们使用创建的订单账号ggb无管理员权限。

4a47a0db6e20240408224251

当我们访问/ordermgr/control/login/webtools/control/login路由,其中/webtools/control/login为web管理工具的登录路由,/ordermgr/control/login为订单的登录路由。会直接进入不到hasBasePermission方法进行权限检测,直接提示路由错误。

fb5c81ed3a20240408224317

当我们访问/ordermgr/control/login/../../../webtools/control/login,使用../进行路径穿越。此时可以进入到hasBasePermission检测方法。我们将断点设置在String contextPath = request.getContextPath();查看此时获取到的contextPath。可以发现此时contextPath/ordermgr/control/login/../../../webtools

7b6fbd4c5920240408224354

继续调试,系统会通过ComponentConfig.getWebAppInfo(serverId, contextPath);获取web应用的配置信息,当获取的信息不为空着进入hasBasePermission方法进行权限检测。那么这里当我们通过../进行路由跳转后,可以发现其获取不到配置信息。从而跳过hasBasePermission方法进行的权限检测。

d642f8c3d220240408224720

最后返回为true,通过hasBasePermission方法的校验。

1e4125441220240408224744

其中hasBasePermission方法只是doMainLogin登录逻辑中的一个检验方法,详细代码如下。

public static String doMainLogin(HttpServletRequest request, HttpServletResponse response, GenericValue userLogin, Map<String, Object> userLoginSession) {
        HttpSession session = request.getSession();
        boolean authoriseLoginDuringImpersonate = EntityUtilProperties.propertyValueEquals("security", "security.login.authorised.during.impersonate", "true");
        if (!authoriseLoginDuringImpersonate && checkImpersonationInProcess(request, response) != null) {
            return "error";
        }
        if (userLogin != null && hasBasePermission(userLogin, request)) {
            doBasicLogin(userLogin, request);
        } else {
            String errMsg = UtilProperties.getMessage(resourceWebapp, "loginevents.unable_to_login_this_application", UtilHttp.getLocale(request));
            request.setAttribute("_ERROR_MESSAGE_", errMsg);
            return "error";
        }

        if (userLoginSession != null) {
            session.setAttribute("userLoginSession", userLoginSession);
        }

        request.setAttribute("_LOGIN_PASSED_", "TRUE");

        // run the after-login events
        RequestHandler rh = RequestHandler.getRequestHandler(request.getSession().getServletContext());
        rh.runAfterLoginEvents(request, response);

        // Create a secured cookie with the correct userLoginId
        createSecuredLoginIdCookie(request, response);

        // make sure the autoUserLogin is set to the same and that the client cookie has the correct userLoginId
        autoLoginSet(request, response);

        return autoLoginCheck(request, response);

    }

其中我们主要分析hasBasePermission方法通过后的代码,hasBasePermission方法存在if (userLogin != null && hasBasePermission(userLogin, request))判断逻辑中,其中表示当userLogin对象不为空且通过hasBasePermission方法校验用户具有基本权限,就执行基本登录操作。这里我们通过判断,执行登录操作,成功通过登录。

c9baca3cda20240408224817

然后进行判断当传入的用户会话信息不为空,则将其设置到会话属性中。这里为空,不设置到会话中。

88399fdcf820240408224841

然后设置一个属性,表示登录过程已通过

然后运行登录后事件,并创建一个安全的cookie,包含正确的userLoginId,将客户端cookie设置为正确的正确的userLoginId

ba6beb7ae220240408224902

自此我们以及成功绕过安全校验,通过../进行路径穿越,拿到了webtools路径的cookie。

9eb9cd58b920240408224924

7afbb1602620240408224946

可以看到成功跳转至webtools首页。

漏洞利用

这里我们直接点击进行利用,会被提示没有权限。应为直接利用,新的路由还是会进入上方的权限校验中。这里我们在路由前方继续加上/ordermgr/control/login/../../..,同时请求体中提交低权限的用户名和密码。这里我们创建新用户,发出如下请求,会得到以下页面。提示我们没有权限浏览。

9eb60bc8bf20240408225011

但此时我们已经成功执行了操作,创建了新用户。

c00b57557720240408225033

修复建议

厂商已发布补丁修复漏洞,用户请尽快更新至安全版本 将 ofbiz 升级至 18.12.12 及以上版本

来源

https://avd.aliyun.com/detail?id=AVD-2024-25065

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
评论 共1条

请登录后发表评论

    请登录后查看评论内容