Jira 文件读取分析(CVE-2021-26086)
九五二七 漏洞分析 38535浏览 · 2021-08-23 02:10

Jira 文件读取分析(CVE-2021-26086)

安装

先下载最新版和有漏洞的版本并安装上,地址: https://www.atlassian.com/software/jira/update

远程调试

安装好了之后,顺便做了远程调试,网上搜索了下,发现在 CVE-2019-11581 Atlassian Jira未授权模板注入漏洞分析 中讲了调试方法,是使用插件的方式,但是感觉有点复杂。看了下 Jira 是用 tomcat 起的,那就直接在 tomcat 的启动过程中加上调试即可。

catalina.bat 中加入以下调试语句:

set JAVA_OPTS=%JAVA_OPTS% -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=0.0.0.0:9999

漏洞定位

由于不是补丁的形式,而且官方公告也没有指出具体漏洞信息(也有可能没有看到),所以只能下载了有漏洞版本和非漏洞版本的文件,然后写个脚本计算所有文件的 md5,比较各个文件的 md5 变化,最后输出发生改变的文件:

import os
import sys
import hashlib



files_md5 = {}
new_files_md5 = {}

def md5sum(path,files_md5_set):
    for i in os.listdir(path):
        md5 = hashlib.md5()
        file = os.path.join(path, i)
        if os.path.isfile(file):
            with open(file,mode='rb') as fd:
                while True:
                    data = fd.read(4096)
                    if data:
                        md5.update(data)
                    else:
                        file_modify = file[file.find("/"):]
                        files_md5_set[file_modify] = md5.hexdigest()
                        break
        else:
            md5sum(file,files_md5_set)

if __name__ == '__main__':
    md5sum(sys.argv[1],files_md5)
    md5sum(sys.argv[2],new_files_md5)
    set1 = set(files_md5.items())
    set2 = set(new_files_md5.items())
    for item in (set1 ^ set2):
        print(item,end='')
        print("\n")

把得到的数据去重整理了下:

结合修复公告尽可能排除其他漏洞修改的文件:

然后先看 class 文件,并先排除 jsp 文件,很快定位到了 CachingResourceDownloadRewriteRule 文件:

感觉这个类有点熟悉,网上一搜,发现以前出现过漏洞:

瞬间感觉稳了,应该是一个绕过,马上 diff 一下 8.5.138.5.14 两个版本:

8.5.13 版本中,

Pattern PATHS_ALLOWED = Pattern.compile("^/s/(.*)/_/((?i)(?!WEB-INF)(?!META-INF).*)");

/s/xxx/_/后不允许有 WEB-INFMETA-INF;

8.5.14 版本中

Pattern PATHS_DENIED = Pattern.compile("[^a-zA-Z0-9]((?i)(WEB-INF)|(META-INF))[^a-zA-Z0-9]")

如果在 WEB-INF 或者 META-INF 的前后有特殊字符,则返回 null;

漏洞复现

实际上是针对 "^/s/(.*)/_/((?i)(?!WEB-INF)(?!META-INF).*)" 正则的绕过,只要在 /s/xxx/_/ 后面不以 WEB-INF 或者 META-INF 开头即可,想着用 /xxx/../ 不是妥妥的绕过吗?结果发现代码中已有过滤:

而且还有对多重 URL 编码的防御:

最后剩下个 ; 貌似可以,绕过之:

1 条评论
某人
表情
可输入 255