探索Duqu木马的身世之谜
——Duqu和Stuxnet同源性分析
文/ 安天实验室 antivirusersky
摘要
同源( Homology),是生物遗传学领域的重要概念,主要用于描述物种或DNA序列是否具有相同的祖先。计算机病毒分析工程师也经常通过分析病毒同源性的方法,追踪病毒制造者的身份——比如,dvldr(口令蠕虫)和lovegate(爱门蠕虫)的制造者曾被认为是同一人,安天实验室的反病毒工程师通过同源性分析方法,否定了该观点。本文以对Duqu木马与Stuxnet蠕虫的分析比较为例,介绍病毒同源性分析方法。
背景介绍
2012年3月20日,知名计算机反病毒厂商Symantec在其官方博客(New Duqu Sample Found in theWild)中宣布捕获到了最新的Duqu木马变种,样本的编译时间显示为2012年2月23日。时隔数月,曾备受关注的Duqu木马又回来了? 或者说,它从没有消失过?Duqu木马是什么?为什么会这样令人瞩目?原来,Duqu木马一直被认为是此前更为著名的Stuxnet蠕虫的第二代。那么,Stuxnet蠕虫又是什么?
Stuxnet蠕虫(亦称震网蠕虫、超级工作蠕虫),具有对工业控制系统的破坏能力,被看作是第一个以现实世界中的关键工业基础设施为目标的计算机蠕虫。有媒体形容它为“超级武器”和“潘多拉的魔盒”,因为它开启了真正意义上的网络战,也为以后的网络攻击形式和恐怖主义行为树立了“榜样”。Stuxnet蠕虫曾于2010年7月爆发,利用了微软公司的4个Windows操作系统漏洞(其中3个是当时全新的零日漏洞)和2个WinCC操作系统漏洞,2个有效的数字证书,通过一套完整的入侵和传播流程,突破工业专用局域网的物理限制,攻击用于数据采集与监控的工业控制系统。伊朗政府已经确认该国的布什尔核电站遭到Stuxnet蠕虫的攻击。
Stuxnet蠕虫具有以下特点:
1.同时使用了多个零日漏洞。普通病毒作者一般不会这样做(即使是当年肆虐横行的冲击波蠕虫和震荡波蠕虫,也只是使用了一个微软操作系统的RPC漏洞而已)。
2.模块结构复杂,制作周期较长。Stuxnet蠕虫包含了驱动程序、PLC(Programmable Logic Controller,可编程逻辑控制器)指令以及命令与控制服务器(以下简称C&C服务器)通讯模块等,普通病毒作者不需要、也不愿意付出这样的开发代价。
3.传播过程复杂而漫长。普通的病毒作者一般急于获得利益。
4.主要用于攻击伊朗的核设施。据发表在德国新闻杂志《Der Spiegel》的一篇文章(Stuxnet Virus Opens New Era of CyberWar)介绍,该蠕虫感染了伊朗IR-1型离心机后,将其正常运行速度由1,064 赫兹增加到1,410赫兹,并在15分钟后回到正常频率,从而造成离心机的损坏。伊朗核计划当局认为Stuxnet蠕虫破坏了约1000台离心机。伊朗也承认其核计划遭到了阻碍,并遭受了“潜在的重大损失”。普通的病毒作者,显然无法由此获得利益。
通过以上分析不难看出,Stuxnet蠕虫更可能是团队制作。知名计算机反病毒厂商Kaspersky实验室甚至认为,Stuxnet蠕虫的攻击是具有国家和政府的支持和协助的。
与Stuxnet蠕虫的复杂相比,出现于2011年的Duqu木马则显得有些单薄,它主要功能是数据的采集和回传。这些功能似乎并不比常见的QQ盗号木马具有更大的危害,可是,由于它采用了与Stuxnet蠕虫极为相似的技术手段,引起了多个计算机反病毒厂商的密切关注。假设Duqu木马与Stuxnet蠕虫具有相同出处(即两者具有同源性),那么它出现的意义是什么?是否意味着新的Stuxnet蠕虫即将问世?新的Stuxnet蠕虫的攻击目标又是哪种工业设施?该工业设施会属于哪个国家?另外,通过对Duqu木马的分析,是否可以找出Stuxnet蠕虫的作者或者制作团队?
计算机病毒分析工程师通过判断新病毒与已有病毒是否在编写上存在相互借鉴、衍生、复用等关系,找到新病毒的某些线索,最终确定两个病毒是否具有同源性。主要考查病毒样本的以下几个方面:
模块结构相似性
编译器架构相似性
关键功能实现相似性
数据结构相似性
病毒作者编码心理特点
Duqu木马与Stuxnet蠕虫的同源性分析过程
模块结构相似性分析
Duqu木马的模块结构如图1所示,由驱动模块(使用数字签名)、DLL模块和配置文件组成。其中,驱动模块为jminet7.sys,用于解密负载代码和注入系统进程;DLL模块和配置文件均以加密形式存储在磁盘上,仅在需要时解密到内存;DLL模块的资源中还包含一个负责进程注入的DLL模块,因为不需要保存在磁盘,所以没有文件名;该无名模块提供了多种注入方式,通过这些注入方式中的一种,将自身的资源节代码(用于与C&C服务器通讯)注入到目标进程。
[图1]Duqu木马模块结构图
Stuxnet蠕虫的模块结构如图2所示,由驱动模块(使用数字签名)、DLL模块和配置文件组成。驱动模块分为Rootkit功能(主要用于躲避反病毒软件)的mrxnet.sys文件和负责解密和注入的mrxcls.sys文件;DLL模块和配置文件均以加密形式存储在磁盘上,仅在需要时解密到内存;Stuxnet蠕虫的漏洞攻击代码和工控系统攻击代码均存储在主DLL模块的资源节中,在需要的时候释放出来,主DLL资源中包含了用于与C&C服务器通讯的功能。
[图2]Stuxnet蠕虫模块结构图
通过模块结构的对比,不难看出两者非常相似。两者所使用的驱动模块均采用了有效的数字签名,这一情况在一般的病毒中很少出现。至于两者模块数量的差异是由于两者功能和技术实现方式不同造成。比如,Duqu木马在Stuxnet蠕虫的基础上又加入了新的注入方法,从而增加了新的模块。
编译器架构相似性分析
Duqu木马的jminet7.sys使用Microsoft Visual C++ 6.0编译。
Stuxnet蠕虫的mrxcls.sys使用Microsoft Visual C++ 7.0编译。
Duqu木马和Stuxnet蠕虫的主DLL都使用了UPX压缩壳。
Duqu木马和Stuxnet蠕虫主DLL模块资源节中的DLL文件都是采用Microsoft Visual C++编译。
很奇怪,后出现的Duqu木马反而使用了更早的VC编译器。
关键功能实现相似性分析
注入方式
Duqu木马和Stuxnet蠕虫都采用了DLL注入方式来隐藏自身模块,以躲避杀毒软件的检测,并且都同时采用了驱动层注入和用户层注入两种方式。
两者都通过PsSetLoadImageNotifyRoutine设置回调函数的方式来完成驱动层的注入,并且两者的回调函数的功能基本一致。每当有PE程序(DLL或者EXE)被加载,这个函数都会发生回调,从而获得执行机会。如果加载的是kernel32.dll文件,则通过API名称的哈希值,获得kernel32.dll上一些特定的API函数地址。如果被加载是特定的进程名称(该名称以加密形式保存在注册表),则修改此进程的入口点函数跳转到注入代码执行恶意行为,然后跳回到原入口点(很像感染式病毒,不过是完全内存态的感染),成为蠕虫的傀儡进程。
从两者驱动层注入部分代码逻辑结构可以看出,虽然两者采用了不同的编译器(或编译选项),并且在代码中存在少量差别,注册表和主DLL文件的解密算法也有不同,但是两者的逻辑总体一致,如图3.
[图3]驱动层注入实现方式
通过挂钩 ntdll.dll中的下列函数来完成无实体文件的用户层DLL注入:
ZwQueryAttriutesFile
ZwCloseFile
ZwOpen
ZwMapViewOfSection
ZwCreateSection
ZwQuerySection
注入过程为:
加载一个特殊构造的DLL名称,当LoadLibrary函数加载这个DLL的时候,模拟PE程序加载执行过程,直接从内存中加载这个DLL(而不是从磁盘上),从而躲避杀毒软件的文件扫描。图4展示了系统感染Stuxnet蠕虫后,关键进程services.exe中发现的隐藏模块情况。
[图4] Stuxnet蠕虫的进程隐藏情况
RPC服务
Duqu木马和Stuxnet蠕虫都提供了RPC服务完成点对点通讯。下面两份代码说明两者使用了相同的rpc绑定方式,分别出现在Duqu木马的netp191.pnf文件及Stuxnet蠕虫的oam7a.pnf文件。
[图5] Duqu木马的RPC绑定方式
[图6] Stuxnet蠕虫的RPC绑定方式
关键数据相似性分析
配置文件
Duqu木马和Stuxnet蠕虫都采用了配置与功能分开的实现方式,两者的配置文件结构非常相似:
1、配置文件的前4字节(被用识别标记)内容相同,均为0x90,0x05,0x79,0xae。
2、文件偏移4字节为配置文件头部长度。
3、文件偏移12字节处为文件长度,区别只是长度的大小不一样。
4、均包含生存周期。虽然Stuxnet蠕虫配置文件中记录的时间为自我卸载日期,而Duqu木马记录的日期为感染日期,但后者会在感染之后指定的时间完成自我卸载。所以,两者记录日期目的相同,都是为了控制生存周期,防止分析人员追踪、分析样本。
注册表数据
Duqu木马和Stuxnet蠕虫均由驱动从注册表中读取数据(分别记录在注册表特定主键的Data键和Filter键,均为二进制数据格式),然后实施DLL注入。其中,Duqu木马的键名有所变化,但两者注册表的数据结构几乎相同。
Duqu木马在注册表中保存的二进制数据解密后结构如下(包括:DLL模块的解密密钥、注入目标进程名、注入目标模块路径):
DWORD control[4]
DWORDencryption_key
DWORDsizeof_processname
BYTEprocessname[sizeof_processname]
DWORDsizeof_dllpath
BYTEdllpath[sizeof_dllpath]
Stuxnet蠕虫在注册表中保存的二进制数据解密后结构如下(包括:DLL模块的解密密钥、注入目标进程名、注入目标模块路径):
DWORD control[4]
WORD expNumber;//注入dll调用的导出函数
WORD Flags;
DWORD encryption_key
DWORDreserved;
//List
DWORD sizeof_processname
UNICODEprocessname[sizeof_processname]
DWORD sizeof_dllpath
UNICODEdllpath[sizeof_dllpath]
病毒作者编码心理特点分析
解密密钥
Duqu木马采用无参数的解密算法解密驱动中的加密数据,得到注册表键值和解密注册表数据的密钥0xae240682,从解密后的注册表数据中获取解密主dll模块的密钥0xae240682。
Stuxnet蠕虫先用密钥0解密驱动中的加密数据,得到注册表键值和解密注册表数据的密钥0xae240682,从解密后的注册表数据中获取解密主dll模块的密钥0x01ae0000。
注册表解密密钥相同,说明该数字对病毒作者有着特殊意义,或者是由于心理习惯使然。
反跟踪手段
在两者的驱动程序中,都有是否需要检测系统状态的判断,而且判断过程是相同的:从加密配置数据中读取参数,与1进行逻辑与运算判断是否需要检测系统安全模式,与2进行逻辑与运算判断是否需要检测系统调试模式。这两处判断的目的是企图避免被病毒分析工程师跟踪、调试。然而,常见病毒样本对抗分析与调试的方法却并非如此——它们会直接判断系统当前运行状态,而不是通过配置参数来决定是否进行这样的判断。见图7、图8。
[图7] Duqu木马判断系统状态
[图8] Stuxnet蠕虫判断系统状态
程序Bug
从编码心里学的角度看,由于知识体系和编码习惯的原因,由一个作者同一时期编写的代码应该会存在类似的错误(甚至漏洞)。这一特点经常被黑客利用——当有某系统发布了新的漏洞补丁之后,黑客会尝对比补丁定位漏洞位置和类型,然后在漏洞位置附近查找类似的漏洞。经分析发现,Duqu木马和Stuxnet蠕虫在处理注册表数据代码中存在同样的缓冲区溢出漏洞。该漏洞出现在注册表数据复制的时候,两者都通过ExAllocatePool申请了大小相同(均为0x10字节)的缓冲区,然后使用memcpy函数将注册表数据复制到缓冲区,但在此之前并没有检测注册表数据长度是否正确。如果注册表数据经过特殊构造,则会导致两者出现缓冲区溢出错误。经对比发现,两者代码实现的逻辑几乎完全一样
[图9] Duqu木马注册表操作代码
[图10] Stuxnet蠕虫注册表操作代码
Duqu木马和Stuxnet蠕虫在驱动都存在判断操作系统的版本,且逻辑非常相似。区别在于后者将版本获取函数化,而前者则是使用inline形式执行,这个区别很可能是编译器造成。经过分析发现,两者在判断WindowsXP版本时,均将参与比较的MinorVersion和MajorVersion两个域稿反了。这是一个非常低级的错误,很少出现在有经验的程序员的代码中。
[图11] 判断系统版本代码
总结
主要的比较项目经过整理,如表1所示。
比较项目 | Duqu木马 | Stuxnet蠕虫 |
功能模块化 | 是 | |
Ring0注入方式 | PsSetLoadImageNotifyRoutine | |
Ring3注入方式 | Hook ntdll.dll | |
注入系统进程 | 是 | |
资源嵌入DLL模块 | 一个 | 多个 |
利用微软漏洞 | 是 | |
使用数字签名 | 是 | |
包括RPC通讯模块 | 是 | |
配置文件解密密钥 | 0xae240682 | 0x01ae0000 |
注册表解密密钥 | 0xae240682 | |
Magic number | 0x90,0x05,0x79,0xae | |
运行模式判断代码存在Bug | 是 | |
注册表操作代码存在Bug | 是 | |
攻击工业控制系统 | 否 | 是 |
驱动程序编译环境 | Microsoft Visual C++ 6.0 | Microsoft Visual C++ 7.0 |
[表1] Duqu木马和Stuxnet蠕虫比较
从表中可以看出在模块功能、数据结构、技术实现和编码心理比较中Duqu木马和Stuxnet蠕虫之间存在很多相似性,尤其体现在相同功能的技术实现方式。不难得出两者均由同一团队制作,或者存在着代码复用(即同源)的结论。
至此,本文通过对Duqu木马和Stuxnet蠕虫的分析和比较,简单介绍了反病毒工程师在分析病毒同源性时使用的方法。其中,通过编码心理学分析病毒同源性的方法由安天实验室在2005年正式提出值得一提的是,提出该方法的反病毒工程师恰恰是通过这种方法,得出Sasser蠕虫(“震荡波”)与Netsky蠕虫(网络天空)作者是同一人的假设,而这个假设在2004年9月份德国籍18岁青年Sven Jaschan被抓获时的供述中得到证实。
其实早在2011年年底,Kaspersky实验室已经在报告中提出Duqu木马和Stuxnet蠕虫的作者是同一个人(或者团队)的观点,并在另份报告中提出Duqu木马可能早在2007-2008年之间就已出现,而其主要目的正是收集一系列有关伊朗企业和政府情报机构活动的数据。似乎先有Duqu木马后有Stuxnet蠕虫的假设,更符合实际情况(即先用木马收集详细数据再用蠕虫实施精确攻击),而这也很好地解释了编译器架构相似性分析中的疑点。
只是,被认为是Stuxnet蠕虫的第二代的Duqu木马,会感觉有点委屈。