2020年Oracle Weblogic发布了包含编号为CVE-2020-2555、CVE-2020-2883漏洞的CPU。
CVE-2020-2555和CVE-2020-2883漏洞的相似性非常高,均使用T3
协议,均利用核心的ChainedExtractor
类进行攻击,CVSS 3.0均达到9.8
,均能完成远程任意命令执行。
漏洞环境:
java version "1.8.0_112"
WebLogic 12.2.1.4.0
IDEA DEBUG
使用Y4er师傅基于weblogic_cmd修改的支持T3协议WebLogic攻击框架:
https://github.com/Y4er/CVE-2020-2555
CVE-2020-2555可以直接使用该框架进行攻击,CVE-2020-2883需要单独新增一个攻击模块,攻击模块来源Y4er师傅:
https://github.com/Y4er/CVE-2020-2883
导入IDEA:
因为会使用到weblogic中的jar包,所以添加lib到本地项目中:
WebLogic 12.2.1.4.0可以使用攻击框架项目自带的,其他的版本最好使用和目标版本一致的,可以从WebLogic提取。
coherence.jar的位置
/Users/rai4over/Oracle/Middleware/Oracle_Home/wlserver/server/lib/console-ext/autodeploy/coherence.jar
wlfullclient.jar需要手动生成
java -jar ~/Oracle/Middleware/Oracle_Home/wlserver/modules/com.bea.core.jarbuilder.jar
运行后在会生成wlfullclient.jar,路径为:
~/Oracle/Middleware/Oracle_Home/wlserver/server/lib/wlfullclient.jar
替换攻击框架中lib
中的jar即可。
Weblogic
开启远程调试:
vim /root/Oracle/Middleware/user_projects/domains/base_domain/bin/setDomainEnv.sh
添加配置代码:
debugFlag="true"
export debugFlag
在Middleware
目录下提取全部的jar
、war
包到test
目录。
cd /Users/rai4over/Desktop/weblogic/weblogic_jars/Oracle/Middleware
mkdir test
find ./ -name "*.jar" -exec cp {} ./test/ \;
find ./ -name "*.war" -exec cp {} ./test/ \;
新建IDEA
项目,然后添加包含test
目录到项目的Libraries
。
该编号反序列化利用的类为BadAttributeValueExpException
,先看EXP如何构造的
文件位置:
com.supeream.CVE_2020_2555#main
创建三个ReflectionExtractor
对象,第一个参数均为字符串,第二个参数均为对象,然后将三个ReflectionExtractor
元素放入ReflectionExtractor
的数组中。
先跟进ReflectionExtractor
的构造函数。
com.tangosol.util.extractor.ReflectionExtractor#ReflectionExtractor(java.lang.String, java.lang.Object[])
继续调用其他参数的构造函数
com.tangosol.util.extractor.ReflectionExtractor#ReflectionExtractor(java.lang.String, java.lang.Object[], int)
分别将第一个参数存在m_sMethod成员,第二个参数存在m_aoParam成员,放入数组后的赋值情况为:
回到主流程
创建一个ChainedExtractor
对象,并将ReflectionExtractor
数组作为构造参数传入,跟进构造函数:
com.tangosol.util.extractor.ChainedExtractor#ChainedExtractor(com.tangosol.util.ValueExtractor[])
ChainedExtractor继承AbstractCompositeExtractor类,首先将ReflectionExtractor
数组传给AbstractCompositeExtractor
父类并调用构造函数。
com.tangosol.util.extractor.AbstractCompositeExtractor#AbstractCompositeExtractor(com.tangosol.util.ValueExtractor[])
在父类的构造函数中将ReflectionExtractor
数组赋值给m_aExtractor
成员,并返回至子类ChainedExtractor
的构造函数,调用computeTarget()
完成对m_nTarget
的赋值。
com.tangosol.util.extractor.ChainedExtractor#computeTarget
是个三元表达式,对ReflectionExtractor
数组的长度,还有数组中第一个元素是否为AbstractExtractor的实例进行了判断
aExtractor != null && aExtractor.length > 0 && aExtractor[0] instanceof AbstractExtractor == true
执行aExtractor[0].getTarget()
,第一个元素调用父类AbstractExtractor
的getTarget方法
com.tangosol.util.extractor.AbstractExtractor#getTarget
返回值为0
,最终整个ChainedExtractor
对象的内容为:
返回到主流程继续
创建LimitFilter
对象,然后利用反射将上文的ChainedExtractor
对象赋值给m_comparator
成员,将Runtime.class
赋值给m_oAnchorTop
。
最终整个LimitFilter
对象的内容为
返回到主流程继续
创建一个BadAttributeValueExpException
对象,同样利用反射将LimitFilter
对象赋值到val
成员,然后将整个对象反序列化,俄罗斯套娃的最终结果
先直接跟踪到最外层的BadAttributeValueExpException类
javax.management.BadAttributeValueExpException#readObject
反序列化获取val成员,也就是LimitFilter
对象,然后调用toString方法。
com.tangosol.util.filter.LimitFilter#toString
this.m_comparator
是ChainedExtractor对象且为ValueExtractor
类实例,进入if分支,并调用this.m_comparator的extract方法,参数为this.m_oAnchorTop
,此时的this.m_comparator内容为:
com.tangosol.util.extractor.ChainedExtractor#extract
调用getExtractors
函数
com.tangosol.util.extractor.AbstractCompositeExtractor#getExtractors
返回数组:
迭代循环调用数组元素的extract方法,并且上一次循环extract的结果作为这一次的参数
com.tangosol.util.extractor.ReflectionExtractor#extract
这里method.invoke参数可控,可以进行任意反射,结合上层的循环,完成反射调用链。
简化的调用栈:
exec:485, Runtime (java.lang)
invoke:-1, GeneratedMethodAccessor239 (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
extract:121, ReflectionExtractor (com.tangosol.util.extractor)
extract:105, ChainedExtractor (com.tangosol.util.extractor)
toString:599, LimitFilter (com.tangosol.util.filter)
readObject:86, BadAttributeValueExpException (javax.management)
该编号反序列化利用的类为PriorityQueue
,先看EXP如何构造的
该编号反序列化利用的类为PriorityQueue
,先看EXP如何构造的
PriorityQueue
一个基于优先级的无界优先级队列。
优先级队列的元素按照其自然顺序进行排序,放入PriorityQueue
的元素,必须实现Comparable
接口,PriorityQueue
会根据元素的排序顺序决定出队的优先级;或者根据构造队列时提供的Comparator
进行排序,元素就不必实现Comparable
接口,具体取决于所使用的构造方法。
和前文相似,同样是创建三个ReflectionExtractor对象,放入ValueExtractor数组中。
再创建一个ValueExtractor数组
创建一个ChainedExtractor对象,ValueExtractor数组作为构造,然后将ChainedExtractor对象作为构造参数传入ExtractorComparator对象
com.tangosol.util.comparator.ExtractorComparator#ExtractorComparator(com.tangosol.util.ValueExtractor<? super T,? extends E>)
再将ExtractorComparator对象作为构造参数传入PriorityQueue
java.util.PriorityQueue#PriorityQueue(int, java.util.Comparator<? super E>)
利用反射修改ChainedExtractor对象
整个过程和CC2很相似,序列化的最终对象为:
先直接跟踪到最外层的PriorityQueue类
java.util.PriorityQueue#readObject
PriorityQueue
重写了readObject
,首先通过defaultReadObject
执行默认的反序列化操作
java.util.PriorityQueue#queue
queue
成员本来被transient
修饰,不能默认反序列化,但自定义通过循环设置成员数组queue
,此时两个关键成员:
java.util.PriorityQueue#heapify
进入heapify
进行排序,循环遍历成员数组queue
,Runtime
作为参数传入siftDown
java.util.PriorityQueue#siftDown
java.util.PriorityQueue#siftDownUsingComparator
这里的comparator是ExtractorComparator
对象,调用compare方法
com.tangosol.util.comparator.ExtractorComparator#compare
继续调用ChainedExtractor
对象的extract方法,和上文相似,迭代循环调用数组元素的extract方法,并且上一次循环extract的结果作为这一次的参数,最终完成反射
com.tangosol.util.extractor.ChainedExtractor#extract
最终的调用栈为:
exec:485, Runtime (java.lang)
invoke:-1, GeneratedMethodAccessor239 (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
extract:121, ReflectionExtractor (com.tangosol.util.extractor)
extract:105, ChainedExtractor (com.tangosol.util.extractor)
compare:71, ExtractorComparator (com.tangosol.util.comparator)
siftDownUsingComparator:721, PriorityQueue (java.util)
siftDown:687, PriorityQueue (java.util)
heapify:736, PriorityQueue (java.util)
readObject:795, PriorityQueue (java.util)
https://www.oracle.com/security-alerts/cpujan2020.html
本文作者:Rai4over
本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/140206.html