浅析Microsoft Jet Engine MDB File溢出漏洞
-
文/图 爱无言当我第一次在网上看到关于这个 漏洞的公告时,耳边就响起了不断的争论,原因就是因为这个漏洞是一个在地下流行了快一年的漏洞,究竟是谁发现的,而公布者与漏洞发现者是不是一个人就成了大家争论不休的话题。孰对孰错,我相信在安全这个领域里大家还是能够看清的,奉上一句话,希望能与大家共勉——我们只谈技术!抛开这些,还是让我们回归到正题上来。既然这个漏洞公布了,相信那些勇于尝鲜的朋友们早已经得到那个可以弹出一个计算器的mdb文件了,但是一个简单的不能再简单的计算器怎么能满足我们日益增长的“物质与精神”的需求呢?自己常常看到在一些安全 论坛中,有人发帖询问如何修改这个mdb文件能够让其执行别的程序或者如何能够换一段自己的ShellCode到这个mdb文件里呢?不论这些问题背后的目的是什么,但要想弄明白怎么修改ShellCode,就需要一定的技术含量了。如果大家留意过以前gyzy的文章,就会知道这种技术就是如何利用已经公布的POC来打造属于我们自己的exploit。而这一切首先要做的就是必须先要分析清楚Microsoft Jet Engine MDB File Parsing Stack Overflow的原因,找到漏洞触发的方法,然后加入我们的ShellCode。既然有了清晰的思路,下面我们就开始本次的分析之旅吧。公布出的这个POC其实已经是一个exploit了,只是说漏洞的细节不是很清楚,所以比较难回溯出漏洞触发的原因。在我使用UltraEdit32打开这个mdb文件时,我建立的第一个思路就是看能不能找到那段能够执行计算器的ShellCode。为什么要这样做?我的想法是,既然关于这个漏洞的细节比较模糊,利用百度查询出来的结果都只是简单的一个利用mdb文件,没有具体说明什么原因,但是根据一般的栈溢出漏洞的利用原理,要么是先利用过长的字符串填充栈空间到函数的返回地址,然后利用一个jmp (寄存器)指令的地址覆盖函数的返回地址,后面再接SshellCode,这种利用方法主要借助寄存器指向后面的shellcode,其在内存中的形式类似图1。图1此时只要我们找到了ShellCode,通过修改jmp (reg)指令地址的数值,把其改成一个诸如:66666666这样一般不会存在的地址,再打开该POC文件就会引发程序出错,然后利用调试器查看程序出错时的情况就可以准确找到程序溢出时的地址了。还有一种情况,栈溢出的利用可以通过SEH链的覆盖也能获得利用的权限,这主要是利用在一些覆盖栈数据对程序造成破坏作用的情况下,它的原理其实和上面的触发方式差不多,只是覆盖的地址不再是函数的返回地址,而是SEH链的异常处理函数地址,这样一旦程序在溢出出错后,系统就会去执行异常处理函数,而该函数地址却已经被我们控制进而执行我们想要的ShellCode代码了。无论怎样,只要我们找到了ShellCode,那么离找到溢出的原因就不远了。在UltraEdit32中,点击快捷键Ctrl+F,出现“查找”对话框,在查找内容中填入“calc”四个字符,这样写的原因是计算器的程序名称就叫做:calc.exe。公布出来的mdb文件能执行计算器,其ShellCode中必会有计算器的名称,除非是ShellCode加密、断句、双字节或者 数据库本身有 加密,那样就得费点时间查找了。点击查找后,我们果然找到了这段字符,如图2所示。:图2这段ShellCode很是眼熟,因为自己编写过ShellCode,所以多少还是知道一些的。现在我们找到了ShellCode,那么就该找到那个覆盖返回地址或者SEH的关键数值了。正如我前面分析过的,无论是覆盖返回地址还是覆盖SEH,只要找到ShellCode,那么离这些地址就不远了。只有修改这些用来进行覆盖地址的数据,我们才能重新触发程序出错,从而来分析出溢出漏洞发生的原因。通过将执行计算器的ShellCode剥离出来,我发现有一段数字很是让人怀疑,其数值为1B0D4C42,这个数值跟ShellCode确实没什么关系,我试图将其修改为FFFFFFFF,然后保存这个被修改的mdb文件。使用ACCESS2003打开该文件后,ACCESS2003程序瞬间消失,但计算器却没有出现,这会不会告诉我们,刚才的修改已经准确地找到了溢出发生的地方呢?打开Ollydbg程序,用它打开ACCESS程序,F9运行,然后在打开的ACCESS中选择文件打开我们刚才修改保存的mdb文件,此时Ollydbg停了下来,如图3所示。图3注意到图中这段出错的代码了吗?看起来像是一个无法利用的写入错误,千万别这样简单的看待你所要分析的漏洞,其实这是一段非常典型的类似strcpy的函数实现代码,其中ecx控制着字符串拷贝的次数。我们看到刚开始ecx中的内容是由edx赋值过来的,也就是0x5200,见上图右侧的寄存器窗口。转换这个数字为十进制,结果为20992,这么多次的循环移动字符串,如果目标地址空间分配不够,势必会发生一个写入错误。现在我们既然终于找到栈空间溢出的错误了,那么随之又产生了一个新问题,我们是要通过覆盖函数返回地址呢?还是覆盖SEH链来获得执行ShellCode的权限?仔细看看这个栈溢出的错误,我们完全可以断言POC的公布者使用的是覆盖SEH的办法来获得执行ShellCode权限的。因为我们看到在Ollydbg的调试中,利用修改后的mdb进行测试的时候,Ollydbg程序捕获的是一个内存写入性的错误,这其实会引发一个异常,如果是一个覆盖函数返回地址的利用方式,则Olydbg捕获的应该是一个读取某某地址出错,因为EIP寄存器的值会被修改,既然异常发生了,那么异常只能被SEH链上的异常处理函数进行处理,所以要想在溢出后控制程序就必须截获异常处理函数。为了证明我的断言,我再次使用Ollydbg调试这次溢出的结果,选择查看SEH链,如图4所示。图4看到SEH链的内容了吗?它竟然就是我们刚才怀疑的那段数据。通过上面的一步一步的分析,我们现在知道这个mdb文件的溢出是利用覆盖SEH的方法来获得执行ShellCode的权限的,那么为什么POC的作者会选用1B0D4C42这个地址来覆盖这次溢出发生的SEH链呢?我们来更进一步分析一下。首先,0x1B0D4C42这个地址是存在于msjet40.dll文件中的,关于这一点我们在上面的图中可以清楚地看到,而同时,出现溢出问题的文件其实也就是这个文件,因为mdb这样的数据库就是由微软的数据库引擎文件解析的。我们通过Ollydbg去看看这个地址处的代码是什么,如图5所示。图5可以看到原来在地址0x1B0D4C42处的代码是一条“call [ebp+c]”指令,也就是说在溢出发生后,通过SEH链,程序会被执行到0x1B0D4C42处的call指令,这样的话一旦“ebp+c”的内容就是一个指向我们可以控制的ShellCode的地址,我们就可以成功获得执行任意代码的权力了。情况是不是这样呢?我们在Ollydbg中查看一下“ebp+c”的内容,如图6所示。图6看了这张图后,就不必再说什么了吧?“ebp+c”的内容为0013e25c,而在内存窗口中键入0013e25c后看到的,竟然就是我们在UltraEdit32中找到calc后的那段包含ShellCode的代码。至此,我们终于明白了POC的作者利用该漏洞的思路,通过覆盖SEH链,借助[ebp+c]的内容为mdb文件中的某个我们可以修改内容的位置,进而来获得执行ShellCode的权限。总的来说,这个关于Microsoft Jet Engine MDB File溢出的漏洞是较为简单的,但是POC的作者利用思路确实很有技巧,我们应该学习一下这种思路。同时,在自己进行测试的时候发现,这个溢出漏洞对msjet40文件的版本还是有一定要求的,我作测试的msjet40文件版本为4.00.8618.0。下面再说一下ShellCode的修改方法,利用任意一款十六进制编辑软件打开随文章提供的mdb文件,找到偏移文件位置0x3336的地方开始替换即可。这之后还有一个问题是大家最关心的,那就是这个漏洞能给我们带来什么好处呢?除去远程欺骗用户直接访问这个mdb文件进而触发漏洞利用以外,正像以前曾出现过的一个同样的Microsoft Jet Engine溢出漏洞,我们可以利用WebShell先上传修改好的mdb利用文件,然后编写一段简单的通过ADODB.Connection打开该mdb文件的脚本文件,调用该脚本文件就会触发一个本地溢出,从而获得在远程服务器上提升权限的机会。截止到目前为止,网上有人放出了一个带有反弹功能的本漏洞利用工具,这样的话,一旦我们在WebShell里调用这个mdb文件,就能成功地获得一个远程Shell了。可以说,这个漏洞为那些苦于WebShell提权的朋友们又找到了一个新的途径。