从TemplatesImpl类Gadget中提取bytecode

在Java反序列化的gadget中,有很多使用可反序列化TemplatesImpl类进行命令执行(比如CommonsCollections2-4、CommonsBeanutils1、Jdk7u21以及变种JRE8u20等等)。

前言

在Java反序列化的gadget中,有很多使用可反序列化TemplatesImpl类进行命令执行(比如CommonsCollections2-4、CommonsBeanutils1、Jdk7u21以及变种JRE8u20等等)。

实际上这类Gadget的反序列化过程中是直接或间接调用newTransformer或getOutputProperties方法,最终进入defineTransletClasses方法,将_bytecodes字段中存储的类的bytecode重新在JVM中定义为类,最终在对其调用newInstance方法时,触发写在该类static块或者无参构造方法中的代码块,从而达到代码执行的效果。

由于ysoserial中默认用于创建TemplatesImpl对象的createTemplatesImpl函数中,是在bytecode对应的类的静态代码块中加入执行java.lang.Runtime.exec的代码段,所以效果上来说,ysoserial创建的这类gadget是用于触发命令执行的,但实际上是可以进行任意代码执行的。

img

(修改yso令其支持任意代码执行可以参考这两篇文章:

https://blog.csdn.net/fnmsd/article/details/79534877

https://gv7.me/articles/2019/enable-ysoserial-to-support-execution-of-custom-code/

所以,当我们抓取到一些TemplatesImpl类的Gadget时,为了了解其具体的目的、执行的代码,我们需要提取出其中的bytecode进行反编译。

idea调试反序列化过程

以提取Xray Shiro的Shiro扫描中的bytecodes为例(此处膜一下长亭的Koalr师傅)

准备环境:

idea

shiro的samples-web.war

xray高级版(高级版才有Shiro Scan功能)

开始:

idea中下断点下到TemplatesImpl类的内部类TransletClassLoaderdefineClass中defineClass方法上:

img

启动调试,并使用xray开始扫描shiro站点:

  1. xray webscan --plugins shiro --url http://127.0.0.1:8080/samples_web_war/

(注意url一定要加结尾的斜杠,否则会导致响应302扫描失败)

然后idea中会触发断点,这时可以看到进入defineClass方法的bytecode

img

接着使用idea的调试的表达式执行功能将它保存出来,使用如下代码,并点击evaluate:

  1. var f = new FileOutputStream("d:/test.class");//这里路径改成需要保存的位置
  2. f.write(b);
  3. f.close();

此时就将byteCode的内容保存了下来。

img

接着上jd-gui或者luyten就可以看到详细的逻辑了:

img

使用Java Agent

使用Agent修改TemplatesImpl$TransletClassLoader类的defineClass方法,将_bytecodes进行保存。

img

基于javassist写了一个简单的premain模式的Agent,修改defineClass方法,增加字节码的输出,此处感谢同部门的jweny师傅给的支持~

  1. package org.fnmsd;
  2. import javassist.*;
  3. import java.io.ByteArrayInputStream;
  4. import java.lang.instrument.ClassFileTransformer;
  5. import java.lang.instrument.IllegalClassFormatException;
  6. import java.lang.instrument.Instrumentation;
  7. import java.security.ProtectionDomain;
  8. public class DumperAgent {
  9. public static void premain(String args, Instrumentation instrumentation) {
  10. DumperTransformer transformer = new DumperTransformer();
  11. instrumentation.addTransformer(transformer);
  12. }
  13. public static class DumperTransformer implements ClassFileTransformer {
  14. public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
  15. if(className.equals("com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl$TransletClassLoader")){
  16. ClassPool classPool = ClassPool.getDefault();
  17. classPool.appendClassPath(new LoaderClassPath(loader));
  18. try {
  19. CtClass ctClass = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
  20. CtMethod defineClass = ctClass.getDeclaredMethod("defineClass");
  21. //利用JavaAssist增加代码
  22. defineClass.insertBefore("long l = new java.util.Random().nextLong();System.out.println(\"Output Class:\"+l);new java.io.FileOutputStream(l+\".class\").write($1);");
  23. return ctClass.toBytecode();
  24. } catch (Exception e) {
  25. System.err.println("Agent:Patch Method Error");
  26. e.printStackTrace();
  27. }
  28. }
  29. return classfileBuffer;
  30. }
  31. }
  32. }

在defineClass方法最前面加入了:

  1. long l = new java.util.Random().nextLong();
  2. System.out.println("Output Class:"+l);
  3. new java.io.FileOutputStream(l+".class").write($1);//$1是一个参数,即bytecodes的数组b

会将加载的通过defineClass加载字节码,写入到当前工作目录下,具体位置可根据实际需要进行修改。

LoadObject是我自己加的一个用来测试生成好的序列化数据的伪gadget,作用就是用ObjectInputStream加载输出的序列化文件。

当然同样可以挂到Weblogic\Tomcat等中间件上来导出bytecodes。

可以正常弹出计算,此处我就不截计算器图了。

img

查看输出的class文件:

img

会输出两次是因为原版的ysoserial除了代码执行用的bytecode以外,还带一个迷之Foo.class,有关yso的bytecodes相关问题可以看下这篇文章:https://xz.aliyun.com/t/6227

直接分析Java序列化数据

这个只对未加密的序列化数据进行解析,除了shiro反序列化以外,大部分利用应该都是这种。

具体的序列化数据结构,可以参考Java文档中对象序列化流协议部分。

这里选择修改NickstaDB大佬(膜)实现的Java序列化数据解析工具SerializationDumper来进行bytecodes的导出。

https://github.com/fnmsd/SerializationDumper/

(上段用的Agent也传到了这里)

在SerializationDumper类里面加了几个字段,用来确定是解析到了TemplatesImpl类的bytecodes字段以及存储解析出来的byte。

最后效果:

img

img

总结

以上是想到的三种导出bytecodes的方法,我用的最多的是第一种,调试的时候就顺手导出了。

已经有师傅写过第三种方法了,可以参考一下:

https://github.com/r00tuser111/SerializationDumper-Shiro

https://mp.weixin.qq.com/s/EBH3pfFKx4vwCy1Z7h_DcQ

引用

https://blog.csdn.net/u011040537/article/details/107176880/

https://docs.oracle.com/javase/8/docs/platform/serialization/spec/protocol.html

https://github.com/NickstaDB/SerializationDumper

原文转载子自己的博客,原文地址:https://blog.csdn.net/fnmsd/article/details/115015115

  • 发表于 2021-04-20 16:11:07
  • 阅读 ( 6791 )
  • 分类:渗透测试

0 条评论

fnmsd
fnmsd

5 篇文章

站长统计