根据师傅的分析以及提出的疑问,将逐部分进行解答。本文将从下面两个方面进行解释:
- Agent端向云端发送数据分析
- Hook点选取的规则与方法
4. Agent端向云端发送数据分析
agent 每次收到请求,只要不是静态的,都要向云端发送报告,丧心病狂吧。 -- 作者:素十八
师傅的疑惑,也是当初我的疑惑,每个请求都要向云端发送报告,还要发送大量的数据,客户端扛得住吗?对网络带宽的影响,可以合理的解决吗?我们的云端处理得了这些数据吗?当时,我的疑惑远不止这些,很庆幸,我们最终解决了这些问题,有了当前的版本。
所以,我们为什么要把每个请求对应的污点调用数据都发送至云端呢?
4.1 早期的洞态IAST
洞态IAST实现的初期,数据采集和漏洞检测的逻辑都放在agent中,云端只用于接收数据、聚合整理以及展示;云端只能接收到某个API请求,是否存在某个漏洞,漏洞对应的污点调用链是什么,请求响应是什么。简单看来,好像没什么问题,也满足当前市场对IAST的需求,可以很好的检测漏洞,但是,这就够了吗?这种实现方式,agent的维护成本和使用成本是最低的吗?漏洞检测过程中的数据,没有其他的价值了吗?
4.2 新版的洞态IAST
带着上面的疑问,团队内部商量之后,决定做一次创新,把漏洞的检测逻辑放在云端,客户端只负责采集数据,漏洞检测统一由云端负责;这种新的架构,可以保存每一个请求对应的污点调用情况,这样就带来了以下几个好处:
- 新发现漏洞策略时,只需要对数据库中的离线数据进行搜索,就可以找到是否存在相关的污点调用链及漏洞,不需要重复触发API请求,采集数据
- 根据污点调用路径中的数据,快速的创建hook规则,简化IAST与自己系统的适配工作
- 等等
【讨论】上面的原因,是我们把每个请求都发送至云端的原因中的一部分,还有更多的原因,由于篇幅的问题,暂时写到这里,关于新版本的优缺点,大家可以发挥自己的想象,畅所欲言。
5. HooK点选取的规则与方法
作为一名安全研究员,同时也是 RASP 产品的参与者,我提出几点想法:
1. 所有的 hook 点,全部是写死的规则文件,无论是本地的 xml 也好,还是远端的 json 也好,都将 hook 点的类,描述符,相关信息完全写死,我相信这些规则是通过某些手段生成出来的,但是一旦在 hook 点选取上没有选择使用动态手段,那就失去了和 0 day 打交道的能力。
2. hook 点(这里指 sink )的选取还是层次太浅、规律性较差。
3. 洞态 IAST 检测了当前环境使用的中间件,并发送给云端,目前除了信息收集还没看到有什么样的具体用途,但是通过hook点来看,对于http请求的点还是使用了适配各个中间件的方式, OpenRASP 也是采用这种方式,这种方式在功能上没有什么问题,但是同样地还是失去了动态性,不优雅,也不能做到通用。
4. 在调试过程中,包括污点图的处理,总是被大量的无效信息占用了过多的时间,比如 StringBuilder 一类的传播节点,这其实不是漏洞调用的关键节点,个人认为没有必要处理他。
关于hook点,师傅提出了很多的想法,师傅的考虑很正确,我刚向园长师傅请教的时候,园长师傅就给我分析了很多,包括,上面中的一部分;师傅对上面的几点想法,我逐一解释。
5.1 String/StringBuilder/StringBuffer等使用频率极高的基础类型,有没有必要hook?
首先,从代码审计的方法来看,外部输入的污点,经过StringBuilder的一系列操作,最终转换为了一个字符串,污点进入StringBuilder到转换为字符串的过程,是需要我们关心的;
然后,从IAST的角度来看,如果不完整的监控到污点所经过的每一个方法,就没有办法把污点的流向图完整的绘制出来;举个例子,String sql = "SELECT * FROM user WHERE username='"+request.getParameter("name")+"'";
面对这样的一条sql拼接的语句,如果不hook住StringBuilder
,如何判断这条sql语句跟原始污点相关呢?刚开始做IAST的时候,认为通过字符串的值来判断是否包含,就可以解决这个问题,然后,遇到了类似下面的这种场景,被无情打脸:
String sql = "SELECT * FROM user WHERE username='"+request.getParameter("name")+"'";
sql = "SELECT * FROM user WHERE username='admin'";
这个时候,如果用户输入的name参数值是admin
,按照污点值来判断的方法,下面的这条sql语句与用户输入是相关的,那应该如何判断sql语句跟用户的输入无关,排除误报呢?
也许方法有很多,但是,我们是被动式IAST,不重放任何请求,我们不能用重放请求改变数据的方式来排除误报,所以,我们只能选择用最准确的值传递算法来确保污点传播的过程是准确无误的。因此,我们需要对String/StringBuilder/StringBuffer等基础类型进行hook,来尽量的完善污点传播过程,避免误报的出现。
5.2 洞态IAST如何针对中间件进行hook?
洞态IAST没有针对中间件进行适配和hook,这种方式太慢,而且不够灵活,需要人工做大量的适配工作。洞态IAST针对Servlet
相关的API接口进行hook,所有实现了servlet接口的类都会被hook到,因此,不需要针对中间件进行适配,正常情况下,所有的中间件都可以支持,但,部分中间件可能出现违反双亲委派机制,用自定义的classloader的方式加载servlet处理类,导致无法覆盖到的问题,针对这种中间件,我们会做特定的处理。
5.3 hook点层次太浅,规律性较差
基于5.1中的解释,iast需要完整的梳理出污点调用链,而仅仅是通过source点和sink点来进行漏洞的判断。所以,我们会把所有的sink点都hook到,当污点进入刚进入sink点时,就直接拦截并且检测漏洞,减少sink点内部中相关方法调用带来的无效数据,提高性能;
所以,在RASP中,可以仅关心最底层的漏洞触发点,因为不需要关注污点的调用链情况,但是IAST中不能,自然也就不存在这个问题。
5.4 关于hook点的规则及hook规则的创建
为什么用完整的方法签名做匹配,会失去与0 Day打交道的能力呢?我并不认为这两者有什么关系,因为我们有把同一个组件不同版本的hook规则全部分析出来并进行hook,与统配方式达到的效果并没有太大的差别。
另外,师傅说的很对,我们不是手工创建规则的,我们有内部专用的IDEA
插件,用于快速生成规则

如图,我们可以针对java文件、class文件,快速生成对应的hook规则并添加至云端,此外,针对组件,我们还有专门的规则分析提取工具,会自动从jar包中,分析提取出符合我们查询条件的类、方法、字段,还可以用来寻找gadget。
【IDEA插件内测】 IDEA插件与2021-05-25日正式开始内测,安装插件后,可自动安装agent到应用中,实现边调试、边挖洞。第一波内测暂时开放30名用户,感兴趣的师傅们,加工作人员微信并发送:插件内测,工作人员会进行邀请师傅加入内测。
工作人员联系方式:

本文迁移自知识星球“火线Zone”