漏洞挖掘入门教程:从零开始掌握基本过程
初学者最好不要直接上手进行漏洞挖掘,因为漏洞挖掘需要很多的系统基础知识和一些理论知识做铺垫,而且难度较大。较合理的途径应该从漏洞利用入手,不妨分析一些公开的 CVE 漏洞。很多漏洞都有比较好的资料,分析研究的多了,对漏洞的认识自然就不同了,然后再去搞挖掘就会易上手一点。
漏洞挖掘可类比为迷宫游戏,主要包含枚举程序入口点、思考可能出现的不安全状态及设法到达不安全状态三个步骤。漏洞分为通用型和上下文型两类。挖掘者需掌握程序正向开发技术、攻防一体理念、工具使用能力及对目标应用的深入理解。分析方法涵盖程序用途、执行条件、通信分析及代码二进制分析。此外,还需关注漏洞的复杂性与团队协作模式,通过不断尝试与实践提升挖掘能力。

初学者最好不要直接上手进行漏洞挖掘,因为漏洞挖掘需要很多的系统基础知识和一些理论知识做铺垫,而且难度较大。较合理的途径应该从漏洞利用入手,不妨分析一些公开的 CVE 漏洞。很多漏洞都有比较好的资料,分析研究的多了,对漏洞的认识自然就不同了,然后再去搞挖掘就会易上手一点。
俗话说:'磨刀不误砍柴工',就是这么个理儿。
对于有一些基础知识的初学者,应该怎样进行漏洞挖掘呢?

从某个角度来讲,我们可以将漏洞挖掘工作比作玩迷宫游戏,不同的是,这个迷宫与我们平时所见的游戏中的迷宫略有不同:
(1)你无法立即看到它整体的外观 (2)随着漏洞挖掘工作的深入,这个迷宫的形状逐渐扩大 (3)你将会拥有多个起点及终点,但是无法确定这些点具体在哪里 (4)最终这个迷宫可能永远也无法 100% 的完整,但是却能够弄清楚 A 点至 B 点的一条完整路径
具体一点地描述,我们可以将漏洞挖掘工作归结为三个步骤:
(1)枚举程序入口点(例如:与程序交互的接口) (2)思考可能出现的不安全状态(即漏洞) (3)设法使用识别的入口点到达不安全状态
即是说,在这个过程中,迷宫是我们研究的应用程序,地图是我们对程序的理解程度,起点是我们的入口点(交互接口),终点为程序的不安全状态。
所谓入口点,既可以是 UI 界面上直观可见的交互接口,也可以是非常模糊与透明的交互接口(例如 IPC),以下是部分安全研究员较为感兴趣的关注点:
(1)应用程序中比较古老的代码段,并且这一部分随着时间的推移并没有太大的变化。 (2)应用程序中用于连接由不同开发团队或者开发者开发的程序模块的接口部分 (3)应用程序中那些调试和测试的部分代码,这部分代码本应在形成 Release 版本时去除,但由于某些原因不小心遗留在程序中。 (4)C-S 模式(带客户端和服务端)的应用中客户端及服务端调用 API 的差异部分(例如网页表单中的 hide 属性字段) (5)不受终端用户直接影响的内部请求(如 IPC)
从攻击面上来划分,可以将漏洞分为两大类,通用漏洞(General)和上下文漏洞(Contextual)。通用型漏洞是指在我们对应用的业务逻辑不是非常熟悉的情况下能够找出的漏洞,例如一些 RCE(远程代码执行)、SQLi(sql 注入)、XSS(跨站)等。上下文漏洞是指需要在对应用的业务逻辑、认证方式等非常熟悉的情况下才能找到的漏洞,例如权限绕过等。
在漏洞挖掘的过程中,首先根据经验优先考虑研究测试那些可能会对应用产生巨大威胁的部分。一些轻量级威胁检测模型(如 STRIDE)可以辅助我们做出这样的决策。
下面我们来看一个 WEB 应用程序的漏洞示例,后面将会介绍桌面程序:

首先我们假设目标 web 应用是一个单页面应用程序(single-page-application SPA),我们已经获得合法验证去访问这个应用,但是我们没有任何关于服务端的源代码或者二进制文件。在这种情况下,当我们枚举入口点时,可以通过探寻该应用的不同功能来进一步了解其业务逻辑及功能,可以通过抓包分析看 HTTP 请求内容,也可以分析客户端的网页代码获取需要提交表单的列表,但是最终的限制还是我们无法具体知悉客户端和服务端调用的 API 之间的区别,不过通过以上方法,我们可以找到一些入口点。
接着就是操作这些入口点,以试图达到我们预期的不安全状态。由于漏洞的形态很多,我们通常需要构建一个适用于该测试应用程序的业务功能漏洞的测试集,以求达到最高效地寻找漏洞。如果不那样做的话,我们就将会在一些无用的测试集上花费大量时间,并且看不到任何效果(举个例子,当后台的数据库为 Postgres 时,我们用 xp_cmdshell 去测试,测试再多次都无济于事)。所以在构造测试集时,需对应用程序的逻辑有较深的理解。下图形象地展示了低效率测试集的效果:

对于桌面应用程序,漏洞挖掘的思路本质上与 web 程序是类似的,不过也有一些区别:最大的区别在于,桌面应用的执行方式与流程与 web 程序不一样,下图展示的是桌面应用漏洞挖掘的一些内容:

与黑盒测试相比,当有源代码时(白盒测试),在寻找代码入口和程序执行路径等漏洞挖掘点时所做的猜测性的工作会大大减少,在这种情况下,将数据载荷从入口点执行到不安全的程序位置的效率低于从不安全的程序位置回溯至入口点。不过在白盒测试中,你对代码的测试的覆盖面可能会由于你自己的知识局限性而受到影响。
从事漏洞挖掘工作需要具备的知识是极其广泛的,并且随着时间在不断改变,也取决于你所研究的对象(web 程序、桌面程序、嵌入式等等)。不过,万变不离其宗,所需要掌握的知识领域却总可以认为是确定的,大致可以分为以下四个方面:
(1)程序正向开发技术。这是一个开发者需要掌握的能力,包括编程语言、系统内部设计、设计模式、协议、框架等。拥有丰富编程经验与开发能力的人在漏洞挖掘过程中往往比那些只对安全相关领域有所了解的人员对目标应用能有更深入的理解,从而有更高的产出。
(2)攻防一体的理念。这些知识涵盖了从基本的安全原则到不断变换的漏洞形态及漏洞缓解措施。攻击和防御结合的理念,能够有效帮助研究者既能够发现漏洞,同时也能够快速给出有效的漏洞缓解措施和规避方法。
(3)有效使用工具。能够高效的使用工具能够快速将思路转化为实践,这需要通过花时间去学习如何配置和使用工具,将其应用于自己的任务并构建自己的工作流程来不断积累经验。更进一步,需要深入掌握所使用工具的原理,以及如何对其进行二次开发,以使得其能够更加高效的应用于当前的工作实际。事实上,面向过程的学习方法往往比面向工具的学习方法更加高效以及有价值,当自己发现一个在使用一个工具遇到瓶颈时,先不要退缩,尝试去改造它,或者通过自己动手实践去完成能够适应当前工作的工具,这往往能够帮助快速积累大量实践经验。帮助我们以后更加高效的去实践漏洞挖掘工作。
(4)对目标应用的理解。最后,也是最重要的,作为一个漏洞挖掘人员,对自己研究的应用程序在安全性方面必须要比这个程序的开发者或维护者有更深的理解。这样你才能尽可能的发现这个程序中的漏洞并修复它。
下面这张表格介绍了挖掘 web 应用程序和桌面应用程序的漏洞时所需要掌握的内容。每个类别中的条目仅用于说明目的,并非详尽无遗。


这些知识领域将会帮助你提高挖掘漏洞的能力。如果说上面一节是讲述挖掘漏洞所需要的知识,那么下面的这一节将讲述挖漏洞如何做。
当分析一个应用程序时,你可以使用下图展示的四个'分析模型',如果遇到障碍导致思路受阻时,你可以从其中一个模型切换到下一个模型,当然,这不是一个线性的切换,你也可以有自己的一套方法。

在每一个模型之中都有主动活动(active activities)与客观活动存在(passive activities),主动活动需要我们对程序的执行环境及上下文有一个比较全面的了解,而客观活动却不一定,比如它是客观存在与程序的一些技术文档之中。不过,这种划分也不一定严格,不过对于每一个活动,我们可以从以下几方面去考虑:
(1)理解有关漏洞的相关模型 (2)试图假设一个场景去破坏程序 (3)尝试去破坏程序

程序用途分析是指理解一个应用程序做了什么工作,会提供什么服务等。同时,阅读与该程序的相关文档将有助于进一步理解程序功能(如上图所示)。这样做有利于对程序有一个透彻的了解。
或许,比起直接构造测试样例进行测试,这项工作可能并不是那么有意思。不过,它的确可以节省一大笔时间。举一个例子,Oracle Opera(一个广泛使用的酒店管理软件)[CVE-2016-5563/4/5] 的远程代码执行漏洞,可以通过阅读器用户手册快速找到可能存在危险的数据表,最后快速找出远程代码执行漏洞。

执行条件分析是指理解应用程序运行时需要包括的环境因素,比如网络配置,端口使用等。可以通过端口扫描,漏洞扫描等方式进行操作。这些配置上的问题,很可能就会导致一个漏洞的出现。
举个例子,一个系统权限级别的程序,由于配置错误,可能会使的低权限的用户能够访问并修改,最终导致一个权限提升,引发一个提权漏洞。又比如,在一个网络程序中,可能程序本身并没有错误,但是由于这个服务器开了一个 anonymous 的 FTP 服务器,那么任何人都有可能访问这个机器,这就导致 web 应用的源代码或者其他敏感文件暴露在外面。这些问题,理论上并非程序自身的漏洞,但是由于其执行环境的因素,就使得其成为一个漏洞。

通信分析是指对一个目标程序与其他进程或系统之间交互信息的方式进行深入分析。在这样的前提下,可通过发送精心构造的请求(Request)等方法,触发不安全状态。许多 web 应用程序漏洞都是通过这种方式发现的。
在上述模式下,需要我们对数据通信协议有较为清晰的认识,如果并不能够清晰的了解协议格式呢?这种情况就要借助黑盒测试的技术进行解决,主要通过发送请求,并根据返回值进行判断是否存在异常。
下面举个例子来说明,这里假设存在一个金融网站,里面有一项功能允许用户使用不同的货币购买预付信用卡。这里假设实现这项业务的请求(Request)如下:
· fromAccount : 用于购买预付卡的账户 · fromAmount : 需要从 fromAccount 转入预付卡的金额(例如 $100) · cardType : 需要购买的预付卡类型(例如美元、英镑) · currencyPair : 付款账户 fromAccount 和预付信用卡 cardType 的货币配对 , 用于计算汇率(如 CADUSD、CADGBP)
当我们要去测试这样一个应用程序时,首先我们可能会想到发送一个正常的数据请求,以帮助我们了解该应用程序的标准响应的格式。例如下图,用 CAD 去购买 82 美刀的预付卡的请求和响应是下面这个样子:

或许我们并不知道程序在后台到底对我们的数据做了何种处理,但是我们通过观察 status 字段的属性知道我们的请求是 ok 的,下面如果我们将 fromAmount 参数调整为一个负数,或者将 fromAccount 调整为其他某个人的账户,那么这个 web 应用就可能会返回错误响应,比如验证不通过。另外如果我们将 currencyPair 从 CADUSD(加元对美元)改为 CADJPY(加元对日元)而 cardType 不变,那么我们会看到返回值中 toAmount 字段从 82.20 变为 8863.68。如果程序缺乏足够的验证的话,我们有可能通过这种方式获取到更多的钱而付出的钱不变。
另一方面,如果我们能够获取到后台代码或程序,那事情就变得更加有意思,我们可以轻松了解到后台的运作流程,如后台是如何处理请求,有哪些错误响应,这将有助于我们构造出更加具有针对性的数据对应用进行测试。

代码及二进制分析是指理解一个目标程序是如何处理用户输入的数据,以及该程序的执行流程。目前有很多方法可以对程序实现动态和静态分析,下面介绍其中一部分:
在这个过程中,动态分析和静态分析需要紧密配合起来。举个例子,当你在寻找如何从 A 点走到 B 点时,静态分析就好比是在阅读一张地图,而动态分析就好比直接在这地图上走,需要实时关注路上的天气及交通状况,IDA 和 windbg 的配合就是如此。静态分析可以对程序有一个全貌但不细致的理解,动态分析则可以对程序有一个狭隘但却细致的理解,二者是相互补充的。
外部引用分析。在分析程序的过程中,程序上下文环境中可能非常有限,这个时候分析程序的导入 API 可以帮助我们进一步了解程序的功能以及它与操作系统的交互方式。比如说,程序引用加密库对数据进行加密,那么你可以跟踪这个加密库并分析其功能,进而分析自己的输入是否能够影响其功能。另外,理解程序是如何与操作系统的交互也可以帮助我们进一步找到与程序进行交互的入口点。
字符串分析,与外部引用分析一样,分析程序中的字符串将帮助我们进一步理解程序中的功能,特别是那些调试信息,关键字或者令牌什么的,或者是那些看起来特别奇特的东西,对这些关键的字符串的分析及跟踪也将有利于我们寻找到更多的程序入口,进而更加全面的找出程序中的缺陷。
安全扫描分析。使用自动化的扫描工具(如 PHP 源代码扫描 AWS)可能帮助我们快速找到一些常见的漏洞。但是对于寻找基于上下文和基于设计的漏洞并没有太大帮助。这种方法可以用来做一些辅助性的功能,如果单纯靠扫描就能找出一堆漏洞,你研究的目标安全做的就太差了,这在目前并不常见,或者说研究这类目标对于提高你自己并无太大的帮助。
依赖性分析。一个应用程序往往会依赖其他外来的组件,比如一些开源模块,它所依赖的开源模块自身存在的漏洞可能会被引入造成自身的未公开漏洞。值得一提的是,现今一个程序往往都是引用了众多第三方扩展模块,这些第三方的漏洞极易造成主程序的漏洞。举个例子,大多数浏览器都会使用 sqlite 做数据缓存,如果 sqlite 存在漏洞,那么这些浏览器都有可能存在问题,无论是谷歌还是火狐。
版本分析。如果你有机会访问程序的代码仓库,那么你就可以通过分析历史版本的方式对程序进行分析,这种方式不是基于上下文的,比如说,寻找那些长时间没有做改动的部分,这些部分极易寻在漏洞。
代码分析通常需要花费比其他方式更多的时间,同时也更难,因为研究者对这个程序的功能和使用的技术的掌握程度要不亚于其开发者,另外,一个程序的开发可能是由一个团队进行维护,那么对于研究者,全面掌握这些东西显得比较困难。但是只要肯专研,其实什么也都是能够克服的,请参考名言:只要工夫深,铁杵磨成针。
另外,不得不再次强调一下编程能力的重要性,如果一个研究人员对他当前研究的程序所采用的语言和技术有深入扎实的功底,那么他必将创造出很多有价值的东西。从攻击的角度来说,他可以发现更加简单及直观的漏洞,编写利用程序也将得心应手。从防御的角度来说,他可以提供出代码级别的、具有高度针对性的修复建议而非那种通用的方法。
漏洞的复杂性分布非常广。一方面,有很多漏洞非常简单与直观,并且利用代码一目了然,比如说经典的 sql 注入。另一方面,在系统中有的看似并不相关,并且就其自身而言并非不安全,但是当这些东西以一种特定的方式结合起来的时候,就有可能引发大的漏洞,比如说条件竞争,或者一些其他的复杂的逻辑漏洞。可以尝试将这些漏洞按照复杂级别分为'一级漏洞'和'二级漏洞',不过也有其他分类方法。引用一局来自 Project Zero 的 Ben Hawkes 说过的一句话:
The modern exploit is not a single shot vulnerability anymore. They tend to be a chain of vulnerabilities that add up to a full-system compromise.
如今想要完成一个完整的利用,只靠单一的漏洞往往行不通。很多时候我们需要靠一连串的漏洞才能完成一起完整的利用,致使系统'妥协'。
在一个团队中工作能够有效帮助自己了解自己不知道的知识,以及提高自己已知的知识。不过在团队中要需要注意工作的方式方法,知之为知之,不知为不知,永远不要强行假装精通你不熟悉的东西,因为精通的人可以很轻易的指出你的症结。如果一个团队里面大家都不坦诚相待,那么这不是一个合格的团队,你可以尽早更换。在优秀的团队中,不要指望别人会把所有的知识交给你,要学会如何高效的学习,并在团队交流与合作中不断提高。
希望这篇文章可以帮助你解开一些对于漏洞挖掘的谜团。在学习和研究漏洞挖掘的过程中遇到困难并感到不知所措是很正常的。不过学习的过程就是这样,只有不断的去尝试才会进步。祝你在漏洞挖掘的路上走的越来越远。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online