「JOJO這是我最後的波紋了!你收下吧!」-《JOJO的奇妙冒險》
第 26~29 天都會專注在 CVE-2022-28219 這個漏洞上,這個漏洞可以堪稱為 OWASP Top 10 教科書級別的漏洞。其中手法部分包含了 OWASP Top 10 2017 的 A4 XXE 手法以及 A8 不安全反序列化,外加這個軟體又是微軟的 Active Directory 服務的 Audit 軟體,也就是說光是要學習這個漏洞就需要使用 2種 OWASP Top 10 攻擊手法外加建立 Active Directory 服務,根本就賺爛了賺爛了。所以這系列會分成四集說明,就先來看看這個漏洞的相關資訊。
漏洞相關資訊
第一個部分先從不安全反序列化攻擊原理開始介紹起,但要先說說何為序列化及反序列化。假如有個物件定義如下,其本身是負責將設定的 IP 資料並透過 nslookup 進行反查,但今天有個需求是要把該物件的狀態傳送另一台伺服器上進行處理,那試著想想會怎麼做?
Serialization.java
import java.util.*;
import java.io.*;
public class Serialization implements Serializable {
private static final long serialVersionUID = 1L;
public Serialization() {
System.out.println("Call Serialization()");
}
private String command = "nslookup" ;
public String ip = "";
public void setIP(String ip) {
this.ip = ip;
}
public String getIP() {
return this.ip;
}
public void executeCommand() {
try {
Runtime rt = Runtime.getRuntime ();
Process proc = rt.exec (command + " " + ip);
int exitVal = proc.exitValue ();
System.out.println ("Process exitValue: " + exitVal);
} catch (Exception e) {
e.printStackTrace ();
}
}
}
簡單來說可以只把 IP 的數值部分傳送給伺服器,之後設定把數值設定到物件後,呼叫 executeCommand() 即可。但是試著想想,如果該物件定義很複雜,或是該物件又有包含其他物件,那該怎麼節省開發的時間? 這時候就可以透過所謂的物件序列化功能。
所謂的序列化,就是把儲存在記憶體中的物件狀態轉換成某種資料格式,儲存在檔案、資料庫、記憶體中,再經由媒介傳送給另外一端後,透過反序列化還原回原本的物件。這個功能很多程式語言都有支援,像是 Java、.Net、Python 都有。
資料來源 : Serialization vs deserialization
但萬一反序列化的時候沒有驗證資料來源,就會延伸出所謂的不安全的反序列化問題。也就是說一旦直接反序列化駭客精心製作的資料,就可能造成無法想像的後果。一般來說,不安全的反序列化有兩種進攻方式。
第一種是針對反序列化的邏輯進行攻擊,導致反序列化執行的功能與想像中的不同。以上面的物件定義例子來說,當今天駭客竄改物件的 command 數值時,再去引發呼叫 executeCommand() 就可以達到 RCE 的效果。接著就先來建立一下這個環境。
Sender.java
import java.util.* ;
import java.io.* ;
public class Sender {
public static void main(String [] args) throws Exception {
File file = new File("test.ser");
ObjectOutputStream objOutputStream = new ObjectOutputStream(new FileOutputStream(file));
Serialization ss = new Serialization();
ss.setIP("127.0.0.1");
objOutputStream.writeObject(ss);
objOutputStream.close();
}
}
Receiver.java
import java.util.*;
import java.io.*;
public class Receiver implements Serializable {
public static void main(String [] args) throws Exception {
File file = new File("test.ser");
FileInputStream fileInputStream =
new FileInputStream(file);
ObjectInputStream objInputStream =
new ObjectInputStream(fileInputStream);
Serialization ss = (Serialization)objInputStream.readObject();
System.out.println("IP is "+ss.getIP());
ss.executeCommand();
objInputStream.close();
}
}
步驟如下 :
步驟如下 :
參考資料 :