confluence.home 值修改为 confluence home 的地址CATALINA_OPTS 值,使程序能够以远程调试模式运行对于 Windows,文件 ./bin/setenv.bat
set CATALINA_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
对于 Linux,文件 ./bin/setenv.sh
CATALINA_OPTS="-Xrunjdwp:transport=dt_socket,suspend=n,server=y,address=5005 ${CATALINA_OPTS}"
Remote JVM Debug,host 和 port 值为 localhost:5005,以及 Command line arguments for remote JVM-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
$ su - postgres
postgres@ubuntu:~$ psql -U postgres
postgres@ubuntu:~$ psql -U postgres
psql (10.6 (Ubuntu 10.6-0ubuntu0.18.04.1))
Type "help" for help.
postgres=# CREATE USER wiki WITH PASSWORD 'wiki';
CREATE ROLE
postgres=# CREATE DATABASE wiki OWNER wiki;
CREATE DATABASE
postgres=# GRANT ALL PRIVILEGES ON DATABASE jira TO wiki;
GRANT
我们需要将以下 jar 添加到 lib:./confluence/WEB-INF/atlassian-bundled-plugins/widgetconnector-x.x.x.jar、./confluence/WEB-INF/lib/confluence-x.x.x.jar、./confluence/WEB-INF/lib/velocity-x.x.x-atlassian-x.jar,这样调试时我们就能看到所需的源码。
我们接着运行 ./bin/start-confluence.bat 文件,你也可以参考这份指南从源码进行安装。
阅读描述后,我们可以知道这个漏洞始于 Widget Connector 功能,所以我立刻用谷歌搜索,以了解该功能是什么以及如何使用:
进入编辑页面

选择其他宏
选择 Widget Connector

我随便选择了一些参数然后点击预览,接着转到 Burp 查看是否有异常。

在这个数据包中,我注意到有一个参数 "pluginKey":"com.atlassian.confluence.extra.widgetconnector",因此我猜测 Widget Connector 功能定义在类 com.atlassian.confluence.extra.widgetconnector 中,于是我在路径中查找是否有可疑的 jar 包。

我尝试将 ./confluence/WEB-INF/atlassian-bundled-plugins/widgetconnector-x.x.x.jar 文件添加到项目的 lib 中,以便阅读源代码并进行调试。
将 jar 文件添加到 lib 的方法
打开 widgetconnector 包后,我对 WidgetMacro 类很有兴趣,于是在该类的构造函数和 execute 方法上设置断点,以查看我在使用 Preview 功能时这个类是否会被调用 🕵️

execute 函数已被调用,随后程序调用 DefaultRenderManager.getEmbeddedHtml

我们看到要进入 if,需要满足条件 widgetRenderer.matches(url)。我们接下来检查 YoutubeRenderer 类中的 widgetRenderer.matches(url) 函数


因此,我需要将参数 url 设置为 YouTube 视频的链接(或 Vimeo、Twitter……)。我将 url 设置为任意 YouTube 视频的 URL,程序便进入了 if 语句,接着调用 widgetRenderer.getEmbeddedHtml(url, params) 函数(YoutubeRenderer 类)

程序跳转到 setDefaultParam 函数,在这里我们看到一个隐藏参数 _template,看起来相当可疑 :)

退出 setDefaultParam 函数后,程序调用 DefaultVelocityRenderService.render 函数

接着经过 getRenderedTemplate 函数和 VelocityUtils.getRenderedTemplate(String templateName, Map<?, ?> contextMap)


接下来是 VelocityUtils.getRenderedTemplate(String templateName, Context context) 和 getRenderedTemplateWithoutSwallowingErrors(templateName, context)

renderTemplateWithoutSwallowingErrors 函数

程序调用 getTemplate 函数,然后是 VelocityEngine.getTemplate 和 RuntimeInstance.getTemplate,在这里我们看到程序使用参数 _template 的值作为输入调用了 getResource 函数。在 Java 中,getResource 函数可以用来加载本地文件形式的资源,也可以加载互联网上的资源(通过 HTTP 协议)。
停下来想想:这是否允许攻击者通过在请求中插入额外的 _template 参数,将任意模板(来自本地服务器或来自攻击者的主机)注入程序中??

我们继续向前跟踪,看看获得模板后程序如何处理:
获得模板后,程序调用 VelocityUtils.renderTemplateWithoutSwallowingErrors(template, context, writer); 函数

然后进入 template.merge(context, writer);
public void merge(Context context, Writer writer, List macroLibraries) throws ResourceNotFoundException, ParseErrorException, MethodInvocationException {
if (this.errorCondition != null) {
throw this.errorCondition;
} else if (this.data == null) {
String msg = "Template.merge() failure. The document is null, most likely due to parsing error.";
throw new RuntimeException(msg);
} else {
InternalContextAdapterImpl ica = new InternalContextAdapterImpl(context);
ica.setMacroLibraries(macroLibraries);
if (macroLibraries != null) {
for(int i = 0; i < macroLibraries.size(); ++i) {
try {
this.rsvc.getTemplate((String)macroLibraries.get(i));
} catch (ResourceNotFoundException var17) {
this.rsvc.getLog().error("template.merge(): cannot find template " + (String)macroLibraries.get(i));
throw var17;
} catch (ParseErrorException var18) {
this.rsvc.getLog().error("template.merge(): syntax error in template " + (String)macroLibraries.get(i) + ".");
throw var18;
} catch (Exception var19) {
throw new RuntimeException("Template.merge(): parse failed in template " + (String)macroLibraries.get(i) + ".", var19);
}
}
}