简单来说就是一个confluence的未授权OGNL RCE
修复版本
- 7.4.17
- 7.13.7
- 7.14.3
- 7.15.2
- 7.16.4
- 7.17.4
- 7.18.1
官方修复建议是直接替换有漏洞的包并替换为更新后的包
-
7.15.0 - 7.18.0修复
删除
<confluence-install>/confluence/WEB-INF/lib/xwork-1.0.3-atlassian-8.jar
并替换为 xwork-1.0.3-atlassian-10.jar 然后重启应用
-
6.0.0 - 7.14.2修复
删除下面两个
<confluence-install>/confluence/WEB-INF/lib/xwork-1.0.3.6.jar
<confluence-install>/confluence/WEB-INF/lib/webwork-2.1.5-atlassian-3.jar
并替换为 xwork-1.0.3-atlassian-10.jar webwork-2.1.5-atlassian-4.jar 下载CachedConfigurationProvider.class 放到这个目录下
<confluence-install>/confluence/WEB-INF/classes/com/atlassian/confluence/setup/webwork
要注意权限的问题 重启应用
调试环境
前置环境:
docker环境配置文件
version: '2'
services:
web:
image: vulhub/confluence:7.13.6
ports:
- "8090:8090"
- "5050:5050"
depends_on:
- db
db:
image: postgres:12.8-alpine
environment:
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=confluence
调试源码为在/opt/atlassian/confluence
将/confluence/WEB-INF下的atlassian-bundled-plugins、atlassian-bundled-plugins-setup、lib文件设置为lib
修改/opt/atlassian/confluence/bin/setenv.sh文件,加入远程调试配置。
docker环境也需要对应的设置
首次访问的时候需要认证一下,数据库配置那里,地址是db,后三行都是postgres
网上的一个payload为
/%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%22cat%20/etc/passwd%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/
直接接在url后面,返回的一个自定义header会把结果也返回
调试思路:
根据漏洞信息,官方修复措施
https://confluence.atlassian.com/doc/confluence-security-advisory-2022-06-02-1130377146.html
定位漏洞jar包,xwork-1.0.3-atlassian-10.jar ,比对修复前后的jar包发现修改主要在ActionChainResult.java,定位OGNL调用点,发现修复措施是将漏洞点TextParseUtil.translateVariables()给删除了,改为直接取值。意味着如果这个点再次出现并且能够控制输入,那么这个漏洞依然可以利用。
传入的namespace的值就是ognl表达式
然后到TextParseUtil.java的translateVariables方法,此时传入的payload在这里被解析
然后调用Ognl.getValue()
开始一系列的OGNL表达式处理
表达式解析完成后,执行命令并返回result
payload向下的触发暂时到这里,现在的疑问是这个payload是怎么从url传递到漏洞点的,这里是this.namespace,向上回溯,this.createResult()
(调了一下背景)
this.proxy.getConfig().getResults();
现在就需要溯源这句
上面有一堆invoke来回的调用,溯源到DefaultActionProxy
ConfluenceServletDispatcher的proxy.execute();,再往上是ServletDispatcher,算是到头了
getActionName有两个,第二个 逻辑是返回’/’和’.’之间的字符串或者整个字符串
namespace则是返回’/’前的内容,现在就能理解为什么payload最后会有一个’/’
分析就到这里
后续
漏洞点触发器前会有一段类似循环的操作,最后把actionName设置为’notpermitted’就跳出循环了,触发之后也有一段循环然后等待新的请求,这两部分一个是和漏洞本身流程关系不大,一个是对这块不太了解就暂时不深究了。
从修复的地方可以看出原来的代码略显鸡肋,也不知道出于什么样的原因才这样写的,是因为本来有别的想法来拓展一些功能,最后没有实现,但是也没有修改这几句?
参考
https://mr-r3bot.github.io/research/2022/06/06/Confluence-Preauth-RCE-2022.html
https://zhuanlan.zhihu.com/p/526003612
https://forum.butian.net/share/1645