java反序列化学习与复现

java反序列化学习与复现

0x00 前言

​ 最近面试被问到了,学长说那位是大佬,还问了二进制(好久没学了突然问二进制,没准备只能知道啥答啥了qaq,怕是寄了),奈何自己一直没去了解java反序列化,虽然挖到过shiro反序列化,但是没有去详细了解,不过我呢要学就是那种详细了解的,最近一直在学红队的技术(内网渗透,还看了冰蝎的魔改,frp的魔改,确实大佬们挺强),和实战挖洞,不多说先实际操作。

0x01 基础知识(参考各种博客)

漏洞原理
当开发者自定义实现Serializable、添加自己的readObject()方法时,若readObject()方法内代码逻辑存在缺陷,则可能存在Java反序列化漏洞的风险。如果此时Java服务的反序列化API允许外部用户使用,则会导致攻击者使用精心构造的payload来利用反序列化漏洞达到任意代码执行的目的。

Java反序列化操作

实现方法
1.java.io.ObjectOutputStream
2.java.io.ObjectInputStream

序列化:ObjectOutputStream类 --> writeObject()

1
2
该方法对参数指定的obj对象进行序列化,把字节序列写到一个目标输出流中
按Java的标准约定是给文件一个.ser扩展名

反序列化: ObjectInputStream类 --> readObject()

1
该方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

感觉和php也有些相似hhhh

0x02 实验测试

1.简单实验

做一个简单的java反序列化实验,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package java_Serializable;

import java.io.*;

/*
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
*/

public class Java_Test{

public static void main(String args[]) throws Exception {
String obj = "zwz12138";

// 话说我参考的文章这地方写的是object,但是文件名是aa.cer,2333
// 将序列化对象写入文件1.txt中
FileOutputStream fos = new FileOutputStream("1.txt");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(obj);
os.close();

// 从文件1.txt中读取数据
FileInputStream fis = new FileInputStream("1.txt");
ObjectInputStream ois = new ObjectInputStream(fis);

// 通过反序列化恢复对象obj,传值给obj2
String obj2 = (String)ois.readObject();
System.out.println(obj2);
ois.close();
}

}

,说起来我也就学过假的java(手撕代码背书的那种),不过看着也还行,想起来某个文章说的

众所周知,Java代码开发与Java代码审计,并不是充分必要条件。

你问我懂不懂Java,那我当然是不懂的。

你问我能不能搞Java代码审计,其实也不是不能搞。

有一说一,好像确实hhhh

试了试,成功输出zwz12138

image-20210930163001284

十六进制看了看1.txt,十六进制编码长这样

image-20210930152256931

2.readObject()方法重写测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//代码Main.java
package java_Serializable;

import java.io.*;

public class Main {
public static void main(String[] args) throws Exception {
Evil evil=new Evil();
evil.cmd="calc";

byte[] serializeData=serialize(evil);
unserialize(serializeData);
}
public static byte[] serialize(final Object obj) throws Exception {
ByteArrayOutputStream btout = new ByteArrayOutputStream();
ObjectOutputStream objOut = new ObjectOutputStream(btout);
objOut.writeObject(obj);
return btout.toByteArray();
}
public static Object unserialize(final byte[] serialized) throws Exception {
ByteArrayInputStream btin = new ByteArrayInputStream(serialized);
ObjectInputStream objIn = new ObjectInputStream(btin);
return objIn.readObject();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
//代码Evil.java
package java_Serializable;

import java.io.*;

public class Evil implements Serializable{
public String cmd;
private void readObject(java.io.ObjectInputStream stream) throws Exception {
stream.defaultReadObject();
Runtime.getRuntime().exec(cmd);
}
}

这里我看也看明白了,就是原先定义的evil对象中cmd值为calc,但是在反序列化中调用重新定义的readObject()方法,把cmd的值直接执行了,结果就是调起了windows的计算器,可见攻击要点就是这个反序列化方法

image-20210930163435106

0x03 结合CTF题复现分析

​ 这里准备结合一道java反序列化的题目进行研究,搭建环境复现,后续写。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!,本博客仅用于交流学习,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。 文章作者拥有对此站文章的修改和解释权。如欲转载此站文章,需取得作者同意,且必须保证此文章的完整性,包括版权声明等全部内容。未经文章作者允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。若造成严重后果,本人将依法追究法律责任。 阅读本站文章则默认遵守此规则。