Confluence未受权 RCE (CVE-2019-3396) 破绽剖析 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析

申博_安全工具 申博 254次浏览 已收录 0个评论

申博网络安全巴士站

申博-网络安全巴士站是一个专注于网络安全、系统安全、互联网安全、信息安全,全新视界的互联网安全新媒体。

————————————-

看到官方宣布了预警,因而最先了破绽应急。破绽形貌中指出Confluence Server与Confluence数据中心中的Widget连接器存在服务端模板注入破绽,攻击者能应用此破绽能够或许完成目次穿越与长途代码实行。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析

确认破绽点是Widget Connector,下载最新版的比对补钉,发如今com\atlassian\confluence\extra\widgetconnector\WidgetMacro.java内里多了一个过滤,这个应当就是这个破绽最症结的处所。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析

能够看到

this.sanitizeFields = Collections.unmodifiableList(Arrays.asList(VelocityRenderService.TEMPLATE_PARAM));

TEMPLATE_PARAM的值就是_template,这个以是就是补钉了过滤传入外部的_template参数。

public interface VelocityRenderService {
    public static final String WIDTH_PARAM = "width";
    public static final String HEIGHT_PARAM = "height";
    public static final String TEMPLATE_PARAM = "_template";

翻了一下Widget Connector内里的文件,发明TEMPLATE_PARAM就是模板文件的途径。

public class FriendFeedRenderer implements WidgetRenderer { private static final String MATCH_URL = "friendfeed.com"; private static final String PATTERN = "friendfeed.com/(\\w+)/?"; private static final String VELOCITY_TEMPLATE = "com/atlassian/confluence/extra/widgetconnector/templates/simplejscript.vm"; private VelocityRenderService velocityRenderService; ...... public String getEmbeddedHtml(String url, Map<String, String> params) { params.put(VelocityRenderService.TEMPLATE_PARAM, VELOCITY_TEMPLATE); return velocityRenderService.render(getEmbedUrl(url), params); }

加载外部的链接时,会挪用相对的模板去衬着,如上,模板的途径一样平常是写死的,然则也有破例,补钉的作用也申明有人突破了限定,挪用了意料之外的模板,从而造成了模板注入。

在了解了补钉和有了一些也许的预测以后,最先实验。

起首先找到这个功用,翻了一下官方的文档,找到了这个功用,能够在文档中嵌入一些视频,文档之类的。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析

看到这个,有点激动了,由于在翻补钉的过程当中,发明了几个参数,urlwidthheight恰好对应着这里,那_template的英文不是也。从这里通报进去的?

随意找个的Youtube视频插进去尝尝,点击预览,抓包。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析

params中实验插进去_template参数,好吧,没啥回响反映..

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析

最先调试形式,由于测试插进去的是的Youtube视频,以是挪用的是com/atlassian/confluence/extra/widgetconnector/video/YoutubeRenderer.class

public class YoutubeRenderer implements WidgetRenderer, WidgetImagePlaceholder {
    private static final Pattern YOUTUBE_URL_PATTERN = Pattern.compile("https?://(.+\\.)?youtube.com.*(\\?v=([^&]+)).*$");
    private final PlaceholderService placeholderService;
    private final String DEFAULT_YOUTUBE_TEMPLATE = "com/atlassian/confluence/extra/widgetconnector/templates/youtube.vm";
......

    public String getEmbedUrl(String url) {
        Matcher youtubeUrlMatcher = YOUTUBE_URL_PATTERN.matcher(this.verifyEmbeddedPlayerString(url));
        return youtubeUrlMatcher.matches() ? String.format("//www.youtube.com/embed/%s?wmode=opaque", youtubeUrlMatcher.group(3)) : null;     }

    public boolean matches(String url) {
        return YOUTUBE_URL_PATTERN.matcher(this.verifyEmbeddedPlayerString(url)).matches();
    }

    private String verifyEmbeddedPlayerString(String url) {
        return !url.contains("feature=player_embedded&") ? url : url.replace("feature=player_embedded&", "");
    }

    public String getEmbeddedHtml(String url, Map<String, String> params) {
        return this.velocityRenderService.render(this.getEmbedUrl(url), this.setDefaultParam(params));
    }

getEmbeddedHtml下断点,会先挪用getEmbedUrl对用户传入的url举行正则婚配,由于我们传入的是个一般的的Youtube视频,以是这里是没有问题的,挪用然后setDefaultParam函数对传入的其他参数举行处置惩罚。

 private Map<String, String> setDefaultParam(Map<String, String> params) {
        String width = (String)params.get("width");
        String height = (String)params.get("height");
        if (!params.containsKey("_template")) {
            params.put("_template", "com/atlassian/confluence/extra/widgetconnector/templates/youtube.vm");
        }

        if (StringUtils.isEmpty(width)) {
            params.put("width", "400px");
        } else if (StringUtils.isNumeric(width)) {
            params.put("width", width.concat("px"));
        }

        if (StringUtils.isEmpty(height)) {
            params.put("height", "300px");
        } else if (StringUtils.isNumeric(height)) {
            params.put("height", height.concat("px"));
        }

        return params;
    }

掏出width状语从句:height来推断是不是为空,为空则设置默许值。的症结_template参数来了,若是外部传入的参数没有_template,则设置默许的的Youtube模板。若是传入了,就运用传入的,也就是说,AAAA是胜利的传进来了。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析

也许翻了一下Widget Connector内里的衬着器,大部分是不克不及设置_template的,是直接写死了,也有一些破例,如Youtube,Viddler,DailyMotion等,是能够从外部传入_template的。

通报能_template了,接下来看下是怎样取模板和衬着模板的。

跟进this.velocityRenderService.render,就是也。com/atlassian/confluence/extra/widgetconnector/services/DefaultVelocityRenderService.class内里的render要领。

 public String render(String url, Map<String, String> params) {
        String width = (String)params.get("width");
        String height = (String)params.get("height");
        String template = (String)params.get("_template");
        if (StringUtils.isEmpty(template)) {
            template = "com/atlassian/confluence/extra/widgetconnector/templates/embed.vm";
        }

        if (StringUtils.isEmpty(url)) {
            return null;
        } else {
            Map<String, Object> contextMap = this.getDefaultVelocityContext();
            Iterator var7 = params.entrySet().iterator();

            while(var7.hasNext()) {
                Entry<String, String> entry = (Entry)var7.next();
                if (((String)entry.getKey()).contentEquals("tweetHtml")) {
                    contextMap.put(entry.getKey(), entry.getValue());
                } else {
                    contextMap.put(entry.getKey(), GeneralUtil.htmlEncode((String)entry.getValue()));
                }
            }

            contextMap.put("urlHtml", GeneralUtil.htmlEncode(url));
            if (StringUtils.isNotEmpty(width)) {
                contextMap.put("width", GeneralUtil.htmlEncode(width));
            } else {
                contextMap.put("width", "400");
            }

            if (StringUtils.isNotEmpty(height)) {
                contextMap.put("height", GeneralUtil.htmlEncode(height));
            } else {
                contextMap.put("height", "300");
            }

            return this.getRenderedTemplate(template, contextMap);
        }
    }

_template掏出来赋值给template,其他通报进来的参数掏出来经由推断以后放入到contextMap,挪用getRenderedTemplate函数,也就是挪用VelocityUtils.getRenderedTemplate

  protected String getRenderedTemplate(String template, Map<String, Object> contextMap){
        return VelocityUtils.getRenderedTemplate(template, contextMap);
    }

一起挪用,挪用链以下图,来到求末了/com/atlassian/confluence/util/velocity/ConfigurableResourceManager.classloadResource函数,来猎取模板。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析

这里挪用了4个ResourceLoader去取模板。

com.atlassian.confluence.setup.velocity.HibernateResourceLoader
org.apache.velocity.runtime.resource.loader.FileResourceLoader
org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
com.atlassian.confluence.setup.velocity.DynamicPluginResourceLoader

这里重要看下速率的自带FileResourceLoader状语从句:ClasspathResourceLoader

FileResourceLoader用户会对传入的模板途径运用normalizePath函数举行校验

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析

【FreeBuf字幕组】HackerOne优秀白帽黑客采访系列-Joel Margolis

人物介绍 Joel Margolis,别名@teknogeek,纽约罗彻斯特理工学院网络安全系学生,曾经专注于移动安全研究,擅长逆向工程,喜欢CTF比赛,现在转向做Web安全研究。Joel在HackerOne上提交的有效漏洞为56个,获得Uber、Yahoo和Airbnb等知名厂

能够看到,过滤了/../,如许就致使没有办法跳目次了。
Confluence未受权 RCE (CVE-2019-3396) 破绽剖析

过滤途径后挪用findTemplate查找模板,可看到,会拼接一个流动的path,这是合流的装置途径。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析

如今也就是说能够应用FileResourceLoader来读取合流目次下面的文件了。

读取实验/WEB-INF/web.xml文件,能够看到,是胜利的加载到了该文件。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析

然则这个没法跳出合流的目次,由于不克不及用/../

再来看下ClasspathResourceLoader

public InputStream getResourceStream(String name) throws ResourceNotFoundException {
       InputStream result = null;
       if (StringUtils.isEmpty(name)) {
           throw new ResourceNotFoundException(“No template name provided”);
       } else {
           try {
               result = ClassUtils.getResourceAsStream(this.getClass(), name);
……
           }

跟进ClassUtils.getResourceAsStream

  public static InputStream getResourceAsStream(Class claz, String name) {
        while(name.startsWith("/")) {
            name = name.substring(1);
        }

        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        InputStream result;
        if (classLoader == null) {
            classLoader = claz.getClassLoader();
            result = classLoader.getResourceAsStream(name);
        } else {
            result = classLoader.getResourceAsStream(name);
            if (result == null) {
                classLoader = claz.getClassLoader();
                if (classLoader != null) {
                    result = classLoader.getResourceAsStream(name);
                }
            }
        }

        return result;
    }

会跳到/org/apache/catalina/loader/WebappClassLoaderBase.class

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析跟进,发明会拼接/WEB-INF/classes,个中并且也是挪用了normalize对传入的途径举行过滤..

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析照样这里能够用../跳一级目次。

实验读取一下../web.xml,能够看到,也是能够读取胜利的,然则依然没法跳出目次。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析我这里测试用的版本是6.14.1,然后实验了file://http://https://都没有胜利。厥后我实验把曲奇删掉,发明照样能够读取文件,确认了这个破绽不需要权限,然则跳不出目次。应急就在这里卡住了。

然后的几天,大佬有说用file://协定能够跳出目次限定,我惊了,我肯定事先是已试过了,没有胜利的。看了大佬的截图,发明用的是6.9.0的版本,我下载了,实验了一下,发明真的能够。

照样问题在ClasspathResourceLoader上面,步调和之前的是一样的,到断/org/apache/catalina/loader/WebappClassLoaderBase.classgetResourceAsStream要领

拼接前面/WEB-INF/classes电子杂志失利后,继承往下举行。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析跟进findResource,函数前面依然猎取失利

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析症结的处所就在这里,会挪用super.findResource(name),这里返回了网址,也就是能猎取到工具。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析不仅如此,这里还能够运用其他协定(HTTPS,FTP等)猎取长途的工具,意味着能够加载长途的工具。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析猎取到URL工具以后,继承回到之前的getResourceAsStream,能够看到,当返回的URL不为空时,

挪用会url.openStream()电子杂志数据。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析终究猎取到数据给速率衬着。

实验一下
Confluence未受权 RCE (CVE-2019-3396) 破绽剖析至于6.14.1为啥不可,赶着应急,后续会跟,若是有新的发明,会同步上来,只现在看到ClassLoader不一样。

6.14.1
Confluence未受权 RCE (CVE-2019-3396) 破绽剖析6.9.0

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析这两个装载机的干系以下

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析如今能够加载当地和长途模板了,能够实验举行RCE。

关于速率的RCE,基本上有效载荷都来源于15年入侵者的服务端模板注入的议题,然则在合流上用不了,由于在挪用要领的时刻会经由velocity-htmlsafe-1.5.1.jar,内里多了一些过滤和限定。然则依然能够应用反射来实行敕令。

python -m pyftpdlib -p 2121开启一个简朴的FTP服务器,将有效载荷生存成rce.vm,生存在以后目次。

_template设置分类中翻译ftp://localhost:2121/rce.vm,发送,胜利实行敕令。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析关于敕令回显,一样能够运用反射组织出有效载荷,实行ipconfig的查询查询效果。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析破绽影响

依据ZoomEye网络空间搜刮引擎对症结字“X-Confluence”举行搜刮,共获得61,856条效果,重要散布美国,德国,中国等国度。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析环球散布(非破绽影响局限)

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析
Confluence未受权 RCE (CVE-2019-3396) 破绽剖析

中国散布(非破绽影响局限)

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析

破绽检测

2019年4月4日,404实验室宣布了该破绽的检测PoC,能够应用这个PoC检测Confluence是不是受该破绽影响。

Confluence未受权 RCE (CVE-2019-3396) 破绽剖析

【FreeBuf字幕组】HackerOne优秀白帽黑客采访系列-Joel Margolis

人物介绍 Joel Margolis,别名@teknogeek,纽约罗彻斯特理工学院网络安全系学生,曾经专注于移动安全研究,擅长逆向工程,喜欢CTF比赛,现在转向做Web安全研究。Joel在HackerOne上提交的有效漏洞为56个,获得Uber、Yahoo和Airbnb等知名厂


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明Confluence未受权 RCE (CVE-2019-3396) 破绽剖析
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址