初学者最好不要上手就去搞漏洞挖掘,因为漏洞挖掘需要很多的系统基础知识和一些理论知识做铺垫,而且难度较大……
较合理的途径应该从漏洞利用入手,不妨分析一些公开的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应用程序和桌面应用程序的漏洞时所需要掌握的内容。每个类别中的条目仅用于说明目的,并非详尽无遗。
这些知识领域将会帮助你提高挖掘漏洞的能力。如果说上面一节是讲诉挖掘漏洞所需要的知识,那么下面的这一节将讲诉挖漏洞如何做
三. 漏洞挖掘需要做什么
当分析一个应用程序时,你可以使用下图展示的四个“分析模型”,如果遇到障碍导致思路受阻时,你可以从其中一个模型切换到下一个模型,当然,这不是一个线性的切换,你也可以有自己的一套方法。
程序用途分析是指理解一个应用程序做了什么工作,会提供什么服务等。同时,阅读与该程序的相关文档将有助于进一步理解程序功能(如上图所示)。这样做有利于对程序有一个透彻的了解。
或许,比起直接构造测试样例进行测试,这项工作可能并不是那么有意思。不过,它的确可以节省一大笔时间。举一个例子, Oracle Opera(一个广泛使用的酒店管理软件)[CVE-2016-5563/4/5]的远程代码执行漏洞,可以通过阅读器用户手册快速找到可能存在危险的数据表,最后快速找出远程代码执行漏洞
代码及二进制分析是指理解一个目标程序是如何处理用户输入的数据,以及该程序的执行流程。目前有很多方法可以对程序实现动态和静态分析,下面介绍其中一部分:
数据流分析。数据流分析对于寻找入口点以及数据是如何走向潜在的不安全状态是非常有用的。在通信分析(Communications analysis)遇到困难时,很难构造出合适的Request,这时可以调整思路采取其他的方式寻找不安全状态,在数据流分析中,可以首先判断是否存在不安全状态,如果存在,则进一步跟踪数据是如何流向该状态。这个方法的好处是,一旦发现不安全状态,入口点也随之确定,这将会为发掘漏洞提供巨大帮助。
在这个过程中,动态分析和静态分析需要紧密配合起来。举个例子,当你在寻找如何从A点走到B点时,静态分析就好比是在阅读一张地图,而动态分析就好比直接在这地图上走,需要实时关注路上的天气及交通状况,IDA和windbg的配合就是如此。静态分析可以对程序有一个全貌但不细致的理解,动态分析则可以对程序有一个狭隘但却细致的理解,二者是相互补充的。
外部引用分析。在分析程序的过程中,程序上下文环境中可能非常有限,这个时候分析程序的导入API可以帮助我们进一步了解程序的功能以及它与操作系统的交互方式。比如说,程序引用加密库对数据进行加密,那么你可以跟踪这个加密库并分析其功能,进而分析自己的输入是否能够影响其功能。另外,理解程序是如何与操作系统的交互也可以帮助我们进一步找到与程序进行交互的入口点。
字符串分析,与外部引用分析一样,分析程序中的字符串将帮助我们进一步理解程序中的功能,特别是那些调试信息,关键字或者令牌什么的,或者是那些看起来特别奇特的东西,对这些关键的字符串的分析及跟踪也将有利于我们寻找到更多的程序入口,进而更加全面的找出程序中的缺陷。
安全扫描分析。使用自动化的扫描工具(如PHP源代码扫描AWS)可能帮助我们快速找到一些常见的漏洞。但是对于寻找基于上下文和基于设计的漏洞并没有太大帮助。这种方法可以用来做一些辅助性的功能,如果单纯靠扫描就能找出一堆漏洞,你研究的目标安全做的就太差了,这在目前并不常见,或者说研究这类目标对于提高你自己并无太大的帮助。
依赖性分析。一个应用程序往往会依赖其他外来的组件,比如一些开源模块,它所依赖的开源模块自身存在的漏洞可能会被引入造成自身的未公开漏洞。值得一提的是,现今一个程序往往都是引用了众多第三方扩展模块,这些第三方的漏洞极易造成主程序的漏洞。举个例子,大多数浏览器都会使用sqlite做数据缓存,如果sqlite存在漏洞,那么这些浏览器都有可能存在问题,无论是谷歌还是火狐。
版本分析。如果你有机会访问程序的代码仓库,那么你就可以通过分析历史版本的方式对程序进行分析,这种方式不是基于上下文的,比如说,寻找那些长时间没有做改动的部分,这些部分极易寻在漏洞。
代码分析通常需要花费比其他方式更多的时间,同时也更难,因为研究者对这个程序的功能和使用的技术的掌握程度要不亚于其开发者,另外,一个程序的开发可能是由一个团队进行维护,那么对于研究者,全面掌握这些东西显得比较困难。但是只要肯专研,其实什么也都是能够克服的,请参考名言:只要工夫深,铁杵磨成针。
另外,不得不再次强调一下编程能力的重要性,如果一个研究人员对他当前研究的程序所采用的语言和技术有深入扎实的功底,那么他必将创造出很多有价值的东西。从攻击的角度来说,他可以发现更加简单及直观的漏洞,编写利用程序也将得心应手。从防御的角度来说,他可以提供出代码级别的、具有高度针对性的修复建议而非那种通用的方法。
四. 有关漏洞挖掘的其他想法
(一) 漏洞的复杂性
漏洞的复杂性分布非常广。一方面,有很多漏洞非常简单与直观,并且利用代码一目了然,比如说经典的sql注入。另一方面,在系统中有的看似并不相关,并且就其自身而言并非不安全,但是当这些东西以一种特定的方式结合起来的时候,就有可能引发大的漏洞,比如说条件竞争,或者一些其他的复杂的逻辑漏洞。可以尝试将这些漏洞按照复杂级别分为“一级漏洞”和“二级漏洞”,不过也有其他分类方法。引用一局来自Project Zero的Ben Hawkes说过的一句话:
Themodern exploit is not a single shot vulnerability anymore. They tend to be achain of vulnerabilities that add up to a full-system compromise.
如今想要完成一个完整的利用,只靠单一的漏洞往往行不通。很多时候我们需要靠一连串的漏洞才能完成一起完整的利用,致使系统“妥协”。
(二) 团队工作
在一个团队中工作能够有效帮助自己了解自己不知道的知识,以及提高自己已知的知识。不过在团队中要需要注意工作的方式方法,知之为知之,不知为不知,永远不要强行假装精通你不熟悉的东西,因为精通的人可以很轻易的指出你的症结。如果一个团队里面大家都不坦诚相待,那么这不是一个合格的团队,你可以尽早更换。在优秀的团队中,不要指望别人会把所有的知识交给你,要学会如何高效的学习,并在团队交流与合作中不断提高。
最后
从时代发展的角度看,网络安全的知识是学不完的,而且以后要学的会更多,同学们要摆正心态,既然选择入门网络安全,就不能仅仅只是入门程度而已,能力越强机会才越多。
因为入门学习阶段知识点比较杂,所以我讲得比较笼统,大家如果有不懂的地方可以找我咨询,我保证知无不言言无不尽,需要相关资料也可以找我要,我的网盘里一大堆资料都在吃灰呢。