Confluence CVE-2022-26134
jerem1ah Lv4

Confluence CVE-2022-26134 漏洞分析【远程调试学习】

https://www.yuque.com/tianxiadamutou/zcfd4v/gil3uc

https://github.com/vulhub/vulhub/tree/master/confluence/CVE-2022-26134

调试环境配置

vulhub的环境/vulhub/confluence/CVE-2022-26134

https://github.com/vulhub/vulhub/tree/master/confluence/CVE-2022-26134

1
2
3
wget https://github.com/vulhub/vulhub/archive/master.zip -O vulhub-master.zip
unzip vulhub-master.zip
cd vulhub-master

修改一下docker-compose.yml,增加调试端口,这里添加28136端口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
version: '2'
services:
web:
image: vulhub/confluence:7.13.6
ports:
- "8090:8090"
- "28136:28136"
depends_on:
- db
db:
image: postgres:12.8-alpine
environment:
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=confluence
1
2
3
4
cd /home/39vulhub/vulhub-master/confluence/CVE-2022-26134
docker-compose up -d
docker ps -a

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cve-2022-26134-web-1  | INFO:root:Generating /opt/atlassian/confluence/conf/server.xml from template server.xml.j2
cve-2022-26134-web-1 | INFO:root:Generating /opt/atlassian/confluence/confluence/WEB-INF/classes/seraph-config.xml from template seraph-config.xml.j2
cve-2022-26134-web-1 | INFO:root:Generating /opt/atlassian/confluence/confluence/WEB-INF/classes/confluence-init.properties from template confluence-init.properties.j2
cve-2022-26134-web-1 | INFO:root:Generating /var/atlassian/application-data/confluence/confluence.cfg.xml from template confluence.cfg.xml.j2
cve-2022-26134-web-1 | INFO:root:User is currently root. Will downgrade run user to confluence
cve-2022-26134-web-1 | INFO:root:Running Confluence with command '/opt/atlassian/confluence/bin/start-confluence.sh', arguments ['/opt/atlassian/confluence/bin/start-confluence.sh', '-fg']
cve-2022-26134-web-1 | executing as current user
cve-2022-26134-web-1 | If you encounter issues starting up Confluence, please see the Installation guide at http://confluence.atlassian.com/display/DOC/Confluence+Installation+Guide
cve-2022-26134-web-1 |
cve-2022-26134-web-1 | Server startup logs are located in /opt/atlassian/confluence/logs/catalina.out
cve-2022-26134-web-1 | ---------------------------------------------------------------------------
cve-2022-26134-web-1 | Using Java: /opt/java/openjdk/bin/java
cve-2022-26134-web-1 | 2024-04-25 08:01:37,871 INFO [main] [atlassian.confluence.bootstrap.SynchronyProxyWatchdog] A Context element for ${confluence.context.path}/synchrony-proxy is found in /opt/atlassian/confluence/conf/server.xml. No further action is required
cve-2022-26134-web-1 | ---------------------------------------------------------------------------
cve-2022-26134-web-1 | NOTE: Picked up JDK_JAVA_OPTIONS: --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
cve-2022-26134-web-1 | [0.001s][warning][gc] -Xloggc is deprecated. Will use -Xlog:gc:/opt/atlassian/confluence/logs/gc-2024-04-25_08-01-37.log instead.
cve-2022-26134-web-1 | OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000c0000000, 1073741824, 0) failed; error='Not enough space' (errno=12)
cve-2022-26134-web-1 | #
cve-2022-26134-web-1 | # There is insufficient memory for the Java Runtime Environment to continue.
cve-2022-26134-web-1 | # Native memory allocation (mmap) failed to map 1073741824 bytes for committing reserved memory.
cve-2022-26134-web-1 | # An error report file with more information is saved as:
cve-2022-26134-web-1 | # /var/atlassian/application-data/confluence/hs_err_pid7.log

启动失败,看日志,应该是内存不足,关了clash和portainer这俩容器,以及mysqld服务,再次启动成功。

image-20240425161254231

1
2
3
4
docker ps -a
docker exec -it 467ec0421445 /bin/sh
ps aux
ps -le

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

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

父进程:/usr/bin/tini – /entrypoint.py

docker cp将源码复制出来

1
docker cp 467ec0421445:/opt/atlassian/confluence/ /home/39vulhub/

查看entrypoint.py文件,发现是通过start-confluence.sh启动的。

1
cat /entrypoint.py

image-20240425202759989

1
cat /opt/atlassian/confluence/bin/start-confluence.sh

image-20240425203145540

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# cat /opt/atlassian/confluence/bin/start-confluence.sh
#!/bin/bash

# resolve links - $0 may be a softlink - stolen from catalina.sh
PRG="$0"
while [ -h "$PRG" ]; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`/"$link"
fi
done
PRGDIR=`dirname "$PRG"`
export START_CONFLUENCE_JAVA_OPTS="-Datlassian.plugins.startup.options='${@}'"

if [ "$1" = "--help" ] || [ "$1" = "-h" ] ; then
exec $PRGDIR/display-help.sh
exit 0
fi

if [[ ${@} == *"disable-all-addons"* ]]; then
echo "Disabling all user installed addons";
fi

if [[ ${@} == *"disable-addons"* ]]; then
echo "Disabling specified plugins";
fi

PRGRUNMODE=false
if [[ ${@} == *"-fg"* ]] || [[ ${@} == *"run"* ]]; then
shift
PRGRUNMODE=true
else
echo ""
echo "To run Confluence in the foreground, start the server with start-confluence.sh -fg"
fi

. `dirname $0`/user.sh #readin the username

if [ -z "$CONF_USER" ] || [ $(id -un) == "$CONF_USER" ]; then

echo executing as current user
if [ "$PRGRUNMODE" == "true" ] ; then
exec $PRGDIR/catalina.sh run $@
else
exec $PRGDIR/startup.sh $@
fi

elif [ $UID -ne 0 ]; then

echo Confluence has been installed to run as $CONF_USER so please sudo run this to enable switching to that user
exit 1

else

echo executing using dedicated user: $CONF_USER
if [ -x "/sbin/runuser" ]; then
sucmd="/sbin/runuser"
else
sucmd="su"
fi

if [ "$PRGRUNMODE" == "true" ] ; then
$sucmd -m $CONF_USER -c "$PRGDIR/catalina.sh run $@"
else
$sucmd -m $CONF_USER -c "$PRGDIR/startup.sh $@"
fi

fi

#

会调用catalina.sh,即启动tomcat,而tomcat会通过setenv.sh来管理环境变量

1
2
cat /opt/atlassian/confluence/bin/catalina.sh
cat /opt/atlassian/confluence/bin/setenv.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# cat /opt/atlassian/confluence/bin/setenv.sh
#-----------------------------------------------------------------------------------
# See the CATALINA_OPTS below for tuning the JVM arguments used to start Confluence
#-----------------------------------------------------------------------------------

echo "If you encounter issues starting up Confluence, please see the Installation guide at http://confluence.atlassian.com/display/DOC/Confluence+Installation+Guide"

# set the location of the pid file
if [ -z "$CATALINA_PID" ] ; then
if [ -n "$CATALINA_BASE" ] ; then
CATALINA_PID="$CATALINA_BASE"/work/catalina.pid
elif [ -n "$CATALINA_HOME" ] ; then
CATALINA_PID="$CATALINA_HOME"/work/catalina.pid
fi
fi
export CATALINA_PID

PRGDIR=`dirname "$0"`
if [ -z "$CATALINA_BASE" ]; then
if [ -z "$CATALINA_HOME" ]; then
LOGBASE=$PRGDIR
LOGTAIL=..
else
LOGBASE=$CATALINA_HOME
LOGTAIL=.
fi
else
LOGBASE=$CATALINA_BASE
LOGTAIL=.
fi

PUSHED_DIR=`pwd`
cd $LOGBASE
cd $LOGTAIL
LOGBASEABS=`pwd`
cd $PUSHED_DIR
echo ""
echo "Server startup logs are located in $LOGBASEABS/logs/catalina.out"

# IMPORTANT NOTE: Only set JAVA_HOME or JRE_HOME above this line
# Get standard Java environment variables
if $os400; then
# -r will Only work on the os400 if the files are:
# 1. owned by the user
# 2. owned by the PRIMARY group of the user
# this will not work if the user belongs in secondary groups
. "$CATALINA_HOME"/bin/setjre.sh
else
if [ -r "$CATALINA_HOME"/bin/setjre.sh ]; then
. "$CATALINA_HOME"/bin/setjre.sh
else
echo "Cannot find $CATALINA_HOME/bin/setjre.sh"
echo "This file is needed to run this program"
exit 1
fi
fi

echo "---------------------------------------------------------------------------"
echo "Using Java: $JRE_HOME/bin/java"
CONFLUENCE_CONTEXT_PATH=`$JRE_HOME/bin/java -jar $CATALINA_HOME/bin/confluence-context-path-extractor.jar $CATALINA_HOME`
export CONFLUENCE_CONTEXT_PATH
$JRE_HOME/bin/java -jar $CATALINA_HOME/bin/synchrony-proxy-watchdog.jar $CATALINA_HOME
echo "---------------------------------------------------------------------------"

#-----------------------------------------------------------------------------------
# This section contains commonly modified Java options and system properties
# When upgrading Confluence, copy this section to reapply your customizations
# Always the review the new file for any changes to the default values

# To learn more about Java 8 options see:
# https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html
# To learn more about Java 11 options see:
# https://docs.oracle.com/en/java/javase/11/tools/java.html
#-----------------------------------------------------------------------------------

# Set the Java heap size
CATALINA_OPTS="-Xms${JVM_MINIMUM_MEMORY:=1024m} -Xmx${JVM_MAXIMUM_MEMORY:=1024m} -Dconfluence.home=${CONFLUENCE_HOME} ${CATALINA_OPTS}"

# Default values for small to medium size instances
CATALINA_OPTS="-XX:ReservedCodeCacheSize=${JVM_RESERVED_CODE_CACHE_SIZE:=256m} ${CATALINA_OPTS}"

# Recommended values for medium to large, and enterprise size instances
# Comment out the default values in the block above, then uncomment the values below
# To learn more about the impact of disabling the upgrade recovery file see:
# https://confluence.atlassian.com/x/ShtwPg
#CATALINA_OPTS="-XX:ReservedCodeCacheSize=${JVM_RESERVED_CODE_CACHE_SIZE:=384m} ${CATALINA_OPTS}"
#CATALINA_OPTS="-XX:+PrintTenuringDistribution ${CATALINA_OPTS}"
#CATALINA_OPTS="-XX:+PrintGCDetails -XX:+PrintGCTimeStamps ${CATALINA_OPTS}"
#CATALINA_OPTS="-Dconfluence.upgrade.recovery.file.enabled=false ${CATALINA_OPTS}"

# Additional Confluence system properties
# For a list of properties recognized by Confluence see:
# https://confluence.atlassian.com/display/DOC/Recognized+System+Properties
# We recommend you include a support ticket ID and/or note to help track the reason for change
# For example:
# CSP-123456 - Added example JVM option to help explain this section
#CATALINA_OPTS="-Dexample.property=true ${CATALINA_OPTS}"

# Uncomment this line to disable email notifications
#CATALINA_OPTS="-Datlassian.mail.senddisabled=true -Datlassian.mail.fetchdisabled=true ${CATALINA_OPTS}"

#-----------------------------------------------------------------------------------
# End of commonly modified Java options. You should not need to change the options
# below unless recommended by Atlassian Support
#-----------------------------------------------------------------------------------

CATALINA_OPTS="-XX:+IgnoreUnrecognizedVMOptions ${CATALINA_OPTS}"
CATALINA_OPTS="-XX:G1ReservePercent=20 -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent -XX:+PrintGCDateStamps ${CATALINA_OPTS}"
CATALINA_OPTS="-Xlog:gc+age=debug:file=$LOGBASEABS/logs/gc-`date +%F_%H-%M-%S`.log::filecount=5,filesize=2M ${CATALINA_OPTS}"
CATALINA_OPTS="-Xloggc:$LOGBASEABS/logs/gc-`date +%F_%H-%M-%S`.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=2M ${CATALINA_OPTS}"
CATALINA_OPTS="-Djava.awt.headless=true ${CATALINA_OPTS}"
CATALINA_OPTS="-Datlassian.plugins.enable.wait=300 ${CATALINA_OPTS}"
CATALINA_OPTS="-Dsynchrony.enable.xhr.fallback=true ${CATALINA_OPTS}"
CATALINA_OPTS="-Djava.locale.providers=JRE,SPI,CLDR ${CATALINA_OPTS}"
CATALINA_OPTS="-Dconfluence.context.path=${CONFLUENCE_CONTEXT_PATH} ${CATALINA_OPTS}"
CATALINA_OPTS="-Dorg.apache.tomcat.websocket.DEFAULT_BUFFER_SIZE=32768 ${CATALINA_OPTS}"
CATALINA_OPTS="${START_CONFLUENCE_JAVA_OPTS} ${CATALINA_OPTS}"

CATALINA_OPTS="${CATALINA_OPTS} ${JVM_SUPPORT_RECOMMENDED_ARGS} -DConfluenceHomeLogAppender.disabled=${CONFLUENCE_LOG_STDOUT}"

export CATALINA_OPTS

#-----------------------------------------------------------------------------------
# End configuration options
#-----------------------------------------------------------------------------------

image-20240425205747417

image-20240425205759757

1
CATALINA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:28136 ${CATALINA_OPTS}"

vscode连接服务器,直接把cpu和内存搞满了,直接崩溃,拿本地机器搞吧还是。上kali

1
cd /home/kali/vulhub/confluence/CVE-2022-26134
远程调试配置
1
OpenJDK 64-Bit Server VM Temurin-11.0.15+10 (build 11.0.15+10, mixed mode)

image-20240425164453899

暂时失败原因

centos服务器的内存有限;

kali的docker下载速度太慢;

动态调试环境搭建博客讲的不清晰;

新的博客教程

https://xz.aliyun.com/t/11436?time__1311=mqmx0DB7eWqND%2FQiiQGkAD8AGO78j5x&alichlgref=https%3A%2F%2Fwww.google.com%2F

0709再来远程调试(远程调试成功)

https://github.com/vulhub/vulhub/tree/master/confluence/CVE-2022-26134

https://www.yuque.com/tianxiadamutou/zcfd4v/gil3uc

https://xz.aliyun.com/t/11436?time__1311=mqmx0DB7eWqND%2FQiiQGkAD8AGO78j5x&alichlgref=https%3A%2F%2Fwww.google.com%2F

我的环境

本地虚拟机kali,以防服务器内存不够卡死

finalshell连接root kali操作,方便文件管理

vscode远程ssh连接root kali操作,方便docker文件管理和文件修改以及命令执行

1
2
3
cd /home/kali/vulhub/confluence/CVE-2022-26134
docker-compose up -d
docker-compose down

http://192.168.19.148:8090/setup/setuplicense.action

定位源代码

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

image-20240709121210277

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

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

docker cp将源码复制出来

1
docker cp 3b6dd13a22ec:/opt/atlassian/confluence/confluence /home/jerem1ah/confluence

image-20240709140250356

配置IDEA

配置项目结构

image-20240709140451719

配置远程调试

image-20240709140646762

image-20240709140546676

远程调式配置

父进程涉及entrypoint.py文件,发现启动是通过start-confluence.sh文件

image-20240709140938218

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

image-20240709141359318

在tomcat中会通过setenv.sh来统一管理环境变量,修改setenv.sh来开启远程调试

image-20240709141536811

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

漏洞分析

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

image-20240709202612480

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

image-20240709202957505

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

image-20240709203132087

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

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

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

image-20240709204017011

也就是获取我们 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))}

image-20240709204236125

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

image-20240709204616482

这里我们输入的是

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 等参数创建一个代理对象

image-20240709211054895

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

image-20240710131644037

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

image-20240710132355330

image-20240710132413458

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

image-20240710132543115

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

image-20240710132829311

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

image-20240710132912693

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

image-20240710133310713

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

image-20240710133441229

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

image-20240710133741758

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

image-20240710133859208

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

image-20240710135242487

不知道为什么我的代码不经过这里,而是经过另一个execute函数,暂且先不提,跟着上面的走

image-20240710135344245

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

image-20240710135530774

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

 Comments