0x00 前置知識
1. classloader defineClass
該方法允許將符合class格式的bytes數組,作為類去加載。該方法返回一個Class對象。
一般情況下,通過defineClass加載的類,不允許同名,否則會報錯,切記
2. java asm& javaassist
既然上面說了,defineClass不允許加載同名類。所以我們需要動態構建class,並生成bytes數組。在java中一般使用asm或者javaassist通過jvm字節碼,直接生成一個class。兩種各有優缺點。
- asm語法復雜,需要熟悉jvm底層知識。運行速度快
- javaassist 語法簡單,運行速度慢
在這里推薦一個asm插件,可以將class一鍵轉換為asm的java代碼,並輸出bytes。然后再按需修改class的相關參數
3. java反序列化的transient參數
protected transient Class<? extends Remotable> m_clz;
protected transient MethodHandle m_mhCtor;
transient參數修飾的變量,是不參與反序列化的。最終變量值為null
0x01 cve-2020-14644 漏洞分析
簡單來講,該漏洞在反序列化時通過defineClass直接加載類。下面是待加載的類
下面我們從RemoteConstructor
的newInstance開始分析,斷點設置以及調用堆棧如下
newInstance的代碼如下
public T newInstance() {
RemotableSupport support = RemotableSupport.get(this.getClassLoader());
return support.realize(this);
}
RemotableSupport可以認為是coherence自定義的Classloader。RemotableSupport中實現了defineClass。下面我們跟入RemotableSupport的realize方法,看一下realize方法都做了什么
public <T> T realize(RemoteConstructor<T> constructor) {
ClassDefinition definition = this.registerIfAbsent(constructor.getDefinition());
Class<? extends Remotable> clz = definition.getRemotableClass();
if (clz == null) {
synchronized(definition) {
clz = definition.getRemotableClass();
if (clz == null) {
definition.setRemotableClass(this.defineClass(definition));
}
}
}
Remotable<T> instance = (Remotable)definition.createInstance(constructor.getArguments());
instance.setRemoteConstructor(constructor);
return instance;
}
首先從RemoteConstructor中獲取m_definition,類型為ClassDefinition。隨后調用m_definition的getRemotableClass方法。這一句是關鍵。我們去看一下m_definition的getRemotableClass方法
可以很明顯的看到getRemotableClass方法返回的m_clz,是通過transient修飾的。所以在反序列化后,這里一定返回null。
於是就會走到if條件的另外一個分支,調用this.defineClass(definition)去加載類。通過RemotableSupport去根據給定的參數,創建一個類。
RemotableSupport的defineClass方法就很簡單了。從ClassDefinition中獲取類名,類的bytes字節,調用系統的classloader去創建一個類
protected Class<? extends Remotable> defineClass(ClassDefinition definition) {
String sBinClassName = definition.getId().getName();
String sClassName = sBinClassName.replace('/', '.');
byte[] abClass = definition.getBytes();
definition.dumpClass(DUMP_REMOTABLE);
return this.defineClass(sClassName, abClass, 0, abClass.length);
}
所以payload代碼如下
在這里我們只需要通過iiop協議,直接將RemoteConstructor對象發送給weblogic服務即可
0x02 回顯利用
在cve-2020-2551 回顯利用中,因為classloader的問題,我們需要上傳一個jar包,並區分windows與linux操作系統才可以通過URLClassloader去正確加載上傳的jar包。但是通過該漏洞,我們發現,可以直接寫好類,並轉換為bytes字節,通過反序列化發送給weblogic服務器即可。
至於回顯,無非就是給服務器安裝一個JNDI實例即可。所以我們需要加載的類的代碼如下
運行結果如下
目前代碼已上傳至 https://github.com/potats0/cve_2020_14644
后台回復14644獲取工具下載