问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
XStream CVE-2021-21341拒绝服务漏洞漏洞分析
漏洞分析
XStream是一个常用的Java对象和XML相互转换的工具。CVE-2021-21341是Stream是2021年爆出的一个拒绝服务漏洞分析。和常见的命令执行漏洞、JNDI注入漏洞不同,拒绝服务漏洞往往是代码逻辑上的漏洞,利用链构造十分巧妙,因此就来分析一下。
XStream是一个常用的Java对象和XML相互转换的工具。CVE-2021-21341是Stream是2021年爆出的一个拒绝服务漏洞分析。和常见的命令执行漏洞、JNDI注入漏洞不同,拒绝服务漏洞往往是代码逻辑上的漏洞,利用链构造十分巧妙,因此就来分析一下。 漏洞原理 ---- 漏洞的利用链前半部分和CVE-2020-26217相同,思路也很像,都是利用Base64Data.get方法,替换一个恶意的InputStream,区别在于之前的入口被封了,因此使用PriorityQueue+ObservableList$1的方法调用到Base64Data的toString。需要注意的是ObservableList这个类只有较高版本JDK会创建内部匿名的compartor。xstream的反序列化漏洞一个很重要的特点是可以利用没有实现Serializable接口的类。 利用链如下 ```Java PriorityQueue.readObject() PriorityQueue.heapify() PriorityQueue.siftDown() PriorityQueue.siftDownUsingCompartor javaFx.collections.ObservableList$1 com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data.toString com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data.get com.sun.xml.internal.bind.v2.util.ByteArrayOutputStreamEx.readFrom while(True) ... ``` 核心的利用点在于ByteArrayOutputStreamEx的 readFrom()方法,该方法while(true)进行条件判断 ```Java public void readFrom(InputStream is) throws IOException { while(true) { if (this.count == this.buf.length) { byte[] data = new byte[this.buf.length * 2]; System.arraycopy(this.buf, 0, data, 0, this.buf.length); this.buf = data; } int sz = is.read(this.buf, this.count, this.buf.length - this.count); if (sz < 0) { return; } this.count += sz; } } ``` 在read函数中,会计算count-pos值,并且如果len大于这个值时,就会判断这个值是否大于0,如果小于等于0则返回0,这里本来的作用是是计算是否已经读完数据。但是如果将pos设置为int类型的最小值,count设置为0,那么count-pos则会等于pos。这和int类型在Java中的存储方式有关,java中最大的正数是2147483647,存储成二进制格式就是011111111111111111111111111111111,而如果此时再加1,则会变成10000000000000000000000,这其实是Java中int类型最小值-2147483648所对应的二进制数,同样的,0减一个负数,实际的数值等于这个负数取反并加一, 10000000000000000000000取反为011111111111111111111111111111111,再加一就又变成了最小的负数。从而陷入了readFrom的循环中。 [![](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-eb6d75e94c4fed7777a1924fd568184891c2ffbc.png)](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-eb6d75e94c4fed7777a1924fd568184891c2ffbc.png) POC构造 ----- 在poc的构造中,如果试图直接从结果入手,演算xstream的处理流程,会比较复杂,简单的方法是构造出对应的对象,然后再调用toXML即可获得恶意XML文本。构造的过程如下: 确定利用链→构造出对应的对象→调用toXML方法 ### Source 首先确定一个可以利用的入手点,漏洞作者找到的是PriorityQueue,xstream会调用这个类的readObject方法。 ### Gadget 在PriorityQueue的利用中,需要找一个危险的comparator。作者找的这个comparator很独特,它是一个匿名类,藏在javafx.collections.ObservableList这个类的一个方法中,在Java中,就算是匿名类,在运行中也会存储一个类名,按照在代码中的定义顺序,在外部类名后增加$1、$2等依次排序。 ```Java public default SortedList<E> sorted() { Comparator naturalOrder = new Comparator<E>() { @Override public int compare(E o1, E o2) { if (o1 == null && o2 == null) { return 0; } if (o1 == null) { return -1; } if (o2 == null) { return 1; } if (o1 instanceof Comparable) { return ((Comparable) o1).compareTo(o2); } return Collator.getInstance().compare(o1.toString(), o2.toString()); } }; return sorted(naturalOrder); } ``` 在这个类中只有这一个匿名类,因此这个匿名类的名字就是javafx.collections.ObservableList$1,利用Class.forName可以找到这个类。接下来是实例化这个类,在Xstream中对类的实例化使用的是Unsafe类的allocateInstance方法,这个方法可以在不使用构造方法的情况下直接实例化对象,这里构造poc也同样可以使用这个方法。 这个类的compare调用了比较对象的toString方法,下一步是找一个可用的toString方法,作者使用的是Base64Data这个类,这个类不是第一次出现了,在Xstream2020年爆出的3个漏洞中都使用了它。由于入口被封,因此这里换了一个方法进行触发。它的特点是toString→get→ByteArrayOutputStreamEx.readFrom() ### Slink ByteArrayOutputStreamEx.readFrom()中使用了while(True)读取数据,is.read()返回0,则循环永远不会结束。
发表于 2021-08-30 15:42:54
阅读 ( 5198 )
分类:
漏洞分析
0 推荐
收藏
0 条评论
请先
登录
后评论
无糖
8 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!