Ysoserial Click1利用连分析
字数 1876 2025-08-09 13:33:49

Ysoserial Click1 Gadget 利用链深度分析

1. 概述

Click1 gadget是ysoserial工具中的一个利用链,基于Apache Click框架和Commons-Collections库的反序列化漏洞。该利用链通过精心构造的序列化对象,能够在反序列化过程中实现远程代码执行(RCE)。

2. 利用链核心组件

2.1 Source点: PriorityQueue

java.util.PriorityQueue是此利用链的起点,在反序列化过程中会调用其comparator属性的compare方法。

2.2 Sink点: TemplatesImpl

com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl是最终的恶意代码执行点,通过其getOutputProperties()newTransformer()方法触发恶意类加载。

2.3 关键桥梁: ColumnComparator

org.apache.click.control.Column$ColumnComparator替代了Commons-Collections中的TransformingComparator,用于连接Source和Sink点。

3. 利用链详细分析

3.1 反序列化触发流程

  1. PriorityQueue反序列化:触发readObject()方法
  2. 调用comparator.compare():使用ColumnComparator作为比较器
  3. ColumnComparator.compare():调用column.getProperty()
  4. PropertyUtils.getValue():通过反射调用目标方法
  5. 触发TemplatesImpl.getOutputProperties():最终导致恶意代码执行

3.2 ColumnComparator.compare方法分析

public int compare(Object row1, Object row2) {
    this.ascendingSort = this.column.getTable().isSortedAscending() ? 1 : -1;
    Object value1 = this.column.getProperty(row1);
    Object value2 = this.column.getProperty(row2);
    
    if (value1 instanceof Comparable && value2 instanceof Comparable) {
        return !(value1 instanceof String) && !(value2 instanceof String) 
            ? ((Comparable)value1).compareTo(value2) * this.ascendingSort 
            : this.stringCompare(value1, value2) * this.ascendingSort;
    } else if (value1 != null && value2 != null) {
        return value1.toString().compareToIgnoreCase(value2.toString()) * this.ascendingSort;
    } else if (value1 != null && value2 == null) {
        return 1 * this.ascendingSort;
    } else {
        return value1 == null && value2 != null ? -1 * this.ascendingSort : 0;
    }
}

关键点在于column.getProperty(row1)调用,传入的row1就是构造好的恶意TemplatesImpl对象。

3.3 getProperty方法调用链

  1. Column.getProperty(Object row):

    public Object getProperty(Object row) {
        return this.getProperty(this.getName(), row);
    }
    
  2. Column.getProperty(String name, Object row):

    public Object getProperty(String name, Object row) {
        if (row instanceof Map) {
            // 处理Map逻辑...
        } else {
            if (this.methodCache == null) {
                this.methodCache = new HashMap();
            }
            return PropertyUtils.getValue(row, name, this.methodCache);
        }
    }
    

    由于TemplatesImpl不是Map的子类,会进入PropertyUtils.getValue()调用。

  3. PropertyUtils.getValue():

    public static Object getValue(Object source, String name, Map cache) {
        String basePart = name;
        String remainingPart = null;
    
        if (source instanceof Map) {
            return ((Map)source).get(name);
        } else {
            int baseIndex = name.indexOf(".");
            if (baseIndex != -1) {
                basePart = name.substring(0, baseIndex);
                remainingPart = name.substring(baseIndex + 1);
            }
            Object value = getObjectPropertyValue(source, basePart, cache);
            return remainingPart != null && value != null 
                ? getValue(value, remainingPart, cache) 
                : value;
        }
    }
    
  4. PropertyUtils.getObjectPropertyValue():

    private static Object getObjectPropertyValue(Object source, String name, Map cache) {
        PropertyUtils.CacheKey methodNameKey = new PropertyUtils.CacheKey(source, name);
        Method method = null;
        try {
            method = (Method)cache.get(methodNameKey);
            if (method == null) {
                method = source.getClass().getMethod(ClickUtils.toGetterName(name));
                cache.put(methodNameKey, method);
            }
            return method.invoke(source);
        } catch (NoSuchMethodException var13) {
            // 尝试其他方法名格式...
        }
    }
    

    关键点:ClickUtils.toGetterName(name)会将name转换为getter方法名。

  5. ClickUtils.toGetterName():

    public static String toGetterName(String property) {
        HtmlStringBuffer buffer = new HtmlStringBuffer(property.length() + 3);
        buffer.append("get");
        buffer.append(Character.toUpperCase(property.charAt(0)));
        buffer.append(property.substring(1));
        return buffer.toString();
    }
    

    此方法将属性名转换为标准的getter方法名(首字母大写,前面加"get")。

3.4 触发恶意代码执行

通过控制Columnname属性,可以调用TemplatesImpl的任意getter方法。选择getOutputProperties()是因为:

  1. getOutputProperties()TemplatesImpl的公共方法
  2. 它内部会调用newTransformer()
  3. newTransformer()会触发恶意类的初始化

TemplatesImpl.getOutputProperties()实现:

public synchronized Properties getOutputProperties() {
    try {
        return newTransformer().getOutputProperties();
    } catch (TransformerConfigurationException e) {
        return null;
    }
}

4. 利用链构造要点

  1. Column.name控制:通过Column构造函数设置name为"outputProperties"

    public Column(String name) {
        if (name == null) {
            throw new IllegalArgumentException("Null name parameter");
        } else {
            this.name = name;
        }
    }
    
  2. PriorityQueue构造

    • 设置comparator为ColumnComparator实例
    • 队列元素包含恶意构造的TemplatesImpl对象
  3. TemplatesImpl准备

    • 包含恶意字节码
    • 设置必要的属性使其能正确初始化

5. 防御措施

  1. 升级Apache Click框架到安全版本
  2. 使用反序列化过滤器,限制可反序列化的类
  3. 替换默认的Java反序列化机制
  4. 对来自不可信源的序列化数据进行严格验证

6. 总结

Click1 gadget利用链展示了如何通过精心构造的序列化对象,利用框架中的反射机制和特性,最终实现远程代码执行。理解这类利用链有助于开发者更好地防范反序列化漏洞,并设计更安全的系统架构。

Ysoserial Click1 Gadget 利用链深度分析 1. 概述 Click1 gadget是ysoserial工具中的一个利用链,基于Apache Click框架和Commons-Collections库的反序列化漏洞。该利用链通过精心构造的序列化对象,能够在反序列化过程中实现远程代码执行(RCE)。 2. 利用链核心组件 2.1 Source点: PriorityQueue java.util.PriorityQueue 是此利用链的起点,在反序列化过程中会调用其 comparator 属性的 compare 方法。 2.2 Sink点: TemplatesImpl com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl 是最终的恶意代码执行点,通过其 getOutputProperties() 或 newTransformer() 方法触发恶意类加载。 2.3 关键桥梁: ColumnComparator org.apache.click.control.Column$ColumnComparator 替代了Commons-Collections中的 TransformingComparator ,用于连接Source和Sink点。 3. 利用链详细分析 3.1 反序列化触发流程 PriorityQueue反序列化 :触发 readObject() 方法 调用comparator.compare() :使用 ColumnComparator 作为比较器 ColumnComparator.compare() :调用 column.getProperty() PropertyUtils.getValue() :通过反射调用目标方法 触发TemplatesImpl.getOutputProperties() :最终导致恶意代码执行 3.2 ColumnComparator.compare方法分析 关键点在于 column.getProperty(row1) 调用,传入的row1就是构造好的恶意 TemplatesImpl 对象。 3.3 getProperty方法调用链 Column.getProperty(Object row) : Column.getProperty(String name, Object row) : 由于 TemplatesImpl 不是Map的子类,会进入 PropertyUtils.getValue() 调用。 PropertyUtils.getValue() : PropertyUtils.getObjectPropertyValue() : 关键点: ClickUtils.toGetterName(name) 会将name转换为getter方法名。 ClickUtils.toGetterName() : 此方法将属性名转换为标准的getter方法名(首字母大写,前面加"get")。 3.4 触发恶意代码执行 通过控制 Column 的 name 属性,可以调用 TemplatesImpl 的任意getter方法。选择 getOutputProperties() 是因为: getOutputProperties() 是 TemplatesImpl 的公共方法 它内部会调用 newTransformer() newTransformer() 会触发恶意类的初始化 TemplatesImpl.getOutputProperties() 实现: 4. 利用链构造要点 Column.name控制 :通过 Column 构造函数设置name为"outputProperties" PriorityQueue构造 : 设置comparator为 ColumnComparator 实例 队列元素包含恶意构造的 TemplatesImpl 对象 TemplatesImpl准备 : 包含恶意字节码 设置必要的属性使其能正确初始化 5. 防御措施 升级Apache Click框架到安全版本 使用反序列化过滤器,限制可反序列化的类 替换默认的Java反序列化机制 对来自不可信源的序列化数据进行严格验证 6. 总结 Click1 gadget利用链展示了如何通过精心构造的序列化对象,利用框架中的反射机制和特性,最终实现远程代码执行。理解这类利用链有助于开发者更好地防范反序列化漏洞,并设计更安全的系统架构。