前文已经讲过XStream的反序列化特性及漏洞产生的原因,以及<=1.4.6版本的几个gadget,在此背景上,本节准备复现披露的几个RCE CVE,正向分析下。
XStream团队很有意思,安全公告会把POC也公开,具体可以看https://x-stream.github.io/security.html。
CVE-2020-26217
这个其实就是Wh1t3p1g师傅中提到的第4个ImageIO gadget,在marshalsec gadgets ImageIO中也有,下面正向跟踪下。
Wh1t3p1g师傅的POC
1 | <map> |
简单解释下调用链:
1 | # 1. XStream 处理Map类型 去调用 |
官网的POC
1 | <map> |
两个POC大同小异,最不同点在FilterIterator的构造,涉及到filter.filter(elt) 中的elt是如何实现可控的
控制elt
这里是FilterIterator类的代码,目标是控制filter.filter(elt)中的elt,注意比较两个POC在FilterIterator这里的区别
1 | #javax.imageio.spi.FilterIterator |
官网的java.util.ArrayList$Itr实现
用的是java.util.ArrayList$Itr
其中需要注意ArrayList.this,当ArrayList add/grow,都会更新ArrayList.elementData,所以iter.next()成功取到ProcessBuilder实例。Wh1t3p1g师傅的java.util.Collections$EmptyIterator实现
用的是java.util.Collections$EmptyIterator,这里注意嵌套了两层1
2
3
4
5Iterator it = makeFilterIterator(
makeFilterIterator(Collections.emptyIterator(), obj, null),
"foo",
filter
);这里的控制elt的思路如下:
- step1:利用的是EmptyIterator hasNext() 为false,构造了第一层FilterIterator iter1,使得iter1.next() = iter1.next
- step2:再构造一层 FilterIterator iter2,iter2.iter=iter1,使得iter2.next() = iter2.iter1.next() = iter2.iter1.next
黑名单:
1 | javax.imageio.ImageIO$ContainsFilter |
CVE-2021-21344
author: 钟师傅
POC
1 | <java.util.PriorityQueue serialization='custom'> |
分析
从POC中可以看出
- 最终的RCE触发点是JdbcRowSetImpl jndi类型注入漏洞
- 出发点是PriorityQueue自动调用compare方法
PriorityQueue这个也是cc链中被用到的,PriorityQueue实现了Serializable,且重写了readObject。
1 | private void readObject(java.io.ObjectInputStream s) |
heapify 是个排序操作,调用了每个key的compare方法
具体的调用链如下
1 | java.util.PriorityQueue#heapify |
个人认为这个关键利用点是com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$GetterSetterReflection#get
1 | public final Method getter; |
在Java原生反序列化中,这里非Serializable并没有问题,但是XStream不受限制所有类都可以实例化,导致了中间可以有很多节点可以用来作为构造链的节点。
黑名单:
1 | denyTypeHierarchyDynamically("javax.sql.rowset.BaseRowSet"); |
CVE-2021-21345
author:钟师傅
POC
1 | <java.util.PriorityQueue serialization='custom'> |
分析
长得很像,出发点是一样的PriorityQueue,RCE触发点是com.sun.corba.se.impl.activation.ServerTableEntry
1 | private String activationCmd; |
黑名单:
1 | com.sun.corba.se.impl.activation.ServerTableEntry |
CVE-2021-21346
author: wh1t3p1g
POC
1 | <sorted-set> |
分析
这个是wh1t3p1g师傅上交的,实际为ysomap里的LazyValue,师傅给的调用链分析
1 | javax.naming.ldap.Rdn$RdnEntry.compareTo |
注意官网poc里面的是
黑名单:
1 | sun.swing.SwingLazyValue |
CVE-2021-21347
author: threedr3am
POC
1 | <java.util.PriorityQueue serialization='custom'> |
分析
这个POC的RCE触发点是com.sun.tools.javac.processing.JavacProcessingEnvironment$NameProcessIterator
1 | ClassLoader processorCL; |
构造一个有evil code的static代码块类,打包jar
1 | public class ExploitStaticCalc { |
1 | jar cvf Exploit.jar ExploitStaticCalc.class |
参考【2】原文中有提到几点有意思的,这里就不复述了
- XStream 的outer-class
- 匿名内部类
- 不同java版本下ObservableList、ProtectionDomain的不同导致POC要做相应的修改
但是在测试的时候,8u60、8u172都失败,8u231成功。失败的报错事com.sun.tools.javac.processing.AnnotationProcessingError,判断应该是processorCL 结构问题,对比8u231跟踪到java.lang.ClassLoader#defineClass1,参数基本一样,但是loadClass失败,未排查到原因。
太菜鸡了。。。
黑名单:
1 | om.sun.tools.javac.processing.JavacProcessingEnvironment$NameProcessIterator |
CVE-2021-21350
author: thread3am
POC
1 | <java.util.PriorityQueue serialization='custom'> |
分析
这个和CVE-2021-21347类似,这是把远程jar改为了BCEL方式加载,相应的将processorCL改为了com.sun.org.apache.bcel.internal.util.ClassLoader。
在8u60环境下同样遇到processorCL构造的问题,更新为Wh1t3p1g师傅构造BCEL的方式之后运行成功。具体可以参考LazyIterator 中的poc。
黑名单:
1 | private static final Pattern BCEL_CL = Pattern.compile(".*\\.bcel\\..*\\.util\\.ClassLoader"); |
CVE-2021-21351
author: wh1t3p1g
POC
1 | <sorted-set> |
需要注意的是:
- 低版本的jdk中没有__overrideDefaultParser,在8u121上测试失败,8u172上成功,8u251测试失败,原因是高版本jdk jndi注入受JEP290影响。
分析
这个也是ysomap中的XercesValue payload。
触发点在IncrementalSAXSource_Xerces.parseSome
1 | private boolean parseSome() |
其中fConfigParse、fPullParserConfig、parmsfalse都可控
黑名单:
1 | denyTypeHierarchyDynamically("javax.sql.rowset.BaseRowSet"); |
ServiceFinder$LazyIterator
POC
1 | <map> |
分析
重点是Wh1t3p1g师傅BCEL的 classLoader的构造思路及过程,可看师傅原博。
黑名单:
1 | private static final Pattern BCEL_CL = Pattern.compile(".*\\.bcel\\..*\\.util\\.ClassLoader"); |
CVE-2021-29505
1 | <map> |
XStream的防御措施
黑名单
在>1.4.6之后的版本中,XStream引入了安全机制,以避免反序列化问题。
Wh1t3p1g师傅《回顾XStream反序列化漏洞》一文中0x03一节中解释得很好了,这里不赘述。贴一下参考【2】中提到的最新版1.4.16的黑名单。
1 | private static final String ANNOTATION_MAPPER_TYPE = "com.thoughtworks.xstream.mapper.AnnotationMapper"; |
自此,把基于jdk的现有已知链都block掉了。第三方的链(如Groovy)还在存活中,之后的发展趋势,不知道会不会类似fastjson/jackson之类的,开始漫长的block三方链。
白名单
XStream在1.4.10版本增加了setupDefaultSecurity方式来设置默认的白名单,仅默认支持基础类的实例化。
小结
本节复现了1.4.6之后的几个POC,主要是跟踪RCE漏洞触发点,至于链是如何构造的本节未做研究,这个作为下节的内容重点研究研究。
过程中遗留了1个现在解决不了的问题,CVE-2021-21347 8u60下的URLClassLoader构造存在问题,未解决,如果有大佬遇到并解决,求分享,不胜感激。
总结下XStream的反序列化特点
在Java原生反序列化中,可实例化的类必须是Serializable的,但是XStream不受限制所有类都可以实例化,这点和fastjson/jackson之类的一样。
fastjson/jackson实现类属性赋值,都是通过getsettr/setsettr来实现的(只是有些调用条件不同),XStream是通过Conveter的逻辑来实现(SerializableConveter也支持Java原生反序列化readObject)。
- 为什么fastjson/jackson 存在jdk反序列化链没有XStream的多?因为并不是所有的类的属性都严格实现了get/set,导致很多jdk类不能完全还原。
XStream的某些Conveter是存在问题的
- MapConverter/TreeSetConveter/TreeMapConveter都会触发这些集合/表 内元素的内部函数,比如compare、hashcode、equal这些函数。
- DynamicProxyConverter 代理类,InvocationHandler可控,导致一些invoke存在RCE风险的InvocationHandler类,如EventHandler,可以加以利用。
总结下RCE触发点
- invoke 实现上有问题的 InvokeHandler,如
- EventHandler
- 搭配MethodClosure的ConvertedClosure
- hashCode、compare、equal实现有问题的Map/Set/Queue,如
- Expando,hashCode搭配MethodClosure可以RCE
- CVE-2021-21345 ServerTableEntry verify方法可RCE
- 存在invoke,且method、obj可控的class(这一类普遍存在)
- CVE-2020-26217 ImageIO$ContainsFilter,filter方法内可控
- CVE-2021-21344 Accessor$GetterSetterReflection,get方法可控
- CVE-2021-21351 IncrementalSAXSource_Xerces parseSome方法内invoke可控
- 利用ClassLoader实例化
- ServiceLoader$LazyIterator,调用点为Class.forName (name,initialize,loader) ,指定loader为BCEL classLoaer
- CVE-2021-21347,调用点为loader.loadClass(name).newInstance(),利用java.net.URLClassLoader加载远程jar类并实例化
- CVE-2021-21350,和LazyIterator一样,利用BCEL classLoader
总结下Bullet(ysomap概念)
- ProcessBuilder.start() 无参数
- Runtime.getRuntime().exec(cmd) 有参
- JdbcRowSetImpl.connect()/prepare()/getDatabaseMetaData()/setAutoCommit(var1) 无参
- MethodClosure.call() 无参
有参的case比较少见,GroovyConvertedClosure是一例
参考
- [1] 回顾XStream反序列化漏洞
- [2] Xstream 反序列化远程代码执行漏洞深入分析
- [3] CVE-2020-26217
- [4] CVE-2021-21344
- [5] CVE-2021-21345
- [6] CVE-2021-21346
- [7] CVE-2021-21347
- [8] CVE-2021-21350
- [9] CVE-2021-21351