RASP技术实现

0x00 概念

运行时应用自我保护,RASP(Runtime Application Self-Protection)是一种植入到应用程序内部或其运行时环境的安全技术。它能够控制应用程序的执行流程,并且可以实时检测和阻止漏洞攻击行为。该技术可以用来通过自我保护的措施来阻止相关网络攻击,或在没有人为干预的情况下自动重新配置环境,以此来解决特定网络问题(威胁,故障等)。

WAF原理和RASP原理做比较:
 WAF在边界进行规则匹配。  RASP技术在应用程序内部进行探测和规则分析,更为精准。优点:1.误报率低。2.可以防护0Day级别的漏洞攻击。缺点:1.对应用程序性能有消耗。理论上是5%~10%。

0x01 Java版本技术实现原理(OpenRASP分析)

RASP技术实现实质是在不接触应用源码的情况下,对函数进行Hook操作。 而JVM提供了接口(Instrument机制),让我们操作字节码。而操作字节码用到的库,一般有ASM、Javassist等。ASM提供底层字节码操作、效率性能好。而Javassist库封装了底层操作,更加方便开发实现,百度的OpenRASP产品就是使用Javassist实现字节码修改的。 这里通过阅读OpenRASP源码(很多干货),来看看如何防护SSRF攻击的。 基于Instrument机制的字节码编织,会到rasp-boot的Agent类premain方法。

1
2
3
4
5
6
7
8
9
 /**
 * 启动时加载的agent入口方法
 *
 * @param agentArg 启动参数
 * @param inst     {@link Instrumentation}
 */
public static void premain(String agentArg, Instrumentation inst) {
    init(START_MODE_NORMAL, START_ACTION_INSTALL, inst);
}

紧接着会进入EngineBootstart方法进行初始化,initTransformer(inst);就是对Java字节码进行修改的具体代码了。
 这里会扫描com.baidu.openrasp.hook包下所有带注解@HookAnnotation的类,每个类负责Hook一个/多个Method。提取Method的参数,使用Javassist技术增加检测代码并植入到目标Class文件。 CustomClassTransformer类的transform方法是编织字节码的入口,加载类文件时,都会调用这个方法,判断是否时需要修改编织的类。如果是,则修改完返回字节码流。  我框出来的代码部分会调用每个Hook类的hookMethod方法。SSRF防护时,会Hook所有常见发送网络请求的函数。这一步主要获取请求参数,结合用户网络请求输入的参数,进行关联比对分析。  上图使用了Javassist库,在org/apache/commons/httpclient/URIparseUriReference方法后面添加了1行代码,调用CommonHttpClientHook.checkHttpConnection方法。参数$0$1表示调用栈里面的参数,也就是当前URI类的实例(Object)和第1个参数String original(即解析的URL)。  接着,将通过Hook函数获取的URL、HostName等重要信息放在Map中,供检测攻击使用。Checker代码大部分作为扩展在JS里面实现,而SSRF检测代码在Java中实现了。  可以看到,检测算法是:

  • 遍历每个request层面拦截到的用户输入参数(parameterMap),与拦截的URL比较。如果相同,则可判断是用户输入的URL到达了底层网络请求的API。
  • 检测URL对应的IP是否是内网地址。如果是,则判定为SSRF攻击。
  • 根据配置,攻击Block。可以通过Hook返回的Respone里面,都存储在ThreadLocal。

小结下,过程是:Java Instrument机制 -> Javassist库修改字节码Hook关键函数 -> 通过比对用户Request的参数和底层网络请求参数,检测攻击。

0x02 基于JVM-Sanbox的实现

OpenRASP开源实现已经很赞了,还有很多商业功能,用到实际业务中实践没问题。这里我为了完成相关研究测试,及平常简单使用。使用阿里的JVM-Sandbox快速简洁地实现了2个工具,分别用来禁用命令执行防护通用RCE/SQL注入攻击的RASP实现。 Java禁用掉命令执行API,可以防护很多安全攻击。在2次的DDCTF题目中,我都用了这个,线上运行无bug。由于JVM-Sandbox提供了良好的API支持,代码优雅而简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Http("/blockSystemExec")
public void blockSystemExec() {
    new EventWatchBuilder(moduleEventWatcher)
            .onClass("java.lang.ProcessBuilder")
            /**/.includeBootstrap()
            .onBehavior("start")
            .onWatch(new AdviceListener() {
                         @Override
                         public void before(Advice advice) throws Throwable {
                             String cmd = "echo 'your are a good man'";
                             Runtime run = Runtime.getRuntime();//返回与当前 Java 应用程序相关的运行时对象
                             Process p = null;
                             try {
                                 p = run.exec(cmd);
                             } catch (IOException e) {
                                 e.printStackTrace();
                             }
                             // 然后立即返回,因为监听的是BEFORE事件,所以此时立即返回,方法体将不会被执行
                             ProcessControlException.throwReturnImmediately(p);
                         }
                     }
            );
}

命令执行,包括Runtime.exec都是走到java.lang.ProcessBuilderstart方法。运行过程中,只要知道进程号,就能拦截命令执行,效果如下:
 RASP我实现了通用RCE检测以及参考OpenRASP算法实现SQL注入的检测。主要目的是研究和测试,RCE检测和拦截实现是针对性的分析Spring、Struts2框架历史漏洞,找到关键API进行Hook分析。与OpenRASP不同的是,针对性的加入了多层次监控(如:OGNL、SpEL语言层),整体当时框架设计是: 

0x03 参考

Java动态编程初探——Javassist
https://github.com/baidu/openrasp
禁用命令执行
防护通用RCE/SQL注入攻击的RASP实现

文章作者: angelwhu

文章链接: https://www.angelwhu.com/paper/2019/05/12/rasp-technology-implementation/

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值