自研之路:腾讯漏洞扫描系统的十年历程

安全 作者:HackerEye 2015-12-17 08:33:18

1、前言

在业务的生命周期里面,测试阶段——不管是上线前测试还是上线后测试都是安全团队的重要战场,历来为兵家必争之地,所以这里成就了漏洞扫描系统(这里指系统和Web漏洞)。漏洞扫描系统的市场非常火爆,很多安全公司都出售自己的漏洞扫描设备或者提供远程漏洞检测服务。

但是对于大型企业,特别是在线业务庞大的大型互联网企业来讲,服务器和Web站点众多,且发布变更频繁,传统的商业漏洞扫描器往往不能满足其大规模和定制化的个性需求,这里就产生了自行研发的需求。

“十年生聚十年教训”,腾讯自2005年就开始研发漏洞扫描系统,迄今为止正好十年,历经了三代架构变迁,最近正好在总结规划,于是我就顺便把腾讯漏洞扫描系统的一些建设经验和教训分享出来,供同行参考。

2、石器时代:艰苦创业

腾讯安全平台部的前身腾讯安全中心刚刚成立之初,准备自动化的发现和清理安全漏洞,所以就产生了使用漏洞扫描系统的需求。当时公司又发布了《高危端口管理规范》,推动业务把对外暴露的服务控制在Web层面(简单理解就是非HTTP端口无必要不对外开放),所以就可以集中精力来保证Web安全。

那时条件比较艰苦,整个团队也就几个人,也没有专业的开发,所以当时采用的方案是开源的Nessus做系统漏洞扫描,Nikto、Wikto等加上自己写的Perl脚本来做Web漏洞扫描。那时网站还没有现在那么多,系统对外暴露的比较少,这套方案勉强满足了当时的需求。

其实说起原理来也比较简单,漏洞扫描系统的常规工作模式无非是基于HTTP协议的请求发送和响应检查(正则匹配),而Perl自身的LWP包(当然你也可以用IO::Socket自己来实现HTTP协议)就支持HTTP协议,所以用Perl写一个简单的漏洞扫描器非常方便。比如以下就是在2007年写的临时检测Apache Expect HTTP Header XSS漏洞的Perl代码:

由于年代久远,腾讯第一代漏洞扫描器的Perl代码应该早已失传——不过也不一定,或许在benjurry、coolc、炽天使他们老一辈无产阶级革命家的某个尘封已久的电脑里能找到。不要小看这个简易扫描器,当年它为腾讯安全立下了汗马功劳。

这个时期商业的漏洞扫描系统大致分为两类:一类是Windows客户端软件,如IBM的APPScan、Acunetix的WVS、惠普的WebInspect等;另一类是硬件设备,一个硬件设备直接接入网络工作,如绿盟的极光、启明星辰的天镜等。

3、铁器时代:初具雏形

随着时间的推进,Perl扫描器的各种问题就暴露出来了。

首当其冲的就是Perl代码是解释执行的,执行速度慢,也没有分布式任务,整体效率非常低下,往往检测一遍全部业务要花很长时间。加之当时Web 2.0时代,Web业务急速膨胀,在线业务也经常会有更新,这时候安全团队迫切需要一个更快速的漏洞扫描系统。

时势造英雄,当时正好有新的血液加入团队:来自武汉大学的mango。信息安全专业在2002年首次在武汉大学成立,mango正是当年的首批毕业生(关于他在腾讯经历可以看他的文章《武大学子在腾讯做应用安全》)。他一来就在做Web安全,积累了一定经验,开发功底又比较好,所以新的漏洞扫描系统的就由他当时的导师apple(腾讯挂马检测系统之父,业内首创JS解析检测挂马攻击,我也有幸作为运营人员为挂马检测系统配置了第一批规则)带着他一起做了。

新的漏洞扫描系统使用C++开发,扫描节点分别部署在几台服务器上(节点很容易安装部署,方便扩容),还有一个总控的任务调度服务器,采用爬虫先爬行URL再检测的方式,支持像SQL注入、XSS、命令执行、任意文件读取等大部分常见的Web应用漏洞。

这个阶段基本也没有研发流程,主要是靠mango自己开发测试甚至运营;漏洞处理流程也是刚刚建立,就是检测出漏洞后运营人员确认无误报后通知到安全接口人处理——我毕业那会儿刚到腾讯的工作职责之一就是这个。

还记得当时XSS漏洞原理并不普及,而我们的XSS漏洞验证PoC就是alert弹框,导致很多开发人员误以为XSS漏洞就是弹框,进而认为这不是漏洞,往往会挑战这里的专业度,然后我把PoC改成了类似下面这样的代码,一切都迎刃而解了(运营思路是多么重要)。

这里还有个坑要注意,漏洞扫描系统在检测生产环境时一定要避免进行破坏性测试或者要对破坏性测试有应急预案(这是另外一个话题了,参见这篇《安全产品的自我修养》)。当年mango用延时法检测SQL注入漏洞的时候把业务数据库挂起了一段时间——这是一个一秒钟几十万上下的业务,我们把花了巨资买来的教训无私奉献出来了,请点赞。

新的漏洞扫描系统完成后速度和效率基本满足了当时的场景。今天我们为了纪念mango当年的功劳,都尊他为腾讯“扫描器之父”。后来mango去了某银行安全团队,不再写漏洞扫描系统,但是他的传奇仍然延续——据说mango在新的单位负责渗透测试,在内网驱驰如入无人之境,以至于蓝军团队不得不把他全程视频监控起来避免他找到新的漏洞而自己不知道。

4、工业时代:全面开战

mango之后薪尽火传,新一届毕业生接手了漏洞扫描系统。现在团队壮大了,项目、研发、运营、安全各司其职。

这个阶段公司业务飞速发展,每年服务器和Web站点都在增加,IDC也在增加,跨IDC扫描会有速度慢、网络不通、误报、网络阻塞等问题,所以团队在之前的架构下优化代码并大规模部署(基本上要每个IDC都有一个扫描节点,已成为IDC建设标配),同时接入SOC流程(2008年我们自建了SOC),所有漏洞通过安全事件工单来跟进闭环。

名正言顺,与流程对应的是配套安全规范的制定和发布。公司专门发布了安全漏洞处理规范,规定了安全的责任口径、上线前安全检测流程、漏洞处理细则(基本上外部报告的高危漏洞必须立即修复)、违反规范的处罚等。

接下来又进行了一系列技术上的优化。

随着Web2.0的技术应用,传统的HTML爬虫已经不能胜任,所以研发团队需要优化爬虫。我们抛弃了旧版基于SpiderMonkey的爬虫,而使用了基于浏览器内核的QtWebKit来解析JavaScript,这样遇到类似JavaScript拼接或者ajax的页面也可以畅通无阻了(这需要解决几个问题,例如消除所有弹窗、支持代理、解决执行死循环问题等等,业界已经有非常成熟的实现方案了),这个新一代的爬虫启动后URL量立即新增了一倍多。除了爬虫,QtWebKit的JavaScript解析和模拟执行能力还可以应用到一些DOM类漏洞的检测上,比如DOM XSS、DOM Jump等。

很多业务逻辑需要QQ登录才能触发,所以漏洞扫描器也增加了这个定制功能——市面上的商业扫描器还没有自动支持QQ登录的吧,当然他们的客户也不需要这个功能。

类似的还有一些跟QQ业务逻辑关联的漏洞(统称为业务逻辑漏洞),都做了定制化的策略,这些能力也是商业设备不具备的。

即使如此还是有URL会漏,直接导致漏洞不能被漏洞扫描系统发现,所以团队又集思广益做了四件事情:IDS改造、Proxy部署、客户端插件和业务提交——分别通过部署在机房入口的IDS、办公网的HTTP代理、测试人员PC上安装浏览器插件以及业务主动上报URL列表来实现最大化的URL收集。

然后又遇到一个海量数据的处理问题。腾讯Web站点庞大,据不完全统计,把各种渠道收集到的URL去重后大概有两千万(未去重的全量就更多了),把这些URL放到数据库中作为缓存,可以在快速模式检测的时候直接检测而不用再用爬虫去抓取(这个有点类似知道创宇的ZoomEye)。海量数据放到MySQL后,效率完全跟不上,团队又采用了Storm来解决这个问题。

这里就不得不说到快慢速模式,它其实就是一个速度优先或准确度优先的方案。快速模式可以迅速过一遍已知的URL,适用于新的漏洞出现后的快速扫描,目前我们能够两小时内检测完全量URL;慢速模式就是牺牲速度提升准确度,适用于常规漏洞的日常扫描。

新建一个系统的时候往往备受瞩目,而系统建成后就会平静下来,所以做实事的我们一定要避免“重建设轻运营”。

在运营上,团队一方面是优化规则,这个主要是通过漏报案例来优化。比如我们分析外部报告漏洞的时候发现有个白帽子连续发现很多高危漏洞,再从技术上分析他的手法,发现他是经常找一些偏僻业务,这种小业务的运维团队安全意识很弱,非常容易出问题。于是我们也用扫描器增加了类似的扫描,采用“疑罪从有”的思路,每天人工去跟进确认,很快就把这块漏洞清理完毕。

另一方面是数据分析(嗯,用时髦的话来说就是数据驱动需求)。下面是2011年的一个报表,当时XSS漏洞量比较大,于是就深入分析出问题较多的部门和原因并进行了优化。比如当时某个部门线上漏洞多的原因是他们发布前未接入漏洞扫描系统检测,于是我们的运营人员就拿着数据去推动该部门在测试阶段加上这个流程。

也得益于公司业务的蓬勃发展和部门的稳步前进,这个时期漏洞扫描系统也在快速发展,不管是系统功能还是人力都得到了增强,特别是后来圈内元老zhaohuan的加入,让漏洞扫描系统如虎添翼。

我们来看一下这几年腾讯的外部发现漏洞趋势图,可以看到2013年起有一个明显的收敛,一方面是因为腾讯安全应急响应中心的工作,另一方面就是漏洞扫描系统的发力。

这个时期商业漏洞扫描系统进化成云服务,一些新兴安全公司提供了基于云的远程漏洞扫描的服务,如知道创宇的SCANV、360的WebScan等。同时互联网巨头如阿里、百度都已走上自研之路。

5、后工业时代:全新架构

虽然漏洞扫描系统取得了前述的一定进展,但是随着时代的进步,我们又遇到了新问题。

第一个问题就是漏洞转化为规则慢。我们发现一个漏洞更新到规则或者修改一个规则至要花上好几天,这是不能容忍的。再深入分析发现,原来旧的系统架构大部分核心规则是被编译到二进制里的,规则还需要运营人员先跟开发人员讲清楚原理和方案,然后开发人员再编码,然后再编译再测试再发布,结果导致任何规则变更都要重新编译、测试、灰度部署,一套发布流程下来几天就过去了。

第二个是产品化问题。以前漏洞扫描系统就是运营人员自己使用,最多也给业务的测试人员用,都是技术流,又都是内部自己人,所以就是一个简单的又土又挫的Web页面进行配置就行。但是随着腾讯云的发展,我们的漏洞扫描系统也会给到腾讯云上的用户以及合作方使用,很多用户是小白,根本搞不清楚这些配置参数,这块用户体验也需要重新整改。

最后是资源问题。漏洞扫描系统一般是通过单个线程或者进程处理同一个CGI的漏洞检测,这样就会阻塞起来,提高性能的唯一办法就是采用多线程/多进程,但是频繁的进程间切换就会耗费大量CPU时间,太多进程也会耗费大量内存,最终导致性能低下。之前是通过堆服务器的方式解决了性能问题,现在回过头来发现架构上是可以优化的——嗯,是时候展示真正的后台能力了。

由于以上种种原因,我们决定重构,打造一个全新的漏洞扫描系统(内部代号:“C”),主要实现规则插件化、UI产品化、性能大大优化。于是“漏洞扫描系统重构项目”启动,我们跨中心组建了包括安全、研发、前端、产品的十余人敏捷团队历时五个月完成一期工程。

这个版本的主要设计思想是把平台和规则分离,也就是说平台只负责性能和调度,而规则由插件集合组成,一个规则对应一个或者多个插件。

平台由C++开发,插件是Lua语言。为了方便一些非专业人士(未来会对合作方和云用户开放),我们把一些简单的规则做成Web页面编写,比如输入X,若输出Y,则存在该漏洞这种简单逻辑;对于一些复杂逻辑,可以用Lua来实现——你可以自定义任何HTTP请求字段乃至TCP/IP的数据包格式。

以下就是一个简单的Lua插件。

新的系统采用全异步事件驱动、协程的方案来解决性能问题。这个方案立竿见影,服务器立即节约出来了。一台8核CPU、8G内存的服务器一天可以扫描的CGI数大约是10万个,发送的HTTP请求为2亿个,是之前的N倍。

来看一下系统架构图:

目前这套新架构已经在腾讯内部灰度上线,后续也会支持到腾讯云,所以腾讯云用户将来也可以体验到。

插件化看起来是未来的趋势,国内新一代安全公司如四叶草的BugScan、乌云的TangScan都是这种插件化的扫描器,而且它们直接是采用众包模式来开发插件。

6、后记

总结来看,企业的漏洞扫描器不管是采购还是自研,都不是越强大越高级越昂贵越好,而是能适合企业当前乃至未来一段时间的需求,能够解决企业所遇到的实际问题才行。

十年磨一剑,腾讯漏洞扫描系统的十年发展历程,也是腾讯安全团队从小到大由弱变强的一个缩影,有幸能够跟这样一个积极上进、低调务实的团队一起见证——业务发展、老板支持、团队稳定三因素缺一不可。

随着漏洞扫描系统的更迭优化,运营中我们逐渐明白一个道理:安全是一个整体,安全风险并不是只依靠漏洞扫描系统能够解决的。

当你意识到这一步的时候,你又将踏上新的征程。

文章来源【腾讯安全应急响应中心】

关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接