#序列化和反序列化
序列化 (Serialization):将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。
反序列化:从存储区中读取该数据,并将其还原为对象的过程,称为反序列化。
- Java反序列化及命令执行代码测试
- 在IDE创建一个package包,包名为SerialTest
- 包中创建三个类文件 Main Person SerializableTest
Main文件代码
// 执行DOS命令
package SerialTest; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; public class Main { public static void main(String args[]) throws IOException, InterruptedException { Process p = Runtime.getRuntime().exec("ipconfig"); java.io.InputStream is = p.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(is, Charset.forName("GBK"))); p.waitFor(); if (p.exitValue() != 0){ // 命令执行失败 进入错误处理步骤中 } String s = null; while ((s = reader.readLine()) != null){ System.out.println(s); } } }
Person 文件
// 待调用类
package SerialTest; import com.sun.xml.internal.ws.server.ServerRtException; import java.io.Serializable; class Person implements Serializable { private String name; private int age; private String sex; private int height; public Person(){ this.name = null; this.age = 0; this.sex = null; this.height = 0; } public Person(String name,int age,String sex,int height){ this.name = name; this.age = age; this.sex = sex; this.height = height; } public String toString(){ return "Persion{" + "name=" + name + ", age=" + age + ", sex=" + sex + ", height=" + height + "}"; }
SerializableTest 文件
// 序列化
package SerialTest; import java.io.*; public class SerializableTest { public static void main(String[] args) throws Exception { serialPerson(); Person person = deserialPerson(); System.out.println(person); } /** * Person 对象序列化 * @throws IOException */ private static void serialPerson() throws IOException{ Person person = new Person("阿杰",20,"男",175); ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(new File("F:/person.txt")) ); oos.writeObject(person); System.out.println("person 对象序列化成功!"); oos.close(); } /** * Person 对象反序列化 * @return * @throws Exception */ private static Person deserialPerson() throws Exception { ObjectInputStream ois = new ObjectInputStream( new FileInputStream(new File("F:/person.txt")) ); Person person = (Person)ois.readObject(); System.out.println("person 对象反序列化成功!"); return person; } }
代码分析
java中 在ObjectOutputStream类中 有一个writeObject()方法 把指定的对象进行序列化后 把字节序列写到一个目标输出流中 ObjectInputStream类中 readObject()方法 从一目标输入流中读取字节序列进行反序化 成一个对象 再把结果返回 代码中定义了一个person类 类中含有成员属性 使用writeObject()方法 把对象序列化 写进一个文本里 然后在使用readObject() 方法 从文件中读取字节序列 在还原成源对象
目前没有此文件 运行后
写入文件中的是字节序列 通过readObject()方法 再将对象还原。
如果对象不是字符串 而是一些命令 则反序列化后 利用java exec命令函数进行执行 就会产生命令执行漏洞。
在Web应用中有时候程序员为了考虑灵活性、简洁性,会在代码调用代码或命令执行函数 去处理。比如当应用在调用一些能将字符串转化成代码的函数时,没有考虑用户是否能 控制这个字符串,将造成代码执行漏洞。同样调用系统命令处理,将造成命令执行漏洞。 php(system()、shell_exec()、exec()、eval()) JAVA中的命令执行漏洞(struts2/ElasticsearchGroovy等) ThinkPHP命令执行
比如下图:
执行了ipconfig系统命令
WebGoat_Javaweb靶场反序列化测试
资料链接:
https://github.com/frohoff/ysoserial/releases
https://github.com/WebGoat/WebGoat/releases
cmd 输入 java -jar webgoat-server-8.0.1.jar
注:JDK8 无法运行 版本较低 安装11以上的版本
浏览器输入 127.0.0.1:8080/WebGoat
注册一个账号即可
部分源码示例
public static Object fromString(String s) throws IOException, ClassNotFoundException { byte[] data = Base64.getDecoder().decode(s); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data)); Object o = ois.readObject(); ois.close(); return o; } public static String toString(Serializable o) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(o); oos.close(); return Base64.getEncoder().encodeToString(baos.toByteArray
将对象序列化后 进行base64加密 变成了图片中的一堆字符
rO0ABXQAVklmIHlvdSBkZXNlcmlhbGl6ZSBtZSBkb3duLCBJIHNoYWxsIGJlY29tZSBtb3JlIHBvd2VyZnVsIHRoYW4geW91IGNhbiBwb3NzaWJseSBpbWFnaW5l
字符串 ——> 字节序列 序列化 writeObject()
字节序列 ——> 字符串 反序列化 readObject()
如何构造payload?
calc ----> 序列化 ----> base64加密=rO0AB格式开头的字符串
java -Dhibernate5 -cp hibernate-core-5.4.9.Final.jar;ysoserial-master-30099844c6-1.jar ysoserial.GeneratePayload Hibernate1 calc.exe > payload.bin