从二进制漏洞分析入门到辅助分析脚本诞生

阅读量195572

|

发布时间 : 2016-08-15 18:00:02


作者:k0shl


(一)写在前面

从接触二进制漏洞以来一直在边学边思考,有没有一些共通的地方,可以通过一些简单的脚本或者工具来简化一些过程,不得不承认二进制漏洞无论在挖 掘,分析,还是最后写exp上都是有一定难度的,经过不断的请教,拜读大牛们的作品,也逐渐摸到了一些门道,下面的分享如有不当之处请多多指教, 大牛轻喷:)

感谢蛙师傅给予的灵感!

相应的脚本也已经开源放在我的github下,欢迎大家多提意见,也可以进行修改,后续我也会根据我逐步学习逐步改进增强工具的功能。这里之所以说是 辅助分析工具,是因为我还想不到一种方法能够完全自动化分析漏洞的成因,只能说简化一些漏洞分析过程中的过程。

在二进制漏洞的入门学习中,我个人感觉相比漏洞挖掘,构造PoC,编写Exp,只有漏洞分析是最核心也是最容易入手的,通过已有的PoC,搭建复现漏 洞的环境,获得存在漏洞的软件,复现漏洞后就可以进行分析了,而我写的这个脚本,也是为了简化一些漏洞分析过程,从而更清晰直观的看到漏洞执行 流程。


(二)为什么要写辅助分析脚本

说到二进制漏洞分析,在windows下,入门阶段最好用的两款工具就是windbg和IDA pro对于这两款工具,网上相关的介绍有很多,这里我就不再多做赘 述,在我进行漏洞分析的过程中,经常用的方法就是windbg的动态调试,配合上IDA pro的静态分析,其中windbg提供了很强大的动态调试功能,包括堆 栈的回溯,跟踪,加载符号表中特定的变量,结构体等等;而ida pro则提供了静态分析的功能,比如指令流流程,伪代码还原等等。

一般当我们第一次开始学习漏洞分析的时候,拿到一个崩溃场景,往往会碰到这样的崩溃场景。

造成软件或者系统崩溃的原因有很多,比如某些关键地址,关键指针被覆盖,导致引用时发生错误,比如空指针引用,比如越界操作内存等等,而二进制

漏洞分析就是要分析为什么会造成崩溃的发生,这样无论对于修补漏洞,还是编写利用工具,都有极大的帮助。

在漏洞分析过程中,避免不了这样一个过程—-回溯。刚才提到,漏洞分析就是要分析为什么会造成崩溃的发生,那么就少不了对程序执行流程的回 溯,通常在windbg中,我们使用“kb”命令回溯堆栈调用的情况。

http://p3.qhimg.com/t01f8275a6f44dc4905.png

通过kb命令,我们可以看到在程序执行到崩溃场景前调用的函数内容,而这个调用往往是嵌套调用,就是栈增长方向是外层函数,因为熟悉堆栈的小伙伴 应该知道,栈的开辟是由高地址向低地址开辟,堆是由低地址向高地址开辟,也就是每次调用内层函数的时候,栈就会向低地址方向开辟一片空间使用, 我们可以这样简单理解函数调用关系。

http://p2.qhimg.com/t0193b103ea66a8adba.png

我们需要在ida中动态跟踪这个调试过程,追踪从接收到PoC中的畸形数据,到触发漏洞的整个过程,才能较为完整的完成对漏洞的分析,那么实际上在 一个函数内部,涉及到大量的条件判断,跳转等功能,在ida的指令流程图中可以看出这个过程在静态分析中,会耗去很多时间。

http://p8.qhimg.com/t01a0e2c3a58dde59f1.png

那么实际上,我写的这个辅助分析脚本,其实也是为了针对这种情况而诞生的。


(三)从PcMan FTP漏洞看辅助分析脚本

这里我以PcMan FTP这个漏洞为例,先结合漏洞的分析过程,再讲解辅助分析脚本的编写及功能,首先这个漏洞是由于PcMan FTP在对用户传输的数据 进行处理的过程中,没有对传输的内容进行长度控制和内容检查,从而导致可以通过ftp指令+畸形字符串来覆盖返回地址,最后导致远程代码执行,在发 送PoC之后,这边用windbg对进程进行附加,可以捕获到崩溃场景。


http://p5.qhimg.com/t01e777888811b20f6c.png


通过回溯,我们找到了一处call recv的调用,这个调用会获取畸形的payload。

http://p8.qhimg.com/t01fa7857db1e79dc05.png

在004029d5位置接收到recv之后,观察一下此时接收到的数据。

http://p8.qhimg.com/t0175ef1746c54773ce.png

已经是畸形字符串了,接下来进行连续跟踪。我们跟踪到一处函数sub_403E60,这处函数中会执行一处sprintf操作,正是这个过程会将payload拷贝到缓 冲区,而没有进行长度控制的情况下,会造成缓冲区溢出。

http://p0.qhimg.com/t013669879688ed16af.png

最后执行到返回后会因为返回地址被覆盖导致任意代码执行。

http://p1.qhimg.com/t01c98828e6716b990c.png

在对这个过程进行动态调试跟踪的过程中,涉及到很多函数的嵌套调用,以及很多的跳转,这无论在windbg还是ida pro中通过地址比对来动静结合是很 耗时间的,因为要经过很多的地址比对,甚至有时在面对ASLR的情况下还需要进行地址换算,于是就有了这个辅助分析脚本。

(三)idahelp.script和winidc.idc

在windbg下,支持使用脚本,同样在ida pro下,也支持使用.idc的脚本,首先我来讲解一下windbg下的脚本,以及编写,首先来看一下idahelp.script。

http://p4.qhimg.com/t0186f253fe2d298f31.png

在windbg中,涉及到寄存器操作的都需要加上r,而涉及到一些if,else,while命令的,则需要加上一个“.”,windbg有很多种调用脚本的方法,这里介绍 两种常用的调用方法。

http://p3.qhimg.com/t01ec13658ef676508b.png

第一种调用的是不带参数的,第二种则是调用带参数的,在我的脚本里,需要两个参数,在脚本开头已经传入t1,t2模拟寄存器里。

这两个参数分别对应脚本执行的起始地址和结束地址,在上述的分析过程中,我们提到在回溯调用的过程中,需要由外层函数向内层函数不断动态跟踪, 这就需要我们利用脚本对想跟踪的地址区间进行设定,然后脚本会不断跟踪,同时通过logopen命令来将整个跟踪时的路径保存至一个文件里,方便之后 我们在使用ida pro脚本进行标记。


http://p2.qhimg.com/t01d38e62e1d5ad1c10.png


执行脚本之后,程序会按照流程动态执行,并且将整个执行的过程记录在txt中。


http://p9.qhimg.com/t013c2ca54b110be1a2.jpg


这样,就完成了对这个指令区间的跟踪,接下来我们来看一下winidc.idc。

比起windbg的脚本,ida pro提供了一套自己的功能,在代码编写方面和C很像,需要通过#include方法,把idc提供的api库导入,这样才能使用ida可识 别的脚本函数,来完成我们的功能。来看一下winidc.idc的代码。

#include <idc.idc>extern ida_image_base_addr,windbg_image_base_addr,offset;
//主函数static main(void)
{
auto i,temp;auto FileName,FileLength,hFile,str,Target="66666666";
auto Fileline;
//
//获取输 Windbg和IDA中模块的基址//
temp=AskStr("00401000","Please input Windbg's imageBase,For example:");
windbg_image_base_addr=xtol(temp);temp=AskStr("00401000","Please input IDA's imageBase,For example:");
ida_image_base_addr=xtol(temp);
FileName=AskFile(0,"*.*","Please choose Windbg Instruction stream file");
hFile=fopen(FileName,"r+");FileLength=filelength(hFile)-30-34;Fileline = FileLength/17;
fseek(hFile,37,1);
Target[0]=fgetc(hFile);
Target[1]=fgetc(hFile);
Target[2]=fgetc(hFile);
Target[3]=fgetc(hFile);
Target[4]=fgetc(hFile);
Target[5]=fgetc(hFile);
Target[6]=fgetc(hFile);
Target[7]=fgetc(hFile);
temp=xtol(Target);
temp = temp-windbg_image_base_addr+ida_image_base_addr;
SetColor(temp,1,0x98fb98);
for(i=1;i<Fileline;i++)
{fseek(hFile,9,1);
Target[0]=fgetc(hFile);
Target[1]=fgetc(hFile);
Target[2]=fgetc(hFile);
Target[3]=fgetc(hFile);
Target[4]=fgetc(hFile);
Target[5]=fgetc(hFile);
Target[6]=fgetc(hFile);
Target[7]=fgetc(hFile);
temp=xtol(Target);
temp = temp-windbg_image_base_addr+ida_image_base_addr;
SetColor(temp,1,0x98fb98);}
}

这里AskStr是获取用户输入字符串,AskFile则是获取用户文件,这里打开的文件,就是刚才我们通过windbg脚本跟踪生成的文件ida.log,之后通过fseek 的方法跳转到指令开头部分,随后会获取相应的地址,并且进行标记,同时需要用户输入ida的对应领空基址以及windbg对应领空基址,这是为了对抗 aslr。

两者获取基址的方法,windbg通过lm命令查看加载模块获得基址。

http://p6.qhimg.com/t0187c4c89f8fbde7c3.png

ida pro直接观察打开pe文件开头就可以获得

http://p7.qhimg.com/t01aa7d9733fd5ca124.png


在ida的文件菜单中有一个功能叫script command,可以导入这个idc的脚本。

http://p6.qhimg.com/t01efacd35e19a70a9e.png

通过import按钮导入idc脚本,再通过run执行,进行相应的设置,这里我们选择打开之前windbg生成的文件。进行对应的参数设置之后观察一下效果。

http://p0.qhimg.com/t01b0b46b24e14aaf85.png


可以看到,执行路径已经被标记出来了,再看下流程图


http://p0.qhimg.com/t01f7e631405477a8ed.png


对应函数的执行路径也都很清晰的展示出来,省去了对地址比对分析的过程。


(四)写在最后

这里我和大家分享了二进制漏洞分析入门的一些技巧方法,并且结合一个实例漏洞分享了我写的辅助分析脚本,比较基础,希望能对大家有所帮助,这个 辅助分析脚本也存在一定的不足,以后会继续完善升级功能,并且弥补存在的一些bug。

地址有效性的判断 函数调用先后顺序的标记 其他可能存在的bug

对应的github下载地址:https://github.com/k0keoyo/binhelp/

也希望大家能够一起交流,一起进步,谢谢!

本文由k0shl原创发布

转载,请参考转载声明,注明出处: https://www.anquanke.com/post/id/84395

安全客 - 有思想的安全新媒体

分享到:微信
+10赞
收藏
k0shl
分享到:微信

发表评论

内容需知
  • 投稿须知
  • 转载须知
  • 官网QQ群8:819797106
  • 官网QQ群3:830462644(已满)
  • 官网QQ群2:814450983(已满)
  • 官网QQ群1:702511263(已满)
合作单位
  • 安全客
  • 安全客
Copyright © 北京奇虎科技有限公司 360网络攻防实验室 安全客 All Rights Reserved 京ICP备08010314号-66