聊聊漏洞分析、漏洞利用和漏洞挖掘。
前言
说到安全就不能不说漏洞,而说到漏洞就不可避免地会说到三座大山:
- 漏洞分析
- 漏洞利用
- 漏洞挖掘
从笔者个人的感觉上来看,这三者尽管通常水乳交融、相互依赖,但难度是不尽相同的。本文就这三者分别谈谈自己的经验和想法。
漏洞分析
漏洞分析相对简单,通常公开的漏洞中就有一两句话描述了漏洞的成因,自己拉代码下来看也就能了解个大概。对于一些自己发现的bug,从崩溃日志中一般也能比较轻松地进行复现和调试。尽管有的bug排查起来相对繁琐,但总归是可以一步步减少范围锁定最终目标的。因此,网上对于漏洞分析的文章很多,一方面分析起来有迹可循,另一方面分析的漏洞也不一定是自己的“原创”漏洞,素材来源更加广泛。
漏洞分析虽然简单,却是每个安全研究人员的必经之路。就像练武中的扎马步、站梅花桩一样,是日积月累的基本功。之前研究内核时有段时间热衷于写漏洞分析的文章,后来随着日渐熟练,写文章记录的速度已经远远跟不上分析的进度,所以现在往往懒得动笔了。
基本功必不可少,但扎马步扎得再稳也不表示你能独步武林。有大佬曾经说过,如果他想的话,可以一天写好几篇分析文章还不带重样的。毕竟,漏洞分析的目的是为了学习、吸收、转化,以史为鉴,最终形成自己独到的理解。
漏洞利用
漏洞利用就相对复杂一点,尤其是对于二进制漏洞,成功的利用需要精巧的内存布局,因此需要对程序涉及到的数据结构要相当的了解。而且并不是所有漏洞都能转换为有效利用的,一般比较容易编写利用的漏洞,我们称之为品相好。对于品相不好的漏洞,我更喜欢将其称之为bug。当然也有人认为 bug 至少造成了程序崩溃,所以可以算一个DoS(拒绝服务)漏洞。
当然漏洞能否利用其实也是和人有关。对于复杂的系统,你认为无法利用的漏洞,大佬就能以一种你没想到的方式利用成功。比如安卓CVE-2019-2025(水滴)漏洞,属于Binder中的一个条件竞争,竞争窗口只有几条汇编指令。漏洞品相相当不好,连CVSS给出的可利用分数(Exploitability Score)也只有1.8分,但360的大佬们也通过玩弄调度器进行稳定利用提权了。
因此,关于漏洞利用的文章也就少了很多。一方面处于负责任披露安全问题的考虑,安全研究人员不会给出完整的利用细节,以免脚本小子滥用;另一方面对于公开的利用,你也总不能跟着写一篇文章灌水,毕竟利用思路很多时候是因人而异的,过于雷同就难免有炒冷饭的嫌疑,除非有一些独到的思考补充,或者有新的利用思路。
很多时候漏洞利用的文章看着看着就变成了漏洞利用分析
的文章,这也说明了漏洞利用难度颇高,能独立写出原创利用并进行分享的人不多。就我的感觉而言,漏洞利用更像是另一种形式的软件开发,首先通过漏洞构造原语,然后通过原语实现最终的利用程序。
漏洞挖掘
漏洞挖掘可以说是安全研究人员向往的高地之一,不管你分析了多少漏洞,写了多少利用,如果你没有自己挖掘出过原创的漏洞,那你的安全研究生涯就是不完整的。但是漏洞挖掘这事儿并不是确定性的。漏洞分析只要有漏洞肯定能分析清楚,只不过是时间问题;漏洞利用只要不是明显的无法利用,那至少也存在利用成功的可能性。
漏洞挖掘则不然,即便你盯着某个应用使劲挖,也不能保证有结果,说不定对方根本就没有能触发的漏洞。都说世上没有绝对安全的系统,但是相对安全的系统一抓一大把,至少在出问题之前,你是不知道的。
我们能看到各种安全会议中介绍各种新发现的漏洞和问题,网上也有很多相关的文章,但更多是炫技式分享(show-off),很少有分享怎么挖洞的。因此笔者就先抛砖引玉,谈谈自己的想法。
Fuzzing
自从 AFL 横空出世之后,当今漏洞挖掘言必称 Fuzzing,仿佛这是李云龙他娘的意大利炮,不管三七二十一先来上一发就能轰出几个 0day。当然,我不是说 Fuzz 不好,只不过凡事都有其诞生和得以应用的环境。
Fuzzing 即模糊测试,在早期是 QA 测试中的一项黑盒测试技术,通过随机变异的输入来测试程序的鲁棒性。在程序的崩溃被用于漏洞利用后,也就一跃成为一种漏洞挖掘方法。随机变异输入的效率相对低下,可能变异了半天连 main 函数里第一个 if 都没有跳进去。AFL 率先提出并实现了根据路径/覆盖率等反馈来进行输入的变异,从而大大提升了测试用例的有效性。
AFL
自从 2013 年 AFL 提出以来,各类 Fuzzer 百花齐放,在学术上有了爆发性的论文增长;开源社区有 honggfuzz、libFuzzer 等优秀的项目;在工程上有 OSS-Fuzz 利用庞大机器集群进行持续测试的应用和 syzkaller 这种年均发现几千内核漏洞的工具等。
从产出的漏洞数量来看,Fuzzing 作为一种漏洞挖掘方法可谓一骑绝尘。当时,随着时间的推移,通用模糊测试策略已经越来越难发现新的漏洞,要么你有独特的测试语料,要么你有领先的运算资源。因此,一部分人就从通用 Fuzzer 转回到了针对特定目标变异的 Fuzzer(即 Structure Aware Fuzzer)。也就是说,只针对目标程序接受的数据类型进行特定变异,比如针对 PDF 文件格式每个字段变异等等。
别忘了,AFL 这种通用 Fuzzer 的出现,就是为了实现一次编码,到处 Fuzz 的目的;而针对不同目标去写 Fuzzer,显然有违初衷。另外,如果目标接受的是已知格式的输入还好,对于未知格式,还需要自己去分析和理解各个字段含义。在阅读代码和理解代码逻辑的过程中,目标程序的潜在问题很可能已经出现在你眼前了,再去编写一个不能复用的 Fuzzer,显得有些多此一举。这种发现漏洞的方法也就是下节所说的——代码审计。
代码审计
代码审计,俗称看代码。有的人用 SourceInsight 看,有的人用 VIM 看,但不管怎么样还是用眼睛看。既然大家都长了两只眼睛,为什么有的人就能一个月看出十几个高危,有的人就只看了个寂寞?
看代码也是有方法的。虽然我比较想听听 @oldfresher 是怎么看代码的,但他似乎不太愿意分享,所以我只能说说自己的方法。
要挖漏洞首先要对漏洞进行分类,大致可以分为下面三种:
- 设计漏洞
- 实现漏洞
- 操作漏洞
所谓设计漏洞就是软件设计过程中就存在逻辑问题,比如 WiFi 的 WEP,设计的问题往往是比较严重的,而且修复周期长,所幸这类问题不是太多;实现漏洞就是我们常见的软件漏洞,内存溢出、UAF、条件竞争等都算在里面;操作漏洞和实现漏洞往往类似,只不过更多是指配置错误而产生的漏洞,比如 nginx 配置错误导致的目录穿越问题就属于一种操作漏洞。
明确漏洞类型后也不是马上开始看代码,而是先进行初步的攻击面分析,也就是常说的威胁建模。主要分为下面几步:
- 信息收集: 收集所有相关的资料,尤其是设计文档或者帮助手册等
- 应用架构建模: 列举应用所含的组件以及状态机,注意各个组件之间隐含的信任关系
- 威胁鉴定: 在各个流程中列举潜在的攻击点,并分别标记危害等级
- 审计计划: 按优先级对实现的审计计划进行排序
代码审计听起来是个让人退缩任务,因为你面对的是一堆你不熟悉的代码,而且要求你快速地建立起自己的理解而且找到其中最深层的秘密(安全漏洞)。通常你不会有足够的时间审计项目的每一行代码,因此这其中的一个重点就是懂得如何分配精力,在最可能出现安全问题的代码中达到满意的审计覆盖率。
成功的代码审计过程一定是务实、灵活且面向结果的。虽然讲究方法,但并不意味着根据别人的方法就能成功。与很多人的认知不同,代码审计其实是一件需要创造力的技能。那位说了,看别人代码要什么创造力?要在应用中找到漏洞,审计者需要将自己代入作者的思维中理解代码,同时还需要跳出作者的思维,洞察到原作者没有预料到的可能性;这种技能与知识相对,像是骑车、游泳、弹琴一样,是需要通过学习和练习去掌握的,而一旦掌握就像本能的一部分难以忘记。当然代码审计也有知识的部分,比如需要了解各种漏洞类型和场景等。
这些都这只是代码审计中的冰山一角,篇幅原因无法面面俱到。比如代码审计策略的抉择,是深度优先还是广度优先(看到某个函数调用是否需要追进去看);以及使用现代的静态分析工具来辅助审计,比如 Fority、CodeQL 等,后续有时间再单独进行介绍吧。
后记
漏洞分析是技术,漏洞利用是艺术,漏洞挖掘是法术。关于漏洞利用和漏洞挖掘哪个“技术含量”更高,还存在一定争议,但漏洞分析的基础地位毫无疑问。技术可以学,艺术可以练,法术呢?其实同样也可以通过练习提高自己的 漏洞挖掘水平。推荐一个忘了是什么地方的议题中提供的方法(也许是 CCC):
-
找到公开的漏洞通告,根据标题的内容自己去相关模块中审计看是否能发现该漏洞
-
如果发现不了,就回头接着看漏洞通告的细节,反思自己的审计方法
许是 CCC): -
找到公开的漏洞通告,根据标题的内容自己去相关模块中审计看是否能发现该漏洞
-
如果发现不了,就回头接着看漏洞通告的细节,反思自己的审计方法
-
不断重复,直到让自己可以认为找漏洞只是时间问题而不是能力问题接下来我将给各位同学划分一张学习计划表!
学习计划
那么问题又来了,作为萌新小白,我应该先学什么,再学什么?
既然你都问的这么直白了,我就告诉你,零基础应该从什么开始学起:
阶段一:初级网络安全工程师
接下来我将给大家安排一个为期1个月的网络安全初级计划,当你学完后,你基本可以从事一份网络安全相关的工作,比如渗透测试、Web渗透、安全服务、安全分析等岗位;其中,如果你等保模块学的好,还可以从事等保工程师。
综合薪资区间6k~15k
1、网络安全理论知识(2天)
①了解行业相关背景,前景,确定发展方向。
②学习网络安全相关法律法规。
③网络安全运营的概念。
④等保简介、等保规定、流程和规范。(非常重要)
2、渗透测试基础(1周)
①渗透测试的流程、分类、标准
②信息收集技术:主动/被动信息搜集、Nmap工具、Google Hacking
③漏洞扫描、漏洞利用、原理,利用方法、工具(MSF)、绕过IDS和反病毒侦察
④主机攻防演练:MS17-010、MS08-067、MS10-046、MS12-20等
3、操作系统基础(1周)
①Windows系统常见功能和命令
②Kali Linux系统常见功能和命令
③操作系统安全(系统入侵排查/系统加固基础)
4、计算机网络基础(1周)
①计算机网络基础、协议和架构
②网络通信原理、OSI模型、数据转发流程
③常见协议解析(HTTP、TCP/IP、ARP等)
④网络攻击技术与网络安全防御技术
⑤Web漏洞原理与防御:主动/被动攻击、DDOS攻击、CVE漏洞复现
5、数据库基础操作(2天)
①数据库基础
②SQL语言基础
③数据库安全加固
6、Web渗透(1周)
①HTML、CSS和JavaScript简介
②OWASP Top10
③Web漏洞扫描工具
④Web渗透工具:Nmap、BurpSuite、SQLMap、其他(菜刀、漏扫等)
那么,到此为止,已经耗时1个月左右。你已经成功成为了一名“脚本小子”。那么你还想接着往下探索吗?
阶段二:中级or高级网络安全工程师(看自己能力)
综合薪资区间15k~30k
7、脚本编程学习(4周)
在网络安全领域。是否具备编程能力是“脚本小子”和真正网络安全工程师的本质区别。在实际的渗透测试过程中,面对复杂多变的网络环境,当常用工具不能满足实际需求的时候,往往需要对现有工具进行扩展,或者编写符合我们要求的工具、自动化脚本,这个时候就需要具备一定的编程能力。在分秒必争的CTF竞赛中,想要高效地使用自制的脚本工具来实现各种目的,更是需要拥有编程能力。
零基础入门的同学,我建议选择脚本语言Python/PHP/Go/Java中的一种,对常用库进行编程学习
搭建开发环境和选择IDE,PHP环境推荐Wamp和XAMPP,IDE强烈推荐Sublime;
Python编程学习,学习内容包含:语法、正则、文件、 网络、多线程等常用库,推荐《Python核心编程》,没必要看完
用Python编写漏洞的exp,然后写一个简单的网络爬虫
PHP基本语法学习并书写一个简单的博客系统
熟悉MVC架构,并试着学习一个PHP框架或者Python框架 (可选)
了解Bootstrap的布局或者CSS。
阶段三:顶级网络安全工程师
如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!
学习资料分享
当然,只给予计划不给予学习资料的行为无异于耍流氓,这里给大家整理了一份【282G】的网络安全工程师从入门到精通的学习资料包,可点击下方二维码链接领取哦。
