查看原文
其他

漏洞分析那些事儿

计算机与网络安全 计算机与网络安全 2022-06-01

一次性进群,长期免费索取教程,没有付费教程。

教程列表见微信公众号底部菜单

进微信群回复公众号:微信群;QQ群:460500587



微信公众号:计算机与网络安全

ID:Computer-network

当打开一个文档或用浏览器打开一个网址时,也许您会很快被文档或网页中的丰富的内容所吸引,但您却不会知道,这可能有一个木马已经悄悄地在计算机里留下了后门,您的游戏账号、隐私信息等正在被屏幕另一端的黑客拿走。不可能存在绝对安全的软件,本文将带大家走入漏洞的世界,看看一个小小的逻辑错误究竟会造成怎样的严重后果。


一、什么是软件漏洞分析


Web端有Web端的漏洞,系统有系统的漏洞,应用软件有应用软件的漏洞,而它们绝大多数都是由于简单的逻辑错误导致的,所以从另一个角度讲,黑客和程序员也有着千丝万缕的联系。有时候当一个程序员费了几个月的时间写了几十万行代码,但是黑客一个小小的操作可能就要让这个程序重写一遍。


其实漏洞的分析就是在逆向进行漏洞发生的过程,假如说这个程序因为执行了某些函数和某些畸形字符串崩溃了,如果崩溃的这一刻叫作案发现场的话,我们就要回溯到程序崩溃前,分析原因并找出Bug所在。


在此之前,需要弄懂一些概念,首先是栈的概念,这对于漏洞分析至关重要。其实无论是漏洞,还是逆向这样的反汇编操作,或是正向的编程,我们都需要了解它们,因为PC端和移动端都一样,都有堆栈操作。


栈其实可以看作一块空间,当调用一个函数参数的时候,这个参数就会进到这个栈里,这个空间就好像一个死胡同,先进来的就在最里面,后面依次排列,所以栈对于参数的操作是先进后出,后进先出。


其实一个程序的操作就是不断地在对栈操作,当调用一个函数的时候,就会开辟一块栈空间,然后把这个函数要用的参数全部放到栈里,经过一系列操作之后,会将这些参数释放出来,返回某些结果给外层的调用函数,最后再释放这块空间,而大多数的漏洞都是发生在这里。


所谓缓冲区溢出,可以分为栈溢出和堆溢出,说白了就是在进行这些函数操作的时候,可能由于一个if语句或者一个strcpy函数导致栈或者堆被破坏,导致程序无法正常执行它该执行的内容,这就造成了崩溃,也就造成了漏洞的产生。


二、漏洞分析的作用


有很多人觉得漏洞分析没什么用,不如那些Web端漏洞危险,其实软件漏洞造成的危害是极大的,例如2008年一个震惊世界的超级漏洞MS08-067,将整个Windows XP系统以及Windows Server 2003系统推到了风口浪尖。很难想象,当输入对方的一个IP地址,就能够控制对方的计算机,时至今日,MS08-067依然被应用在黑客的攻防当中,而这个漏洞诞生的原因正是对于“/”字符的向前检索。2014年仍然是漏洞集体爆发的一年,年初的“心脏出血”、年中的shellshock破壳、年底的IE“神洞”CVE2014-6332都是危害等级极高的神级漏洞


通过漏洞分析,我们不仅能看到整个漏洞爆发的过程,还能找到利用它的方式,这里白帽子会积极联系厂商及时修复,而黑客会继续开发Exploit,利用漏洞来发起一个又一个的攻击。


无论是出于对用户的保护,还是出于私人的目的,漏洞分析都是必不可少的过程。这里要特别提及一下POC这个概念,POC是漏洞验证的程序,用来验证在你配置的漏洞分析环境下,是否能够成功触发漏洞,而POC里不包含恶意代码,就好像网上的绿色软件一样。shellcode是传说中的恶意代码,也就是在利用漏洞的时候,通过触发软件漏洞使程序去执行shellcode,从而远程完成在目标计算机上的操作。


在完成一次完整的漏洞分析和利用之前,还需要了解使用哪些工具可以完成这个过程。其实网上对于漏洞分析、利用的工具很多,包括很多大牛也做出过用来fuzz的工具,以及很多能挂载在OD、IDA上的插件。当然,对于漏洞分析还需要重点了解三个“神器”,这三个神器可以说是漏洞分析的主体,如果对这三个工具了如指掌的话,对于现如今99%的软件漏洞都能拨开其面纱,了解其本质。


在为大家分享漏洞分析过程之前,在此对这三种工具做简单说明,当我们了解了这三种工具的使用及分析方法之后,就是万事俱备,只欠东风了!


以下内容适合对IDA Pro、WinDbg以及OllyDbg不了解的初学者学习,对这三种工具了解或者精通的朋友可以略过以下内容。


1、IDA Pro


IDA Pro是静态反汇编的神器,无论在Windows还是Linux系统下都有不凡的表现。随着IDA Pro的更新,它现在也开始支持动态调试,其强大的反汇编能力不仅能将PE文件的文件格式分析得一清二楚,而且可以将选择的代码段反汇编成伪代码的形式,大大缩短了分析枯燥的汇编代码的时间。它不仅能够在Windows下完成文件的分析,同时在令人烦恼的Linux系统下仍旧可以完成文件的分析。Linux下常见的反汇编方式就是使用GDB,但是GDB也是在命令行下使用,而且绝大部分溢出需要-core的支持,其烦琐程度令人恼火,但是IDA Pro的Remote Linux Debugger功能非常强大,可以支持远程调试Linux下的软件,这将大大减少烦琐的命令行操作,令Linux下的软件,进程调试变得和Windows下一样简单。


下面将针对IDA Pro进行一些入门级的介绍,描述在进行漏洞分析过程中需要的一些主要功能,其实IDA Pro本身的功能非常强大,其余的功能需要大家慢慢学习。


IDA Pro的主界面如图1所示,界面上方是菜单栏,其中包含了IDA的所有工具,左侧是函数栏,右侧是主窗口,下方是输出栏。左侧的函数栏在没有导入Windows的符号表的时候,会将函数以“sub_数字”的形式表现,其实它代表着一些函数的定义,比如printf、strcpy等,当符号表导入之后,这里就会显示出真正的函数值了。

图1  IDA Pro主界面

界面右侧是反汇编的主窗口,在IDA View-A菜单中会包含反汇编的结果,其中.text代表着PE文件中的字段,后面的8个字节是汇编语言所在的内存地址。


当选中某段汇编语言后,按F5键会将该段汇编语言反编译成伪代码的形式,这样使逆向调试变得更为简单,更容易分析出漏洞的形成原因,如图2所示。

图2  IDA Pro反编译伪代码窗口

在对PE文件进行加载并用IDA Pro完成分析之后,它会将该程序的代码结构以流程图的形式展现出来,如图3所示。这不仅方便我们观察每个模块之间的关联与跳转等关系,同时再对补丁进行比较分析,从而快速定位漏洞位置时也起到了很大作用。

图3  IDA pro反汇编流程图窗口

Hex View-A是将程序以十六进制形式表现,和UltraEdit的功能类似,在这里可以快速搜索定位关键的汇编代码段,比如通过查找FF E4就能快速定位到Jmp esp上等,如图4所示。

图4  IDA Pro内存显示窗口

远程调试Linux的功能,可以执行Debugger→Run→Remote Linux debugger命令完成,同时IDA还支持不同的远程调试,如图5所示。

图5  IDA Pro菜单栏及远程调试选项

在理解和掌握之后,IDA Pro的主要功能我们就能很好地结合动态调试工具对漏洞进行分析。


2、WinDbg


WinDbg是微软调试器集合的一个GUI界面,它可以针对用户态和内核态进行调试,它精简却很彪悍,虽然界面不如OllyDbg友好,但是其调试功能强大得令人震惊,尤其是对页堆的跟踪,对于现在很多的堆溢出漏洞来说是一个很简便的过程,很容易就能观察到指定内存区域的堆变化情况。

下面简要介绍WinDbg界面及常用的调试命令,WinDbg的调试命令非常丰富,在不同的漏洞环境下需要调用不同的命令,这里为方便大家入门只介绍比较通用的命令,不常用的命令需要大家在对漏洞进行多层次了解分析之后再进行研究。


WinDbg的主界面(如图6所示),在我们通过File进行对PE文件的打开或对进程的附加之后,仅仅只打开了CMD窗口,其他的窗口需要通过在View里选择打开,图6中展示的是几个常用的窗口,其实也是OllyDbg主界面中展示给用户的窗口,其中左上窗口是寄存器窗口,左下窗口是展示内存区域的窗口,中间窗口是动态调试及命令输入的窗口,右侧是反汇编跟踪窗口。

图6  WinDbg主界面

对于每个窗口的跟踪使用,这里不做说明,感兴趣的朋友可以在OllyDbg工具的API文档中根据介绍详细了解,或者可以查阅相关的资料,这里主要讲解常用的调试命令。


在CMD窗口中,下方就是输入命令的地方,在菜单栏的Debug区域可以看到通过按F11、F10、F5键或直接单击可以对程序目前中断的地方进行步过、步进及执行等操作,这与VS或者VC6.0的调试方式是异曲同工的,当然这里也可以通过在下方命令栏输入t(步过)、p(步进)和g(执行)的方式进行调试(见图7)。

图7  Windbg命令行

下面介绍调试过程中几个主要的命令。


kb——查看堆栈调用,通过输入kb可以查看进入函数前都调用了哪些函数,从而快速回溯还原漏洞触发前的场景,有助于快速定位漏洞触发的位置,如图8所示。

图8  Windbg kb命令

bp,ba——下断点,其中bp可以对指定地址下断点;ba可以对函数写入断点,执行断点。写入断点是指如果在指定内存区域有新的数据写入时,则触发断点,执行断点是指当该内存区域的内容被执行时则触发断点,同时bc可以用来删除断点。也可以通过bp FFFFFFFF ".if(poi(@eax)==).else{g;}"的方式来下条件断点,该条件断点是指在FFFFFFFF地址处如果eax等于某值时暂停,否则继续。


dd esp——查看某寄存器内容,实例使用的是esp寄存器,这里可以改eax、ebx等,这里方便对寄存器的跟踪,可以很好地分析在漏洞触发时寄存器的变化状况等,如图9所示。

图9  Windbg dd命令

!heap-p-a——打开页堆异常检测,其主要功能是在堆空间,如果此时页堆发生异常则显示,这是对很多堆溢出漏洞调试非常实用的工具。


以上命令是在漏洞分析时常用的命令,通过对这些命令的理解,可以很好地看到寄存器的变化,定位汇编代码,再通过对汇编代码的回溯分析,找到漏洞的触发点以及形成原因。


3、OllyDbg


OllyDbg是对于刚入门者最推荐的动态调试工具,它的界面相比WinDbg来说非常友好,而且对于堆栈状态的展示非常清晰。如果说OllyDbg是一个界面的话,WinDbg就像命令行一样,同时OllyDbg同样支持二次开发,有很多人将自己的插件放在OllyDbg里辅助反汇编,往往可以事半功倍。同时OllyDbg本身也自带一些非常好用的插件,比如Disable DEP,这对于构造ROP链绕过DEP来说会起到很大作用,它能迅速帮助使用者定位到构造ROP链所需的地址位置。请大家自己动手操作,下载OD工具并打开。可以看到在界面的左上角是反汇编的主窗口,右上角是寄存器窗口,左下角是内存窗口,右下角是堆栈调用窗口。相比WinDbg,OllyDbg的界面操作起来更直观,可以通过调试界面,选择对程序单步调试或者直接执行等操作,通过右侧可以直接观察到寄存器的变化情况,如果标红,表示在这一汇编代码结束后会影响到该寄存器存放的值,这更加有利于对漏洞的回溯工作。


在菜单栏中可以看到L、E、M、W等按钮,这些按钮代表OllyDbg的其他几个窗口,通过其他几个窗口中的内容可以辅助我们进行反汇编调试。


其中K窗口表示堆栈调用的查看,功能与WinDbg里的K相同,可以查看该汇编代码前的函数调用情况,帮助我们回溯汇编代码执行的流程(见图10)。

图10  OllyDbg堆栈调用窗口

E窗口表示可执行模块,其中可查看该程序执行时调用的模块名称、地址等,这在构造ROP链、ASLR绕过方式等方面都会起很大的作用(见图11)。

图11  OllyDbg可执行模块窗口

M窗口是内存映射的情况,这里可以看到每个模块的地址、访问权限等,比如通过E窗口找到想要构造ROP链调用地址的模块,通过分析它的读取权限来决定是否使用该模块中的地址,或布置shellcode位置的选择等(见图12)。

图12  OllyDbg内存窗口

OllyDbg之所以作为入门级调试工具,就在于其简单易懂的界面,可以通过堆窗口、栈窗口以及寄存器窗口很直观地观察到程序执行及漏洞触发过程中堆栈空间的内存变化情况,甚至可以观察到当漏洞触发时构造的畸形字符串覆盖栈空间及导致恶意代码执行的整个过程,相比OllyDbg、WinDbg就需要更多的命令来查看这一过程。


对于OllyDbg的掌握有助于初学者对于漏洞分析的快速入门,OllyDbg同样提供了很多的插件,这里就不一一讲解了。


三、strcpy引发的“血案”


首先编写了一个有漏洞的程序,程序中关键点在于strcpy函数,这也是目前很多栈溢出漏洞的根本原因,大多数都是因为对于数组边界检查不够严格造成的(见图13)。

图13  超长字符串定义

可以看到给overflow_a赋值为一个超长字符串,这就是触发漏洞的超长字符串,这也方便后期在构造利用shellcode时候修改。


图14所示是一段触发漏洞的关键代码,strcmp并不是关键,只是之前做密码绕过的实验时使用的,这个漏洞的关键点是下面的strcpy,可以看到上面构造的数组大小为8,而定义的overflow_a数组大小为a元素的个数,那么当以超长串拷贝到b数组中的时候,会造成多出来的a元素覆盖到栈中b数组下面的内容,造成栈被破坏,从而产生溢出。

图14  漏洞触发关键代码

挂载WinDbg,执行如下程序。


可以看到程序崩溃了,WinDbg弹了出来,而目前指向的地址是61616161,也就是a的ASCII码(十六进制情况下),这是一片无效的内存空间,直白地说程序无法读取这段内存空间中的汇编语言继续执行程序,导致了程序崩溃,如图15所示。

图15  程序崩溃现场

如果要利用的话,会将特定的shellcode覆盖在特定的空间使程序执行,这在Windows XP系统下是成立的,但是目前大多数系统都会开启DEP、ASLR这些内存执行保护、地址随机化等保护措施,当然现在的黑帽子们也提供了各种绕过方法,比如构造ROP链、利用虚表指针等方式。


下面来看看栈中的情况,如图16所示。

图16  程序崩溃时栈中情况

通过图16和图15可以看到EBP,也就是栈底已被修改成61616161,而假设当初为栈开辟的是30h的大小,那么此时的大小是ebp-esp(栈底-栈顶)也就是61616161-0012fec8,换句话说已经破坏了栈平衡,这个栈也被破坏了。


下面,将以正向调试的角度来为大家还原整个漏洞触发的过程,这在真正的漏洞调试中也是分析漏洞形成原因以及利用方法的最后一步,这里为大家跳过的是之前逆向回溯的整个过程,而这个只有数十行汇编代码的程序也将略去利用“!heap–p–a”开启页堆等繁复的过程。


首先改用OllyDbg工具,执行程序并且在程序main函数的入口点断住(见图17),假设这就是一个复杂的漏洞程序还原到触发点之前的两个函数。

图17  程序反汇编定位

略去main函数入口处对于栈的一系列操作,在最顶上的函数可以看到将偏移尾00422038处保存的ASCII码存入ESI,其实当使用OllyDbg时可以在栈内看到将这一串a推入栈中的过程,而黄色标记的一行中的call正是漏洞触发的关键函数,相当于触发漏洞的最后一层函数,那么在这个函数下断点跟进看一看(见图18)。

图18  程序反汇编定位

可以看到,strcpy函数此时push了ecx及edx,ecx赋值是ebp+8,也就是该函数的第一个参数,就是上面传入的aaaaaaaaaaaaaaa,那么下面edx就应该是我们的b8数组了,这样可以直接让程序执行多次后,发现strcpy函数内部的内容,其实就是将超长字符串以4个字节(即4个a为一段)为一个单位复制到寄存器,那么在栈溢出发生的最后一个调用,可以看到此时ebp的值是0012FEC0,而当以超长串复制到寄存器后,可以看到ebp的值被修改成了61616161,这也就造成了栈溢出(见图19),这里只要精确地修改返回地址的值就能实现对于程序的控制,从而执行想执行的内容,修改overflow数组的内容如图20所示。

图19  程序溢出栈中情况

图20  构造畸形字符串

程序执行后断在cc int 3处,可见在经过7ffa4512跳转之后,程序来到了7ffa4512后面的内容,稍后可以跟一遍程序的流程看看为何会断在那个位置。


这里cc只是为了强行让程序断下,以验证返回地址确实被改成了7ffa4512,这样程序才会执行jmp esp跳转到cc,将cc改成calc的shellcode就可以弹出计算器了(见图21)。

图21  溢出后弹出计算器表示漏洞存在

弹出计算器,证明了漏洞的存在。当然,怀着不良心思的黑客就不会简单地弹出计算器了。

四、分析利用漏洞的一些基本技巧


漏洞分析其实就是逆向的过程,唯一不一样的就是不需要对这个程序整个执行流程有很深刻地了解,只需要知道漏洞是如何发生的,如何构造畸形数据再现漏洞场景,最后能够利用就行了。这里要强调一下,白帽子一般只负责到能够重现漏洞场景,分析漏洞的危害,提出解决方案,以及给厂商提供exploit就行了。而黑客会以此构造真正的exploit,捆绑木马或者病毒,用盲打或者钓鱼实施攻击。


这个PDF漏洞是2013年的漏洞,在虚拟机里搭建了一个XP SP3的环境,安装Adobe Reader 11.0,成功触发POC(漏洞样本,一般是无害的),通过Windbg挂载导致程序崩溃,使Windbg跳出来(见图22)。

图22  PDF漏洞触发现场

这就是案发的时候,可以看到目前内存位置在88888888,其实这时候栈已经被破坏了,eip跳转到一个没有东西的内存空间,所以程序崩溃了。现在就开始逆向还原整个过程,通过命令来回溯整个过程。


如图23所示,由下往上是依次调用关系,就是C语言的函数嵌套,比如说A调用B,B调用了C,那么“案发”前的那一刻函数对应的地址是208a54e0,用WinDbg查看该段函数的汇编代码,如图24所示。

图23  PDF漏洞触发时堆栈调用情况

图24  PDF漏洞触发前汇编代码分析

画线的部分是认为最重要的部分,为了方便大家理解,用一个流程图来简化上面的过程,如图25所示。

图25  PDF漏洞触发流程

由图25可以看到漏洞触发的原因就在于AcroForm!PlugInMain+0xa31f1返回的eax,经过多次赋值后,eax被改变了。因为这个改变,导致最后call eax的时候使程序跳转到了88888888,此时栈已经被破坏了。用IDA Pro来加载这个存在漏洞的AcroForm.api,查看这段函数的伪代码(见图26)。

图26  PDF漏洞触发时伪代码

其实通过上面的汇编语句也不难看出eax作为这个函数第一个参数被传入,经过这个函数的执行,第一个参数又被返回,然后继续上面的流程,这个参数被传入后又进行了sub_208A553F这个函数的一系列操作。由于没有下载符号表,所以无法告诉大家函数的名字,这个函数里面的代码有100行左右,具体分析过程就不赘述了,其大致功能其实就是创建一个新的对象指针,并且分配给这个指针64 Byte的内存,如图27所示。

图27  pdf漏洞触发指针空间分配异常点伪代码

我们可以用IDA Pro看到分配空间的过程,其实这里用汇编看可能更清晰(见图28)。

图28  PDF漏洞触发指针分配异常点汇编代码

push 40h就是将分配内存空间的大小作为参数传入,40h转换成十进制就是64,而下面call的函数其实就相当于C语言中的malloc,只不过malloc是动态分配空间。再回到之前的流程图中,问题就来了,eax+4作为这个指针的起始被传出赋值给了esi,然后esi+44h赋值给了ecx,而其实这个指针的大小只有40h,这就造成了内存地址越界,导致了漏洞的触发,那么只要想方设法构造这个越界位置中的值就可以完成对这个漏洞的利用。


利用漏洞部分只做简要的说明,因为会涉及ROP链的构造,而且这个漏洞的利用其实也伴随着另一个内存泄露基址的漏洞,以此来绕过DEP和ASLR保护。其实该漏洞本身就已具备了绕过ASLR的功能,但是由于构造畸形数据的特殊性,如果单用这个漏洞只能覆盖少量的shellcode,而利用这个漏洞会用到IE常用的heap spray,也就是对喷技术,来看看它的内存空间变成了什么(见图29)。

图29  PDF堆喷后内存空间情况

这段喷射代码在POC中也有体现,我们用Ultra Edit打开POC。

这里给大家展示了部分堆喷的代码,相信对Web略有研究的朋友可能会很熟悉,这是用JavaScript完成的,IE浏览器多数情况下也是利用堆喷技术来绕过ASLR,其中填充大量内存块喷射0c0c的过程也是用JavaScript完成的。


至此,简单的漏洞分析就完成了,其实这中间包含了成百上千次的反复调试,对各个寄存器的值都要有清醒的认识,而且这个漏洞还有很多很多细节没有跟大家说明,比如指针对象的格式,esi+44h布置了什么东西,感兴趣的朋友可以去网上搜索一下。

微信公众号:计算机与网络安全

ID:Computer-network

【推荐书籍】

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存