Strive for lofty goals

基于甲方视角的漏洞发现

为什么总是被外部发现该发现但遗漏的漏洞?为什么各种黑白灰扫描器老有各种原因遗漏的漏洞?如何解决人工渗透测试带来的遗漏、效率问题?你是否也遇到这些问题,本文会讲讲我理解的漏洞发现,并基于该理论延伸的甲方漏洞发现最佳实践初探。

甲白乙黑:打破乙方思维,找到甲方优势

早期为了发现漏洞需要手工一个个参数去尝试各种Payload,后来用黑盒漏洞扫描器来逐渐替换掉那些重复性的手工操作。我们总在说,不知攻焉知防,但现实所见全是用攻的思维做防。白帽子们进入甲方开始建设企业安全时,也自然而然把黑盒漏洞扫描器搬了过来,甚至作为主要漏洞发现手段。

虽然黑盒漏扫确实也能发现漏洞,但却在理念上和甲方漏洞发现相去甚远。甲乙方的安全同学有何差异?好像都要做漏洞发现,但这只是表象。乙方发现漏洞的目的是为了找一个突破口继而深入渗透,或为了证明你确实有漏洞好卖安全产品,他只需要发现一个漏洞就赢了。而甲方发现漏洞的目的是为了漏洞不被利用造成损失,因此需要发现所有漏洞。一边是发现一个漏洞就赢了,一边是要发现所有漏洞。在这种目标不对等的前提下,如果我们发现漏洞的手段还是一样的,那必然斗不过乙方,次次红蓝对抗以失败告终、黑盒扫描器永远在遗漏、甚至低级问题层出不穷。

那怎样破局呢?世上没有绝对的公平但有相对的公平,关了一扇窗必然会为你开一扇窗。甲方到底有什么是乙方所没有的?那就是内部各种信息对于甲方来说是透明的,能很清楚的知道自己有多少域名而不需要爆破、知道自己有多少接口而不用爬取、知道自己开了什么端口而不用扫描、知道自己开了什么服务而不用试探、知道自己引了什么框架依赖而不用扫描、知道应用内的业务逻辑而不用猜测… 透明的白盒子是甲方安全最大的优势,而这一切对于乙方来说都是不透明的黑匣子。

乙方黑盒本质上不清楚目标内部构造,需要尝试通过构造各种请求并根据响应信息来判断漏洞的存在。这种模式的坏处是必然存在较多遗漏,这个遗漏可能是爬取局限性导致没发现某个接口、也可能是不理解业务导致没符合某个接口的前置条件导致没进入到接口逻辑、当然也可能是特定版本差异导致Payload兼容问题没利用成功等低级问题。而甲方则不一样,可以通过流量清楚的知道自己有多少接口和这些接口的响应内容,每个接口的可能存在的风险,对应的后端应用,应用的机器,机器上的进程,进程对应的代码、配置和开启的端口甚至打开的文件Jar包等,当我们充分利用好这些透明信息时,就可以快速的发现和确认漏洞。

除了利用好透明信息外,还需要串起所有安全产品来制造更大优势。每个漏洞抽象来看是存在不同形态的,比如Web目录的文件泄漏他本质上是在Web目录存放了一些能被访问的文件、反序列化漏洞往往是引用了一些序列化的包或类、SSRF往往是最终参数传入了request函数、敏感信息泄漏往往是响应内容的包含特定格式的敏感数据等等。因为漏洞存在不同形态,因此不同的漏洞需要在不同的阶段或层次检测才能得到最优解。每个阶段的白盒子能力都有各自的优势同时也有各自的局限。而我们就是要从单点相互独立的白盒子漏洞发现转向联动体系化的漏洞发现,将局限限制到最小,将各个优势集合起来发挥最大的优势。

除了透明的白盒子和联动各层次阶段的安全产品是甲方安全利器外,另外一大优势就是上线前的漏洞发现。当我们在上线前进行漏洞发现时,我们的竞争对手是我们自己,当我们在上线后进行漏洞发现,我们的竞争对手就是整个互联网的白帽子、黑灰产,用战略将优势发挥到极致,不在战术上和对方比拼,因此上线前的漏洞发现必须作为甲方安全的基础认知保持统一。

为便于后续安全行业内交流和理解一致性,我们将这个理论定义为甲白乙黑(当然如果你觉得做安全的人喜欢造名词也行),并由以下两条定义组成:

  • 甲方主要漏洞发现应按照白盒子方式进行,目标是在上线前利用各阶段或层次的安全产品发现全部已知漏洞。包括域名、IP、端口、服务、代码、依赖、机器、流量、接口、逻辑、数据库等。
  • 乙方主要漏洞发现按照黑盒子方式进行,目标是发现尽可能多的高危漏洞并继续横向扩展。包括域名爆破、端口扫描、服务识别、漏洞扫描等。

这里顺便插一句误区,说到甲方要用透明白盒子理念发现漏洞,很多人就会想到通过扫描代码的方式发现漏洞、或者一些商业扫描器会将甲方流量导入到黑盒中来弥补黑盒漏扫爬取不全的问题,也有一些公司会用HIDS采集主机的漏洞,那这就是甲白乙黑理论的应用吗?说属于确实也属于,但应用的较为初级且浅显。很多时候做安全的人存在一种莫名的优越感,总感觉自己做的更好别人都是垃圾,听到别人做什么怎么做的时候就会把自己做的无意识的往上靠认为自己也做到了,殊不知只是有那么点交集但理念上天壤之别,安全行业缺少一套公开的机制来检验或对标安全水位。比如拼多多和京东看着都能购物,但在购物方式、性价比、送货效率上很不一样。这导致的后果是没有理论指导很有可能下一次决策时就走偏了,很多公司都是看别人家有什么就做什么,对于很多人来说应用安全不就是黑白灰盒上一套、SDL搞一搞,这种没有理论支撑的做法会导致在做决策的时候选错方向。同理应用在其它领域也一样,在各个阶段堆了一些安全产品就叫纵深防御了?做了IAST就是安全切面了?做了最佳安全配置实践就是内生安全了?看到某个漏洞多就去解决某个漏洞就是木桶理论了?公司因为漏洞导致出现安全事件就是没有100%的安全了?

甲方漏洞发现体系最佳实践初探

在阿里有一句土话叫路走对了就不怕。基于甲白乙黑的漏洞发现理念的指导,为了让大家体感更深刻,通过分享一些遇到的实际问题来回顾下我们的实践历程。

解决人工渗透测试弊端,感知应用更细粒度安全

很多甲方安全团队都有人工渗透测试的工作,有因为要降低扫描器的遗漏,也有要补位扫描器的能力不足,也有接手新业务等情况。在早期接手新业务时,也希望快速弄清楚存量业务风险,而通过人工和扫描器的方式去做安全摸底。从漏洞数量上看,效果是很好的,短期内发现了大量的漏洞,其中不乏各种高危严重漏洞。但从过程体验和持续性上来看,很不如人意。典型的问题包括三大类:测不全导致的遗漏、测试效率低、重复测试。

先说说重复测试的问题,分为两类,一类是各个同学间业务业务相关性较大很难完全划分开,必然导致互相测试到对方的业务,这种情况还比较好,就当作double check。另外一类情况是自己负责的业务自己测过,但因为没有记录或记录方式的问题导致很难在后期维护好,从而重复测试接口问题。

测试效率低也可以分为多个环节来看,一方面是目标信息收集的效率,根据资产掌握的程度,一些标准业务的域名、IP、端口、服务、代码等都很清晰,不需要花费太多时间就知道目标大体情况,可往往有很多非标应用此时依赖去跟对应业务方沟通,涉及到沟通效率就骤减。另外一方面是渗透测试效率,需要手动的对每个目标可疑参数进行测试,效率是很低的,想想每个人的人工成本还是很高的。

在人工渗透测试过程中,因为人的参与必然导致人的经验和状态都会直接影响的结果,每个渗透人员的测试的习惯、渗透的思路、看漏洞的深度都不一样,同时每个人每天的状态也不一样,可能昨天熬夜导致今天状态不好,也可能因为家里的事情导致分神。另外一方面是目标本身的复杂性带来的遗漏,很难在短时间理解透系统,触发到每个业务逻辑,覆盖所有接口。

那如何解决呢?回顾上面提到的甲白乙黑理论中讲到黑盒方式必然存在漏洞遗漏,主要漏洞发现应依赖白盒子方式。

回顾下如果做白盒代码审计时,一般如何做?一种方式是找到所有接口,看每个接口传参链路是否会到危害函数。另外一种方式则相反,先找到危害函数,再反推看看入参是否可被外部用户控制,因为存在大量参数不可被外部用户控制,因此第二种方式的成本会比第一种要高。这两者的核心都是拿到程序的调用栈来判断,调用栈信息可以通过IAST或SAST来获取。按照第一种方式,我们有两步要做:拿到所有的接口参数+判断这些参数是否存在风险。

在测试环境拿到含有Request和Response的流量,对流量进行清洗(去掉爬虫/扫描器/静态资源/错误状态码等)和去重(同类型接口合并为一个接口),并对每条流量特征进行风险打标以及赋予分值。并将对应需要处理的风险展示在Web平台供人工处理,确定存在风险的可以点击上报漏洞,不存在风险可点击误报,再优化风险打标逻辑减少误报出现。

这里重点讲下如何基于流量打出风险标签,根据漏洞类型的不同这里打标签的方式也不一样。有些漏洞基于流量很容易直接确认,比如未脱敏、泄漏密钥密码、短信口、登录口、文件上传下载、任意链接跳转、XXE、CSRF、SSRF、命令和代码执行、任意SQL执行、JSONP等。而有一些则需要通过流量进一步分析才可以得出,比如越权漏洞,可以通过历史访问情况来计算某个接口是公共接口、私有接口还是混用接口情况。考虑到规则匹配特征的准确性、危害性以及网络可访问状态可以给每条风险定义一个分值,后续按照分值高低的优先级处理。

此时依赖流量的覆盖情况可以解决人工渗透测试遗漏问题,通过基于流量请求和响应特征自动发现风险解决了人工渗透测试部分效率问题,通过对无风险接口加白解决人工渗透测试的重复测试问题,最终让我们由原来的知道某个应用测过到现在应用的每个接口都测过。

当有新的接口时能及时感知到,当接口参数有变动时也能发现。但当从接口参数上看不出来变化,但背后实现的逻辑却变了时候,就需要联动发布系统,知道每次变更的代码和应用,继而关联对应的域名和接口,重新走一遍接口的漏洞发现逻辑。

解决黑盒漏洞扫描器弊端,联动各层次阶段安全产品制造更大优势

在前面解决了人工渗透测试的弊端,效率、重复、遗漏等问题后,也让我们能从原先对一个应用的安全性细化到接口参数级别。这里面简化了原来人工渗透测试时收集资产和找到疑似风险点两部分工作,同时部分漏洞直接基于流量即可直接确认掉。但因为漏洞的不同形态,还是会存在很多风险需要进一步确认是否真实存在,这块的效率也需要继续提升。

自动化确认风险是否存在,最直接办法就是试一下攻击payload是否能打成功,这听着有点像黑盒,那不是又绕回原点去做黑盒了?这又回到前面提到的,很多东西你看着相似,但理念不一样导致的结果差异巨大。传统黑盒理念上就站在乙方黑匣子立场去爬取流量、发送Payload判断漏洞是否存在,他最大的问题在于不理解业务,所以没有针对性的对所有接口一通乱扫,浪费资源的同时效率也不高。同时由于无法知道正常业务是什么样的,导致很多时候没有进入到真实的业务逻辑里,甚至被账号权限、业务前置条件等低级问题拦住。

流量是个引子,请求响应和访问顺序构成了理解业务的基础,基于不同漏洞的不同形态,联动各层次各阶段的安全产品,弃其局限,聚其优势。可以将基于流量标示出来的风险给到验证脚本,验证脚本则根据正常业务响应内容来判断出是否有漏洞,没有漏洞的话要区分出是没扫到漏洞还是没进入到业务逻辑。如果没进到业务逻辑则需要反馈给平台,让平台调度SAST的抽象语法树或IAST函数调用栈或主机进程文件信息来确认漏洞是否存在,都不能确认就将所有信息展示在平台上供人工处理时参考,同时后续看是否能优化此类场景。

由于安全能力是持续不断的建设,在早期为达到安全目标可以选择漏洞可不被证明,比如一些密码硬编码、引了低版本fastjson包等此类风险无法确定直接的利用途径,一律全部改造修复。要注意的是不能交由业务方判断外部入参是否可控来决定是否改造修复,安全同学之间对漏洞理解都有差异,如果将安全判断交由技术同学则一定会出现误判遗漏情况。而为了给技术更好的体验,而不是天天跟在屁股后面催他们修漏洞,需要提升漏洞发现准确性来减少为了修漏洞而修漏洞的情况,同时也应该用好WAF、RASP等应用层的安全防护工具来为业务方预留更充足的迭代修复时间。

对业务的每次变动带来的漏洞在上线前绝大多数都能自动确认提交,少数需要人工介入确认。很清楚的知道有多少应用和服务,用的什么框架引了什么依赖,上下游应用是什么,运行在哪些机器上,开放了哪些端口,绑定了哪些域名,域名上有多少接口,每个接口有哪些风险是否都测试过。安全工程师不用挖漏洞了,精力可以放到安全能力建设和安全研究上,产生对个人对部门对公司更大的价值。

By Feei
Strive for lofty goals
Loading