目录导航
Java RASP技术
运行时应用程序自我保护(Runtime application self-protection
,简称RASP
)使用Java Agent技术在应用程序运行时候动态编辑类字节码,将自身防御逻辑注入到Java底层API和Web应用程序当中,从而与应用程序融为一体,能实时分析和检测Web攻击,使应用程序具备自我保护能力。
RASP技术作为新兴的WEB防御方案,不但能够有效的防御传统WAF无法实现的攻击类型,更能够大幅提升对攻击者攻击行为的检测精准度。RASP是传统WAF的坚实后盾,能够弥补WAF无法获取Web应用运行时
环境的缺陷,同时也是传统Web应用服务最重要的不可或缺的一道安全防线。
RASP通过注入自身到开发语言底层API中,从而完全的融入于Web服务中,拥有了得天独厚的漏洞检测和防御条件,RASP技术相较于传统的WAF拥有了更加精准、深层次的防御。RASP采用基于攻击行为分析
的主动防御
机制,严防文件读写
、数据访问
、命令执行
等Web应用系统命脉,为Web应用安全筑建出“万丈高墙”。
RASP技术原理
JDK1.5
开始,Java
新增了Instrumentation(Java Agent API)
和JVMTI(JVM Tool Interface)
功能,允许JVM
在加载某个class文件
之前对其字节码进行修改,同时也支持对已加载的class(类字节码)
进行重新加载(Retransform
)。
利用Java Agent
这一特性衍生出了APM(Application Performance Management,应用性能管理)
、RASP(Runtime application self-protection,运行时应用自我保护)
、IAST(Interactive Application Security Testing,交互式应用程序安全测试)
等相关产品,它们都无一例外的使用了Instrumentation/JVMTI
的API
来实现动态修改Java类字节码
并插入监控或检测代码。
RASP防御的核心就是在Web应用程序执行关键的Java API之前插入防御逻辑,从而控制原类方法执行的业务逻辑。如果没有RASP的防御,攻击者可以利用Web容器/应用的漏洞攻击应用服务器。
示例 – Web攻击原理:

当Web应用接入RASP防御后,RASP会在Java语言底层重要的API(如:文件读写、命令执行等API)中设置防御点(API Hook方式),攻击者一旦发送Web攻击请求就会被RASP监控并拦截,从而有效的防御Web攻击。
示例 – RASP防御原理:

RASP的防御能力是基于“行为实现”的,RASP会根据Hook点触发的攻击事件(如:文件读取事件、命令执行事件)调用对应的防御模块,而不需要像传统的WAF一样,一次性调用所有的防御模块。
灵蜥Agent架构
灵蜥Agent由两大核心机制(Agent机制
、Hook机制
)、三大核心模块(RASP Loader
、RASP Context
、RASP 防御模块
)组成。
RASP Agent架构图:

Agent机制和Hook机制是RASP实现防御的必要条件,RASP会使用Hook机制防御容易被攻击的Java类(如:Java SE、Web应用),当被防御的类方法被调用时会自动触发RASP的防御代码。
RASP Hook机制
Hook机制类似于AOP机制(Aspect Oriented Programming
,面向切面编程),使用基于Java Agent实现的Hook技术,RASP可以实现对Java类方法执行执行前后插入自定义逻辑,从而实现控制原本的程序执行的业务逻辑。
ProcessBuilder Hook示例
java.lang.ProcessBuilder
常用于执行本地系统命令,为了便于理解Hook机制,这里以Hook ProcessBuilder类的start方法作为示例,演示如何Hook机制的工作原理。
示例 – 未经Hook的原始java.lang.ProcessBuilder类代码片段:
package java.lang;
import java.io.IOException;
import java.util.List;
public final class ProcessBuilder {
private List<String> command;
// 省略其他不相关类和成员变量
public Process start() throws IOException {
// 省去其他无关代码
return ProcessImpl.start(command, environment, dir, redirects, redirectErrorStream);
}
}
ProcessBuilder类可以调用UNIXProcess/ProcessImpl类的native方法执行本地系统命令,默认情况下可以被任意的Java类调用,所以存在安全问题。RASP使用Agent机制动态修改了ProcessBuilder类的start方法字节码,在方法体的前后插入RASP防御代码,当start方法被调用时因为程序逻辑已被RASP更改,必须先执行RASP的防御逻辑之后才能够执行start方法的原始业务逻辑,如果RASP调用内部的检测逻辑后发现可能存在恶意攻击,RASP会终止start方法执行逻辑,从而避免了恶意攻击。
示例 – RASP的Hook逻辑代码片段:
package org.javaweb.rasp.agent;
import org.javaweb.rasp.agent.commons.RASPLogger;
import org.javaweb.rasp.agent.hooks.advice.RASPMethodAdvice;
import org.javaweb.rasp.agent.hooks.annotation.RASPClassHook;
import org.javaweb.rasp.agent.hooks.annotation.RASPMethodHook;
import org.javaweb.rasp.agent.utils.ClassUtils;
import org.javaweb.rasp.loader.hooks.RASPHookResult;
/**
* Hook 本地命令执行
*/
@RASPClassHook
public class LocalCommandHook {
/**
* Hook 通用的ProcessBuilder类
*/
@RASPMethodHook(className = "java.lang.ProcessBuilder", methodName = "start")
public static class ProcessBuilderHook extends RASPMethodAdvice {
@Override
public RASPHookResult<?> onMethodEnter() {
Object obj = getThisObject();
try {
// 获取ProcessBuilder类的command变量值
List<String> command = ClassUtils.getFieldValue(obj, "command");
// 将执行的系统命令转换成字符串数组
String[] commands = command.toArray(new String[command.size()]);
// 调用processCommand方法,检测执行的本地命令合法性
return LocalCommandHookHandler.processCommand(commands, obj, this);
} catch (Exception e) {
RASPLogger.log(AGENT_NAME + "获取ProcessBuilder类command变量异常:" + e, e);
}
return new RASPHookResult(RETURN);
}
}
// 省略其他本地命令执行Hook点
}
示例 – 经过RASP修改后的java.lang.ProcessBuilder类
package java.lang;
import org.javaweb.rasp.loader.hooks.RASPHookHandlerType;
import org.javaweb.rasp.loader.hooks.RASPHookProxy;
import org.javaweb.rasp.loader.hooks.RASPHookResult;
import java.io.IOException;
import java.util.List;
public final class ProcessBuilder {
private List<String> command;
public Process start() throws IOException {
// 生成Object数组对象,存储方法参数值
Object[] parameters = new Object[]{};
// 生成try/catch
try {
// 调用RASP方法方法进入时检测逻辑
RASPHookResult<?> enterResult = RASPHookProxy.onMethodEnter(parameters, ...);
String HandlerType = enterResult.getRaspHookHandlerType().toString();
if (RASPHookHandlerType.REPLACE_OR_BLOCK.toString().equals(HandlerType)) {
// 如果RASP检测结果需要阻断或替换程序执行逻辑,return RASP返回结果中设置的返回值
return (Process) enterResult.getReturnValue();
} else if (RASPHookHandlerType.THROW.toString().equals(HandlerType)) {
// 如果RASP检测结果需要往外抛出异常,throw RASP返回结果中设置的异常对象
throw (Throwable) enterResult.getException();
}
// 执行程序原逻辑,执行本地系统命令并返回Process对象
Process methodReturn = ProcessImpl.start(command, environment, dir, redirects, redirectErrorStream);
// 调用RASP方法方法退出时检测逻辑,同onMethodEnter,此处省略对应代码
return methodReturn;
} catch (Throwable t) {
// 调用RASP方法方法异常退出时检测逻辑,同onMethodEnter,此处省略对应代码
}
}
}
RASP Hook与Java Web攻击
常见的Java Web攻击方式最终几乎都会调用对应的Java类方法执行,而RASP恰好可以使用Hook机制控制任意的Java类方法执行逻辑,因此RASP可以使用Hook机制将易受攻击的Java类进行监控,从而实现防止恶意的Java Web攻击。

RASP动态防御案例
RASP是一种新型的Web应用防御方案,虽然RASP本意是被设计来检测恶意攻击的,但是在实际的日常业务测试和线上防御时发现过非常多的有意思的漏洞,本文整理了多个比较有代表意义的真实案例以此来演示RASP独特的防御能力。
1. 什么是RASP
运行时应用程序自我保护(Runtime application self-protection
,简称RASP
)使用Java Agent技术在应用程序运行时候动态编辑类字节码,将自身防御逻辑注入到Java底层API和Web应用程序当中,从而与应用程序融为一体,能实时分析和检测Web攻击,使应用程序具备自我保护能力。
RASP技术作为新兴的WEB防御方案,不但能够有效的防御传统WAF无法实现的攻击类型,更能够大幅提升对攻击者攻击行为的检测精准度。RASP是传统WAF的坚实后盾,能够弥补WAF无法获取Web应用运行时
环境的缺陷,同时也是传统Web应用服务最重要的不可或缺的一道安全防线。
RASP通过注入自身到开发语言底层API中,从而完全的融入于Web服务中,拥有了得天独厚的漏洞检测和防御条件,RASP技术相较于传统的WAF拥有了更加精准、深层次的防御。RASP不但可以实现类似IAST的请求参数追踪功能,同时还采用了基于攻击行为分析
的主动防御
机制,严防文件读写
、数据访问
、命令执行
等Web应用系统命脉,为Web应用安全筑建出“万丈高墙”。
2. 某业务系统SQL注入0day
某门户系统上线RASP后发现某业务查询接口无法正常使用,不久后在RASP云端监控到了如下告警信息:

从攻击日志中可以看出RASP捕获到了一次SQL注入攻击,但是经过分析该攻击日志后发现实际上是一个SQL注入漏洞被RASP的零规则检测出来了,而非SQL注入攻击。
从日志中可以看到,请求参数ids的值:691,692,870,871,872,873,874,875,876,877,878,879,883,886,887,888
直接拼接到了SQL语句当中:select distinct ORG_SH_NAME as orgName from t*****fo where ORG_LEVEL in (1, 3) and ORG_CODE in (
691,692,870,871,872,873,874,875,876,877,878,879,883,886,887,888)
,其中ids的参数值并不包含任何攻击的Payload,只是触发了RASP的SQL零规则检测,从而断定该接口存在SQL注入漏洞。
这是一个非常典型的SQL注入案例,我们通常在处理where in
查询的时候会因为无法直接使用SQL预编译而选择了拼接SQL的方式来实现业务,从而也就导致了SQL注入的产生。

3. 某业务系统任意文件读取漏洞
某业务系统上线RASP后发现系统中的预览文件功能不正常,随后在RASP云端监控到了如下告警信息:

从攻击日志中可以看出RASP捕获到了一次文件系统攻击,经过分析攻击日志后发现该请求属于正常业务,请求参数也不包含恶意的Payload,所以并不是恶意攻击,但是RASP分析了请求的参数后判定参数styleFilePath
的值/work/******/index_20210824_1.zip
可控,因此存在任意文件读取漏洞。
该漏洞在我们平时的开发中也是一个非常的漏洞,通常我们在写读取文件相关的接口的时候会忽略了请求参数值的合法性所带来的安全问题,从而导致了攻击者可以通过传入一些恶意的参数值从而获取服务器敏感信息,如:读取数据库配置文件获取数据库密码、读取~/.ssh/id_rsa
获取ssh私钥、读取~/.bash_history
获取bash记录的历史命令等,从而很有可能会导致服务器被非法入侵。

4. 某平台本地系统命令注入漏洞
某资产管理平台上线RASP后发现业务系统存在本地命令执行攻击,经过日志分析后确认该接口存在本地命令执行注入漏洞,日志如下图:

从请求的URL地址可以看出这是一个测试DNS连接速度的接口,传入IP地址会调用操作系统中的ping
命令,如:/bin/sh -c ping -c 1
8.8.8.8,分析传入的参数ip
值8.8.8.8
注入到了bash命令当中,所以可以判断此处存在本地命令执行漏洞。
本地命令注入漏洞是一种非常高风险的的漏洞,攻击者如果可以控制或注入cmd命令那么后果将不堪设想,例如修改请求参数ip
的值为:8.8.8.8;curl localhost:9000
,即可注入一个curl命令,当然也可以通过注入的命令间接的控制服务器。

5. 某业务系统SSRF攻击
某日,RASP平台突然接到一处SSRF攻击告警日志,如下图:

分析攻击日志并结合攻击的调用链得知:攻击者使用了Weblogic 10.3.6版本的SSRF漏洞探测服务器资源,RASP拦截到的攻击内容是http://baidu.com
,而请求参数中operator=http://baidu.com
,由此可知operator
参数存在安全问题。
攻击使用SSRF漏洞多用于探测服务器内部资源,是一种威胁程度较高的攻击手段,某些时候SSRF漏洞甚至可以间接的获取到Webshell,所以对待该类型漏洞也必须引起重视,Web应用必须做好对传入的URL检测,从而防止SSRF攻击。

6. 某OA系统WebShell攻击
某日护网期间,RASP平台突然出现了一个WebShell攻击,一时间既然把看守平台的安全运维人员吓的一激灵,瞬间感觉到了危险降临,此刻气氛紧张到了极点;平日里总是听闻RASP是如何的强大,为何还会有WebShell类型的攻击?于是颤抖的右手点击了攻击详情,如下图:

从攻击日志中只能定位WebShell的绝对路径,并不能确定是否是真实存在的后门,但从文件名shell.jspx
可以看出这多半是一个后门文件,于是立即登录服务器查看查看该文件内容,经分析得知是一个冰蝎
的后门,查看文件的ctime是2021年2月,而RASP是在护网前几日才紧急上线的。
如此说来,有人早在护网前就已经利用致*OA的漏洞上传了WebShell,如今想借机利用该后门进行深入渗透,可是访问该后门的时候却被RASP所拦截了,果然攻击队有些不讲武德,所幸有RASP守护服务器安全。

7. 总结
RASP作为一种新兴的Web应用防御技术手段,可获取运行时环境监测各类威胁,与Web应用同生死;具有0day防御
、精准拦截
、防御深入
、难以绕过
等诸多优点,可作为对传统WAF的有效补充;RASP竭尽所能的在应用层设置多层防线,誓死保卫Web应用安全!
RASP Context
RASP会在Http请求抵达Web应用服务器的时候自动创建RASP Context(RASP上下文,存储了Http请求和响应对象request、response、RASP防御规则、请求参数、RASP防御记录等重要数据),并在该Http请求结束时自动清理RASP Context。
RASP劫持Servlet/Filter对象原理
RASP内置了javax.servlet.Servlet
和javax.servlet.Filter
接口的Hook方法,Servlet容器中的任何Servlet或Filter在被调用之前都被RASP插入了劫持代码。RASP通过劫持javax.servlet.Servlet
的service
方法和javax.servlet.Filter
类的doFilter
方法不但可以获取到原始的HttpServletRequest
和HttpServletResponse
对象,还可以控制Servlet和Filter的程序执行逻辑,从而让RASP能够控制整个Http请求的生命周期。
RASP劫持Servlet/Filter对象原理:

RASPHttpRequestContextManager:

当Servlet或Filter请求结束后会调用RASPHttpRequestContextManager#finishHook
清理RASP Context中的缓存数据。
RASP Context与防御模块之间的关系
RASP在分析Web攻击的时候通常都会使用Hook技术捕获程序执行时的关键参数信息,然后和RASP的上下文中缓存的请求参数进行关联分析,使用基于攻击行为的分析方式分析出请求的参数中是否包含了恶意攻击。
因为RASP Context中存储着当前线程中所有与Http请求相关联的对象,所以在任意的RASP防御模块中都可以随时随地的获取到Http请求的参数、请求方式、请求文件绝对路径、URL地址等重要数据,同时RASP还会在Context中存储当前线程中的Http请求中的攻击信息,在Servlet或Filter的生命周期结束时将攻击日志写入本地日志文件并清理Context中的缓存对象。
转载请注明出处及链接