文章目录
Java代码审计篇 | ofcms系统审计思路讲解 - 篇4 | XXE漏洞审计
0. 前言
我发现很多文章包括教程,大概套路是:只说有漏洞的点,将有漏洞的点指出,然后分析代码;或者黑盒测试出漏洞之后,然后分析代码。
我认为这是在分析漏洞代码,而非代码审计。代码审计文章或教程应该是从0开始找到漏洞所在,包括思路!
所以这里不管有没有漏洞,我都会把审计过程写出来,因此篇幅会很长,但我认为这样对你会很有帮助。
知其然亦知所以然。
由于篇幅较长,因此我会分几篇进行,本篇是整个系列的第4篇,讲解1个内容:
- XXE漏洞审计
本系列文章:
- Java代码审计篇 | ofcms系统审计思路讲解 - 篇1 | 环境搭建、路由机制
- Java代码审计篇 | ofcms系统审计思路讲解 - 篇2 | SQL注入漏洞审计
- Java代码审计篇 | ofcms系统审计思路讲解 - 篇3 | 文件上传漏洞审计
- Java代码审计篇 | ofcms系统审计思路讲解 - 篇4 | XXE漏洞审计
搭建好环境,确定好项目结构之后,按我思路是应该审计项目所使用框架漏洞的,这里关于框架漏洞就放最后篇章来说了,我们先了解下基础漏洞的审计~
文章中有错误点,或者思路上有什么问题的,欢迎师傅们留言指出~
1. XXE代码审计【有1处】
XXE代码审计常搜索的关键字如下:
XMLReader
SAXBuilder
SAXReader
SAXParserFactory
Digester
DocumentBuilderFactory
...
还有一个特殊的,用于加载.jrxml
文件,这是 JasperReports 特定的 XML 格式,用于定义报告模板。
JRXmlLoader
1.1. 搜索JRXmlLoader
当然这样搜比较慢,而且有很多重复的,这里有个小技巧,可以搜到JRXmlLoader之后,然后Find Usages(Alt+F7),然后找到Usage in import查看哪些类有导入JRXmlLoader。
概涉及的类有:
JRAntApiWriteTask
JRAntUpdateTask
TableReportContextXmlRule
JasperCompileManager
JasperDesignCache
JRDesignViewer
...
挨个查看一下,需要找解析jrxml
文件的代码以及对应方法的调用情况:
这里有个小技巧:因为这些类都是导入的jar包内部的,这说明,不是每个类和方法都会被使用到;
与之不同的则是项目自己写的类和方法,一般都会被用到。
因此:我们可以先查找类中方法的调用,确定有没有使用到,没有使用到就不用管了,这样可以节省大量的时间。
1.1.1. JRAntApiWriteTask
进到JRAntApiWriteTask类中之后,在本类中同样搜索JRXmlLoader,查看哪些位置使用了JRXmlLoader:
可以看到,代码中使用了JRXmlLoader.load(srcFileName)
,这里调用了.load()
方法,这是JRXmlLoader
加载jrxml
文件的方式。
其中这段代码是在writeApi()
方法中被调用。
接下来的思路是:先查找writeApi()
方法的调用情况(原因前面已经说了)
可以看到,同类下的execute()
方法对其有调用,但是通过查找execute()
的调用,发现并没有被使用。因此,此处就不需要再往下进行了。
1.1.2. JRAntUpdateTask
进到JRAntUpdateTask类中之后,在本类中同样搜索JRXmlLoader,查看哪些位置使用了JRXmlLoader,以及方法的调用情况:
和JRAntApiWriteTask类中的情况一样,execute()
没有被调用,不用管了。
1.1.3. TableReportContextXmlRule
这个类虽然导入了JRXmlLoader,但是没有调用.load()方法,所以也不用管了
1.1.4. JasperCompileManager【存在漏洞】
这个类中的方法很多,很多方法都用到了JRXmlLoader:
我们应该怎么定位呢?
想一下我们在干嘛?是不是在寻找XXE漏洞,回想XXE原理,其中前提是:代码需要解析xml(jrxml)文件才可能有漏洞,如果是生成xml文件是不是就不用管了。
因此:我们需要定位到解析xml(jrxml)文件的地方。
在JRXmlLoader中解析使用的是load()
方法,因此我们可以在当前类中搜索.load(,
发现定位到了5个位置:
来详细看一下:
分析一下代码,方法之间进行了互相调用,当然也调用了除了上述方法之外的方法。
下面我用调用图展示一下:
这三个调用链都涉及到了load()
方法,因此都有可能存在XXE漏洞。
接下来看每个调用链最上层的方法是怎么调用的(也就是找参数sourceFileName从哪来的),三个方法分别如下:(通过Find Usages/Alt+F7查询)
-
compileReportToFile()
方法,没有被调用,即该方法没有触发,不用管了~ -
第1个
compile(String sourceFileName)
方法,被当前类的compileReport(String sourceFileName)
方法调用 -
第2个compile(InputStream inputStream)方法,被当前类的
compileReport(InputStream inputStream)
方法调用 -
compileReportToStream()
方法,没有被调用,即该方法没有触发,不用管了~
目前,只需要关注其中两个就好:
- 1)
ompileReport(String sourceFileName)
- 2)
compileReport(InputStream inputStream)
继续查看其调用关系:其中compileReport(InputStream inputStream)
存在调用,ompileReport(String sourceFileName)
没有被调用。