漏洞复现之CVE-2017-12616

CVE-2017-12616是Tomcat中间件的一个漏洞,此漏洞可以造成源码泄露。网上有很多人分析CVE-2017-12615漏洞(Tomcat任意文件上传漏洞),但是很少有人分析CVE-2017-12616。漏洞范围是Tomcat 7.0.0 - 7.0.80版本,虽然网上很少有人提操作系统的要求,但是我在复现的过程中发现只有Windows操作系统能够复现成功。

漏洞说明

用户在配置了virtual webapp的情况下,以 xxx.jsp. 的形式访问jsp文件可以获得源码。比如用户在server.xml中通过可以如下配置配置virtual webapp


			
            
        

上述配置的意思翻译成人话就是当你在URL中访问“/test”路径时会被映射到物理路径“D:\vuln\apache-tomcat-7.0.77\webapps\examples”,并且当“/examples”路径中没有你要访问的文件时会去“D:\vuln\leaked”路径中寻找。这个时候你通过“/test/test.jsp.”访问“D:\vuln\leaked”中的“test.jsp”文件时会看到他的源码(仅限于D:\vuln\leaked路径):
漏洞复现之CVE-2017-12616_第1张图片

漏洞分析

至于Tomcat源码下载以及调试配置可以参考这篇文章,中间可能会出现org.apache.catalina.startup.Bootstrap的问题,百度下或者重新下载下以来Maven中的依赖(先clean后install)然后重启下应该就解决了。具体的调试过程如下:

  1. 首先在org/apache/naming/resources/VirtualDirContext.java中打一个条件断点(条件为name.contains(‘test.jsp.’)):
    漏洞复现之CVE-2017-12616_第2张图片
  2. 步入到doLookup方法中
    漏洞复现之CVE-2017-12616_第3张图片
  3. 接着步入到file()中,可以看到file通过调用父类的file,继续跟进:
    漏洞复现之CVE-2017-12616_第4张图片
  4. 来到了父类FileDirContext.java的file方法中,在这个方法中首先new了一个File类(在File.java中定义),然后通过这个类的exists方法判断文件是否存在,在跟进file.exists方法前可以先通过Evaluate Expression工具查看下file.exists的返回值,可以看到返回值为false所以没有继续步入的必要了,直接单步跳过。注意时此时文件的路径是“\exapmles”,这刚好对应了对配置文件的解释。
    漏洞复现之CVE-2017-12616_第5张图片
  5. 如下图所示可以看到FileDirContext.java中的file方法返回null到第二步的doLookup方法中,并且通过步骤中的图片可以看到如果file为null,doLookup方法也会返回null到virtualDirContext的file方法中
    漏洞复现之CVE-2017-12616_第6张图片
  6. 回到VirtualDirContext的file方法后,首先会判断是否为空,如果不为空就返回文件,但是这里为空需要继续往下走,然后在“\leaked”文件夹中寻找看能不能够找到文件。
    漏洞复现之CVE-2017-12616_第7张图片
  7. 再一次new一个File出来,不过这次的文件路径时“D:\vuln\leaked\test.jsp.”,接着执行然后步入到exists方法中
    漏洞复现之CVE-2017-12616_第8张图片
  8. 可以看到exists方法返回了1,这个函数的返回值主要和fs.getBooleanAttributes(),单步步入查看下这个方法
    漏洞复现之CVE-2017-12616_第9张图片
  9. 可以看到这个函数是一个native函数,看不到源码,注意此函数在WinNTFileSystem.java
    漏洞复现之CVE-2017-12616_第10张图片
  10. 继续执行返回到VirtualDirContext中的file方法里可以看到已经将file返回,之后就是一路return最终将文件内容读出
    漏洞复现之CVE-2017-12616_第11张图片

疑问

  1. 为什么上调试过程返回的时jsp文件的内容,而不是执行jsp?
    答:因为jsp文件交由org/apache/jasper/servlet/JspServlet.java处理,但是由于我们访问时后缀名末尾存在“.”,所以tomcat认为其不是jsp执行文件。
  2. 漏洞点体现在哪里?
    答:可以说有两点,首先在Windows系统下以点或者空格结尾的文件名竟然判断为存在!
    漏洞复现之CVE-2017-12616_第12张图片漏洞复现之CVE-2017-12616_第13张图片漏洞复现之CVE-2017-12616_第14张图片
    而在Linux下就不会出现这种情况:
    漏洞复现之CVE-2017-12616_第15张图片
    除此之外漏洞还体现在步骤10中,可以看出此方法在对外部资源文件夹(“\leaked”)中的文件进行处理时只要判断文件存在就将其返回(197-199行),我们可以比较下FileDirContext中的File的实现代码:
//org/apache/naming/resources/FileDirContext.java:763
 protected File file(String name) {

        File file = new File(base, name);
        if (file.exists() && file.canRead()) {

            if (allowLinking)
                return file;
            
            // Check that this file belongs to our root path
            String canPath = null;
            try {
                canPath = file.getCanonicalPath();
            } catch (IOException e) {
                // Ignore
            }
            if (canPath == null)
                return null;

            // Check to see if going outside of the web application root
            if (!canPath.startsWith(absoluteBase)) {
                return null;
            }

            // Case sensitivity check - this is now always done
            String fileAbsPath = file.getAbsolutePath();
            if (fileAbsPath.endsWith("."))
                fileAbsPath = fileAbsPath + "/";
            String absPath = normalize(fileAbsPath);
            canPath = normalize(canPath);
            if ((absoluteBase.length() < absPath.length())
                && (absoluteBase.length() < canPath.length())) {
                absPath = absPath.substring(absoluteBase.length() + 1);
                if (absPath == null)
                    return null;
                if (absPath.equals(""))
                    absPath = "/";
                canPath = canPath.substring(absoluteBase.length() + 1);
                if (canPath.equals(""))
                    canPath = "/";
                if (!canPath.equals(absPath))
                    return null;
            }

        } else {
            return null;
        }
        return file;

    }

可以看到尽管文件存在且可读也会进行进一步的判断,这些判断就可以阻止后缀以点结束的文件返回。
3. 为什么只有“\leaked”文件夹中的文件可以通过这种方式看到源码而“\examples”中的不可以
答:见上一题的分析,就是因为FileDirContext.java中的file方法做了更多的过滤
4. 为什么在Linux下不能够复现此漏洞
答:见下述代码,在调用exists方法判断文件是否存在是关键函数getBooleanAttributes方法的实现不一样,注意此时java文件是UnixFileSystem.class
漏洞复现之CVE-2017-12616_第16张图片

总结

代码都是相通的Java没接触过太多也能多少调调,但是效率太低,有些细节不清楚,所以Java还得好好学学。如果一次调不懂就调多次。

你可能感兴趣的:(漏洞复现)