-
-
[原创]CC1利用链分析
-
发表于: 2024-8-30 15:45 8857
-
CC是“Commons Collections”的缩写,它是 Apache Commons Collections 库的一部分。
实验环境
jdk8u65
maven依赖:
1 2 3 4 5 | < dependency > < groupid >commons-collections</ groupid > < artifactid >commons-collections</ artifactid > < version >3.2.1</ version > </ dependency > |
Transformer接口
全类名:org.apache.commons.collections.Transformer,是 Apache Commons Collections 库中的一个接口,它定义了如何将一个输入对象转换为另一个输出对象,接口中只声明了一个方法:public Object transform(Object input);
在CC1利用链中需要用到的Transformer实现类有如下几个:
InvokerTransformer
作用:输入一个对象,通过反射调用对象中的方法并返回。
示例:
1 2 | InvokerTransformer invokerTransformer = new InvokerTransformer( "exec" , new Class[]{String. class }, new Object[]{ "calc" }); invokerTransformer.transform(Runtime.getRuntime()); |
在调用transform方法时传入一个Runtime对象,InvokerTransformer会通过反射调用exec方法,来看看它的transform实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public Object transform(Object input) { if (input == null ) { return null ; } try { // 通过输入的对象获取其Class对象 Class cls = input.getClass(); // 通过构造方法传入的方法名和参数类型获取Method对象 Method method = cls.getMethod(iMethodName, iParamTypes); // 反射调用方法 return method.invoke(input, iArgs); } // ... } |
ConstantTransformer
它的作用是不管你输入什么,它只给你输出一个由构造器传入的对象:
1 2 3 | public Object transform(Object input) { return iConstant; } |
ChainedTransformer
链式转换器,可以链式调用多个Transformer,构造器参数是一个Transformer数组,由上一个Transformer的输出作为下一个Transformer的输入。
示例:
1 2 3 4 | new ChainedTransformer( new Transformer[]{ new ConstantTransformer(Runtime.getRuntime()), new InvokerTransformer( "exec" , new Class[]{String. class }, new Object[]{ "calc" }) }).transform( null ); |
new一个ChainedTransformer,同时传入一个Transformer数组,第一个元素是ConstantTransformer,输出一个Runtime对象,第二个元素是InvokerTransformer,反射调用Runtime的exec方法。
其transform实现:
1 2 3 4 5 6 7 8 | public Object transform(Object object) { // 遍历构造器传入的Transformer数组 for ( int i = 0 ; i < iTransformers.length; i++) { // 上一个Transformer的输出作为下一个Transformer的输入 object = iTransformers[i].transform(object); } return object; } |
TransformedMap
org.apache.commons.collections.map.TransformedMap可以对原生Map类型对象做增强,采用了装饰者设计模式,用法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | public class TransformedMapExample { public static void main(String[] args) { // 创建一个原生Map Map<string, integer> baseMap = new HashMap<>(); baseMap.put( "apple" , 1 ); // 定义一个转换器,将key转换为小写 Transformer keyTransformer = new Transformer() { @Override public String transform(Object input) { return input.toString().toLowerCase(); } }; // 定义一个转换器,将 value × 2 Transformer valueTransformer = new Transformer() { @Override public Object transform(Object input) { return Integer.valueOf(input + "" ) * 2 ; } }; // 创建TransformedMap装饰器 Map<string, integer> transformedMap = TransformedMap.decorate(baseMap, keyTransformer, valueTransformer); // 向装饰后的Map添加元素 transformedMap.put( "GRAPE" , 2 ); // 输出Map的内容 for (Map.Entry<string, integer> entry : transformedMap.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); } // 通过entry设置value for (Map.Entry<string, integer> entry : transformedMap.entrySet()) { entry.setValue( 3 ); } for (Map.Entry<string, integer> entry : transformedMap.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); } } }</string, integer></string, integer></string, integer></string, integer></string, integer> |
使用原生map时,会原样put键值:
使用transformedMap时,会将key转为小写,value×2
debug看其源码实现,调用put方法时,会先调用transformKey,
然后又调用keyTransformer的transform方法:
继而调用到我们自定义的keyTransformer:
接下来调用transformValue,再调用valueTransformer.transform:
继而调用到自定义的valueTransformer:
还有一种触发valueTransformer的方式是通过entry调用setValue方法:
跟进去这里调用了parent.checkSetValue,parent就是transformedMap:
再步入到checkSetValue中,可见调用了valueTransformer.transform:
构造利用链
cc1链最终就是通过调用ChainedTransformer的transform方法触发RCE,那我们就寻找哪里调用了它,在方法名上按ALT + F7,
这里有上文分析的TransformedMap.checkSetValue方法,点进去:
再按ctrl点击checkSetValue,跳转到AbstractInputCheckedMapDecorator.MapEntry的setValue方法里,
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
- [原创]【Golang】interpolateParams参数导致的宽字节注入 2405
- [原创]从底层视角看面向对象 9471
- [原创]C语言的文件与缓冲区 8737
- [原创]CC1利用链分析 8858
- [原创]VC++6调试状态下的堆结构 7525