目录
Java 中的反序列化漏洞
Java 是一种面向对象的编程语言,使用序列化机制将对象转换为字节流进行存储或传输。Java 提供了 Serializable
接口和 ObjectOutputStream
和 ObjectInputStream
类来执行序列化和反序列化操作。
当 Java 程序反序列化来自不可信源的数据时,如果数据包含恶意构造的对象,攻击者可以利用反序列化漏洞执行任意代码。
攻击手法与原理
-
恶意反序列化攻击
- 在 Java 中,恶意用户可以通过构造恶意的序列化对象,利用存在漏洞的类中的
readObject()
或writeObject()
等方法来执行恶意代码。这些方法可以在反序列化过程中被调用,进而触发恶意操作。
- 在 Java 中,恶意用户可以通过构造恶意的序列化对象,利用存在漏洞的类中的
-
常见的攻击场景
- 通过构造特定的恶意对象并传递给反序列化过程,攻击者可以执行任意代码。例如,攻击者通过构造一个包含恶意命令的对象,可以触发命令执行,导致远程代码执行(RCE)。
- 常见的漏洞是利用 Java 内部类 或 Apache Commons Collections 库中可被利用的类。
-
漏洞利用的典型过程
- 攻击者通过反序列化时注入一个恶意对象(例如
Runtime
、ProcessBuilder
或类似的类)来执行特定的系统命令,从而获得系统控制权。
- 攻击者通过反序列化时注入一个恶意对象(例如
Java 反序列化漏洞的实际案例
-
CVE-2015-4852 (Apache Commons Collections)
- 漏洞描述:Apache Commons Collections 库中的
InvokerTransformer
类允许通过反射执行任意方法。当程序通过不受信任的用户输入反序列化数据时,攻击者可以利用此漏洞执行任意代码。 - 利用方式:攻击者可以通过精心构造一个包含
InvokerTransformer
的恶意序列化对象,执行任意方法,如通过反射调用系统命令。 - 影响版本:Commons Collections 3.x 版本。
- 漏洞描述:Apache Commons Collections 库中的
-
CVE-2017-12149 (Apache Struts2)
- 漏洞描述:Apache Struts2 中的反序列化漏洞可以允许攻击者通过精心构造的请求来执行恶意代码。攻击者可以在 Struts2 应用程序中上传一个包含恶意对象的请求,导致远程代码执行。
- 利用方式:利用 Struts2 中的反序列化漏洞,攻击者可以通过上传恶意对象来执行任意命令,绕过权限控制,获取系统控制权。
Java 反序列化漏洞利用示例
以下是通过 Java 反序列化漏洞执行恶意命令的简单示例:
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
public class RCE {
public static void main(String[] args) throws Exception {
String command = "echo 'hacked'";
// 创建一个 ProcessBuilder 对象,准备执行系统命令
ProcessBuilder pb = new ProcessBuilder("sh", "-c", command);
// 序列化 ProcessBuilder 对象
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ObjectOutputStream objStream = new ObjectOutputStream(byteStream);
objStream.writeObject(pb);
// 反序列化 ProcessBuilder 对象
ByteArrayInputStream inputStream = new ByteArrayInputStream(byteStream.toByteArray());
ObjectInputStream objectStream = new ObjectInputStream(inputStream);
objectStream.readObject(); // 反序列化并执行命令
// 此时命令会在反序列化时执行
}
}
在这个例子中,攻击者构造一个包含 ProcessBuilder
对象的恶意序列化数据,当反序列化发生时,ProcessBuilder
会执行 echo 'hacked'
命令。
防御措施
-
避免反序列化不可信数据:
- 永远不要反序列化来自不可信源的数据。最好的做法是仅反序列化自己完全控制的数据源。
- 对反序列化数据进行严格的验证,确保数据的来源和结构符合预期。
-
使用白名单类加载器:
- 限制反序列化过程中允许加载的类,避免加载恶意类。可以通过使用自定义的类加载器来实现这一点,确保只加载经过验证的类。
-
禁用某些类的反序列化:
- 禁止使用可能被恶意利用的类(如
ProcessBuilder
、Runtime
等)。可以通过禁用反序列化过程中的某些类,或使用 Java 安全管理器来阻止不安全的类加载。
- 禁止使用可能被恶意利用的类(如
-
使用安全的序列化格式:
- 避免使用 Java 原生的序列化格式。可以考虑使用更安全的格式,如 JSON 或 XML 进行数据交换,它们通常不支持执行命令。
-
使用反序列化框架:
- 使用更安全的反序列化库,如 Google 的 Gson、Jackson 等,它们提供了更强的安全性,防止恶意对象的注入。
-
对反序列化的输入进行签名:
- 对序列化数据进行数字签名或加密,确保数据在传输过程中未被篡改。
CVE 漏洞最新概览
以下是一些与 Java 反序列化漏洞相关的最新 CVE 漏洞:
-
CVE-2021-22661 - Apache Struts2 反序列化漏洞
- 描述:Apache Struts2 存在一个反序列化漏洞,允许攻击者通过发送恶意请求,触发远程代码执行。
- 影响版本:Struts 2.5.x 版本。
-
CVE-2020-9484 - Oracle WebLogic Server 反序列化漏洞
- 描述:Oracle WebLogic Server 存在反序列化漏洞,攻击者可以通过发送精心构造的请求,执行任意命令,导致远程代码执行。
- 影响版本:WebLogic 12.x 和 11.x 版本。
Python 脚本 POC
以下是一个 Python 脚本,用于模拟一个 Java 反序列化漏洞攻击的示例。假设我们已经知道反序列化数据的格式。
import socket
import sys
import base64
# 目标服务器和端口
target = 'localhost'
port = 8080
# 构造反序列化的 payload
# 假设目标 Java 应用程序的反序列化数据结构需要以下特定的序列化数据
payload = 'your_base64_encoded_serialized_object'
# 创建 HTTP 请求
headers = {
"Host": target,
"Content-Type": "application/x-www-form-urlencoded",
"Content-Length": str(len(payload))
}
request = f"POST / HTTP/1.1\r\n"
for key, value in headers.items():
request += f"{key}: {value}\r\n"
request += "\r\n" + payload
# 建立与目标的连接
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((target, port))
sock.send(request.encode())
# 接收响应
response = sock.recv(4096)
print("Response:\n", response.decode())
sock.close()
解释:
- 这个 Python 脚本通过构造一个包含恶意序列化数据的 HTTP