java安全基础知识
##java序列化和反序列化
其实和php的类似,生成序列化内容,然后反序列化序列数据。其中有一部分点事需要注意的
Java 序列化是指把 Java 对象转换为字节序列的过程
ObjectOutputStream类的 writeObject() 方法可以实现序列化
Java 反序列化是指把字节序列恢复为 Java 对象的过程
ObjectInputStream 类的 readObject() 方法用于反序列化。
- 是否具有serialize结构(Implements Serializable)
- transient表示的对象成员变量不参与序列化
- 如果该类的某个属性标识为static类型的,则该属性不能序列化。
- 如果对私有方法进行反序列化更改值的时候需要使用反射
接下来看看demo
这里写了一个java类
import java.io.Serializable; |
在这里对其进行序列化,主要使用ObjectOutputStream导入序列化流
import java.io.*; |
在这里对其进行反序列化而最后的println会调用toString方法
import java.io.FileInputStream; |
##java反序列化安全问题
java反序列化和php反序列化类似,都是去寻找可以利用的类和方法,java反序列化时即会调用readObject
###利用条件
- 反序列化点输入可控
- 使用readObject函数执行反序列化
- 当前class空间中存在一个可复写readObject的类
- 可利用当前环境下的readObject进一步构筑利用链
###利用形式 - readObject中有可控危险方法
- 入口类参数中包含可控类,该类有危险方法,readObject时调用
- 入口类参数中包含可控类,该类又调用其他有危险方法的类,readObject时调用
###重写readObject方法
这里就还是举一个demo:
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { |
重新序列化以及反序列化即可弹出计算器
####为什么readObject函数需要private属性,传参java.io.ObjectInputStream?
这个文章里面写了对比
readObject重写解释
总结来说就是:
- 我们其实不是重写了readObject,而是利用传入的参数不同,使得其能被重新赋值,执行被复写的参数,这就回答了标题的问题了
- 而这个条件首先需要方法名为readObject
- 返回类型为void
- 传入参数为ObjectInputStream.class类型参数
- 修饰符不能包含static
- 修饰符必须包含private
###利用可控类执行命令
####URLDNS链
构造链:
HashMap.readObject->HashMap.hash->URl.hashcode->URL.getHostAddress
这里简要分析一下poc: - java在反序列化时会自动调用readObject,如果此类重写了readObject则会调用该类重写以后的
- 在HashMap中重写了readObject,并且调用了hash(key)
- 跟进hash(key),发现其调用了hashCode方法
- 而这里我们可以跟URL的hashCode方法,在这里就触发getHostAddress,访问dnslog链接
public static void main(String[] args) throws Exception{ |
接下来谈谈如何书写这个反序列化链条
1.确定我们要反序列化的对象,也就是要实例化的类,很明确这里就是HashMap,接下来需要研究一下,如何传入数据,可以看到readObject中,最后使用的是put