知识点
反序列化并不只存在于php,也存在各种语言中,如java、python等。 在学习java反序列化之前,我们需要知道一个基础知识:重写。
重写
重写,顾名思义就是重新改写该方法,从而达到想要的结果。需要注意的是:
只有拥有继承关系时才能重写,也就是说,只能重写父类的同名方法。方法重写时, 方法名与形参列表必须一致。方法重写时,子类的权限修饰符必须要大于或者等于父类的权限修饰符。方法重写时,子类的返回值类型必须要小于或者 等于父类的返回值类型。方法重写时, 子类抛出的异常类型要小于或者等于父类抛出的异常类型。 Exception(最坏) RuntimeException(小坏) (顺带提一嘴重载,重载就是一个类里的两个或以上同名方法就是方法重载,两个函数的参数类型或者参数数目必须不一样,但函数名一致)
代码准备
正常序列化
package com
.sertest
;
import java
.io
.*
;
import java
.io
.Serializable
;
class SerObj implements Serializable
{
public String name
;
public int time
;
}
public class ser{
public static void main(String args
[]) throws Exception
{
SerObj serObj
= new SerObj();
serObj
.name
= "serobj";
serObj
.time
= 10;
FileOutputStream fos
= new FileOutputStream("object.ser");
ObjectOutputStream oos
= new ObjectOutputStream(fos
);
oos
.writeObject(serObj
);
oos
.close();
fos
.close();
}
}
正常反序列化
package com
.sertest
;
import java
.io
.*
;
public class Unser {
public static void main(String args
[]) throws Exception
{
FileInputStream fis
= new FileInputStream("object.ser");
ObjectInputStream ois
= new ObjectInputStream(fis
);
SerObj deSerobj
= (SerObj
) ois
.readObject();
System
.out
.println(deSerobj
.name
);
ois
.close();
fis
.close();
}
}
此时的结果时正常的。
重写readobject方法后的恶意代码
package com
.sertest
;
import java
.io
.*
;
class Evil implements Serializable
{
public String name
;
public int time
;
private void readObject(java
.io
.ObjectInputStream in
) throws IOException
, ClassNotFoundException
{
in
.defaultReadObject();
Runtime
.getRuntime().exec("calc.exe");
}
}
public class hack_test {
public static void main(String args
[])throws Exception
{
Evil h2
= new Evil();
h2
.name
= "serobj";
h2
.time
= 10;
FileOutputStream fos
= new FileOutputStream("hack.ser");
ObjectOutputStream os
= new ObjectOutputStream(fos
);
os
.writeObject(h2
);
os
.close();
}
}
反序列化代码:
package com
.sertest
;
import java
.io
.*
;
public class Unser {
public static void main(String args
[]) throws Exception
{
FileInputStream fis
= new FileInputStream("hack.ser");
ObjectInputStream ois
= new ObjectInputStream(fis
);
Evil deSerobj
= (Evil
) ois
.readObject();
System
.out
.println(deSerobj
.name
);
ois
.close();
fis
.close();
}
}
此时在反序列化时,由于恶意代码重写了readObject,所以在调用时调用的是已经被重写的readObject方法,执行了恶意代码。
本来想试行一下把这两个打包成jar文件包,然后一个用来序列化数据一个用来反序列化数据,奈何java编程水平有限,只能做到这个地步。实际上生成恶意序列化数据的时候肯定要使用同一个类名和变量名,不然会因类名不同而报错,那就不能成功了。 以后有时间的话看能不能写一个简单的链出来,再了解一下JAVA的反射机制,这样能对相关的利用就能有一定程度的理解了。 参考文章: https://www.cnblogs.com/Fluorescence-tjy/p/11222052.html