我会在本文介绍这个加载程序的最后进程,它能够下载和执行远程有效负载,例如CobaltStrike和Conti勒索软件。BazarLoader是基于Windows的恶意软件,主要通过电子邮件等方式传播。
![第1步:检查系统语言](http://dingyue.ws.126.net/2022/0927/9d287e9dj00riup3x000sd200u0004ug00it0031.jpg)
与许多恶意软件类似,BAZARLOADER会手动检查系统的语言以避免在其母国开展恶意攻击。
它调用GetSystemDefaultLangID来检索系统的默认语言,并调用GetKeyboardLayoutList来遍历系统的键盘布局。
![](http://dingyue.ws.126.net/2022/0927/ef2a4852j00riup3z0027d200sz00g1g00it00ae.jpg)
对于每一种语言,恶意软件都会使用位掩码检查其是否有效。
如果语言标识符大于0x43或小于0x18,则将其视为有效,这样BAZARLOADER才会继续执行。
如果它在0x18和0x43之间的范围内,语言标识符和0x18之间的差异被用作位掩码中要检查的位的索引。
BAZARLOADER使用的位掩码是0xD8080190C03,即二进制的11011000000010000000000110010000110000000011。如果语言ID为0x18,则检查位掩码中的第一位。如果语言ID为0x19,则检查第二位,依此类推……
![](http://dingyue.ws.126.net/2022/0927/45e0ee9dj00riup3z000ld200jn006bg00it0061.jpg)
以下是恶意软件避免的位掩码中所有语言的列表。
![](http://dingyue.ws.126.net/2022/0927/b465238dp00riup400003d200st002wg00it001v.png)
![第2步:互斥对象](http://dingyue.ws.126.net/2022/0927/9d287e9dj00riup3x000sd200u0004ug00it0031.jpg)
为了检查自身的多个运行实例,BAZARLOADER首先从其进程中提取SID的子权限。它通过调用GetTokenInformation来检索进程的令牌完整性级别并调用GetSidSubAuthorityCount和GetSidSubAuthority来访问SID的子权限来实现这一点。
![](http://dingyue.ws.126.net/2022/0927/568c6fb6j00riup410046d200u00096g00it005q.jpg)
如果SID的子权限是SECURITY_MANDATORY_SYSTEM_RID或SECURITY_MANDATORY_PROTECTED_PROCESS_RID,BAZARLOADER通过调用CreateMutexA检查互斥锁“{b837ef4f-10ee-4821-ac76-2331eb32a23f}”当前是否由任何其他进程拥有。
如果是,恶意软件会自行终止。但是,检查互斥对象是否存在的条件存在一个小错误,它假定它在实际成功时无法打开互斥对象。
![](http://dingyue.ws.126.net/2022/0927/5f1dde53j00riup42002fd200rs00flg00it00aj.jpg)
此后,恶意软件解析字符串“{0caa6ebb-cf78-4b01-9b0b-51032c9120ce}”并尝试使用该名称创建互斥锁。
![](http://dingyue.ws.126.net/2022/0927/d4a32e16j00riup430063d200sc00ehg00it009l.jpg)
如果这个互斥对象已经存在,恶意软件也会自行终止。
如果SID的子权限不是SECURITY_MANDATORY_SYSTEM_RID或SECURITY_MANDATORY_PROTECTED_PROCESS_RID,BAZARLOADER仍然使用这两个互斥对象名称,但在它们前面添加字符串“Global\”。这将检查全局命名空间中的互斥锁,而不是每个会话命名空间,这允许恶意软件检查它是否有在其他用户的会话中运行的实例。
![第3步:生成随机Internet流量](http://dingyue.ws.126.net/2022/0927/9d287e9dj00riup3x000sd200u0004ug00it0031.jpg)
为了生成Internet活动以隐藏其与C2服务程序的通信,BAZARLOADER首先调用InternetOpenA以使用以下字符串作为HTTP用户代理来初始化WinINet函数的使用。
![](http://dingyue.ws.126.net/2022/0927/68c4813fj00riup450064d200tw00eog00it0098.jpg)
然后,恶意软件会生成一个线程以定期连接到随机URL,并利用以下结构生成噪音以隐藏主要的C2流量。
![](http://dingyue.ws.126.net/2022/0927/77f9924ej00riup45000kd200k0008rg00it0088.jpg)
首先,BAZARLOADER调用InitializeCriticalSection来初始化结构的临界区对象,该对象稍后用于保护对creation_flag字段的访问。
接下来,它设置self字段指向结构,creation_flag字段为TRUE,并调用CreateThread生成一个线程来执行这些随机Internet操作。如果创建线程失败,creation_flag字段设置为FALSE。
线程首先尝试获取临界区对象的所有权并检查是否启用了创建标志。如果是,恶意软件会将以下URL解析为堆栈字符串。
![](http://dingyue.ws.126.net/2022/0927/7ab2bc0cj00riup46001fd200tz008wg00it005k.jpg)
接下来,线程进入一个无限循环,开始产生通讯噪音。对于随机数生成,BAZARLOADER使用不同的函数调用Windows API BCryptGenRandom来生成一组随机字节。
它随机选择上面列出的4个URL之一,随机生成URL路径段,然后将两者结合起来构建完整的URL。
![](http://dingyue.ws.126.net/2022/0927/a250e35aj00riup47001xd200sh00eog00it009o.jpg)
在生成路径段时,该函数取生成的路径段的最小和最大数量,以及每个路径段的最小和最大长度。
它在给定范围内随机生成路径段的计数。对于每个段,恶意软件随机生成一个字符串,该字符串在给定范围内具有随机长度,其中包含数字和大写/小写字母。
![](http://dingyue.ws.126.net/2022/0927/de986146j00riup490079d200u000f4g00it009h.jpg)
最后,恶意软件调用InternetOpenURLA与生成的URL建立连接。它使用HTTP_QUERY_CONTENT_LENGTH标志调用HTTPQueryInfoA以检索内容的长度,分配具有该大小的缓冲区,并调用InternetReadFile从该URL读取数据。
![](http://dingyue.ws.126.net/2022/0927/a72c0a3cj00riup4a006md200qv00mtg00it00fy.jpg)
这会重复进行,直到C2通信和有效负载注入完成,这会产生大量噪音来掩盖进出C2服务程序的主要流量。
![第4步:密码结构集群](http://dingyue.ws.126.net/2022/0927/9d287e9dj00riup3x000sd200u0004ug00it0031.jpg)
BAZARLOADER主要使用以下结构与C2服务程序进行通信。我们将在分析代码时解释结构的字段。
![](http://dingyue.ws.126.net/2022/0927/65104393j00riup4f0011d200l300c6g00it00au.jpg)
首先,它填充主结构中的crypto_struct字段。此结构包含稍后用于解密从C2服务程序发送的可执行文件的加密句柄。
结构可以重构如下:
![](http://dingyue.ws.126.net/2022/0927/4164f1d6j00riup4g000pd200m1008og00it007e.jpg)
这个恶意软件会解析字符串“RSA”和“SHA384”,并调用BCryptOpenAlgorithmProvider来获取这两个算法的句柄。句柄存储在crypto_struct结构中的相应字段中。
![](http://dingyue.ws.126.net/2022/0927/c8b90b9dj00riup4h003dd200q800gzg00it00c6.jpg)
接下来,它解析内存中硬编码的RSA公钥和私钥blob,以导入相应的密钥句柄。
![](http://dingyue.ws.126.net/2022/0927/ac51d942j00riup4i003gd200pb00dhg00it00a0.jpg)
对于每个blob,恶意软件会解析字符串“RSAFULLPRIVATEBLOB”或“RSAPUBLICBLOB”,并使用它指定blob的类型时调用BCryptImportKeyPair导入相应的密钥句柄。
![](http://dingyue.ws.126.net/2022/0927/992612c2j00riup4i001td200i700fwg00i700fw.jpg)
最后,它调用BCryptGetProperty来检索RSA公钥和私钥密码块的长度。在完全填充了这个结构之后,BAZARLOADER现在可以执行RSA加密/解密以及SHA384哈希。
![第5步:通过原始IP地址进行C2连接](http://dingyue.ws.126.net/2022/0927/9d287e9dj00riup3x000sd200u0004ug00it0031.jpg)
在与C2服务程序通信之前,BAZARLOADER首先解析原始IP地址列表并将它们写入主结构中的C2_addr_list字段。
该字段是一个表示字符串结构列表的结构,可以如下所示重新构建两个字符串结构。
![](http://dingyue.ws.126.net/2022/0927/0b75caedj00riup4k006id200m700itg00it00fx.jpg)
下面是此示例中使用的C2服务程序的所有IP地址的列表。
![](http://dingyue.ws.126.net/2022/0927/ebec7578j00riup4k001id200ft005ig00ft005i.jpg)
对于其中的每个地址,恶意软件都会尝试与相应的服务程序通信并下载下一阶段的可执行文件。
要建立连接,它会填充以下结构。
![](http://dingyue.ws.126.net/2022/0927/a951d8ebj00riup4k000ad200e20059g00e20059.jpg)
恶意软件调用InternetCrackUrlA来检索C2的URL组件和InternetConnectA以连接到服务程序。
![](http://dingyue.ws.126.net/2022/0927/a98ed516j00riup4l002sd200py00gfg00it00bw.jpg)
然后将此连接结构的字段复制到主结构的C2_connection_struct中。不过,我不完全确定他们为什么不直接填充主要结构。
![](http://dingyue.ws.126.net/2022/0927/9b8c02c8j00riup4m0073d200u000c5g00it007l.jpg)
同样,BAZARLOADER填充下面的结构以创建对C2的HTTP请求。请求的对象名称和HTTP动词被解析为“/data/service”和“GET”。
![](http://dingyue.ws.126.net/2022/0927/8aae1e8aj00riup4o005jd200rk00gtg00it00bg.jpg)
请求的HTTP版本被解析为“HTTP/1.1”,并且BAZARLOADER调用HttpOpenRequestA来使用上面检索到的连接句柄为C2服务器创建此请求。
它还调用InternetSetOptionA设置接收响应和发送请求的超时时间为300秒,连接C2的超时时间为120秒。
![](http://dingyue.ws.126.net/2022/0927/2a2f9667j00riup4p002td200tc00h2g00it00ax.jpg)
BAZARLOADER然后生成附加到请求的HTTP标头。它通过调用GetSystemTime来使用当前日期和时间填充主结构的curr_system_time和datetime_string字段来实现这一点。
它还生成日期时间字符串的SHA384哈希,以填充结构的datetime_string_hash和datetime_string_hash_len字段。
![](http://dingyue.ws.126.net/2022/0927/894feadfj00riup4q0025d200k500e9g00it00db.jpg)
接下来,BAZARLOADER通过调用BCryptSignHash使用其RSA私有签名生成的哈希,并使用此哈希签名随机生成HTTP标头。
下面是随机HTTP标头的形式。
BAZARLOADER的HTTP标头
![](http://dingyue.ws.126.net/2022/0927/09f23bd0j00riup4r0033d200r300gzg00it00bs.jpg)
使用生成的HTTP标头和请求句柄,BAZARLOADER调用HttpSendRequestA将请求发送到C2服务程序并调用HttpQueryInfoA来检索状态码。
如果状态码不是HTTP_STATUS_OK,恶意软件会转移到另一个C2地址。
![](http://dingyue.ws.126.net/2022/0927/cd7536a9j00riup4s0021d200n500dlg00it00b1.jpg)
如果状态码为HTTP_STATUS_OK,BAZARLOADER调用InternetQueryDataAvailable确定要读取的数据大小,根据大小分配内存缓冲区,并调用InternetReadFile读取下一阶段的有效载荷,直到所有内容都写入内存。
![](http://dingyue.ws.126.net/2022/0927/c7df0f90j00riup4t002pd200q500hlg00it00cn.jpg)
最后,恶意软件通过调用BCryptDecrypt使用其RSA公钥解密有效负载,并检查以确保有效负载的大小大于64字节并且包含MZ标头。
![](http://dingyue.ws.126.net/2022/0927/0972d39fj00riup4u002pd200q000erg00it00ao.jpg)
![第6步:通过自定义URL进行C2连接](http://dingyue.ws.126.net/2022/0927/9d287e9dj00riup3x000sd200u0004ug00it0031.jpg)
如果BAZARLOADER无法从上面列出的IP地址下载下一阶段的可执行文件,它会尝试使用用户拥有的DNS社区服务OpenNIC解析自定义C2域。
为了开始查询OpenNIC的API,恶意软件首先解析URL“api.opennicproject.org”并调用InternetConnectA建立与该网站的连接。
![](http://dingyue.ws.126.net/2022/0927/90a9f254j00riup4w004ad200u000ccg00it007q.jpg)
接下来,它调用HttpOpenRequestA以创建对象名称为“/geoip/?bare&ipv=4&wl=all&res=8”的GET请求句柄,并使用HttpSendRequestA发送请求。
通过检查OpenNIC的API,我们可以分解此对象名称以查看BAZARLOADER请求的内容。其中“bare”参数只列出DNS服务器的IP地址,“IPv4”参数只列出IPv4服务器,“wl”参数只列出白名单服务器,“res”参数只列出8个服务器。
为了测试这一点,我们可以简单地将下面的路径粘贴到我们选择的浏览程序中。
![](http://dingyue.ws.126.net/2022/0927/24efc851j00riup4x006vd200rx00l4g00it00e7.jpg)
然后恶意软件进入循环调用InternetQueryDataAvailable和InternetReadFile来读取8个OpenNIC的DNS服务器到内存中。
![](http://dingyue.ws.126.net/2022/0927/4f9068bdj00riup4z0084d200ow00izg00it00ec.jpg)
对于每个DNS服务程序IP地址,BAZARLOADER将其从字符串解析为int并填充主结构中的opennic_server_struct字段。下面是用于存储OpenNICIP地址的结构。
![](http://dingyue.ws.126.net/2022/0927/b32c29d2j00riup51007ad200r000mtg00it00fv.jpg)
最后,恶意软件解码以下自定义C2域,尝试使用DNS服务程序解析它们,并下载下一阶段的可执行文件。
![](http://dingyue.ws.126.net/2022/0927/b95c4221p00riup520001d2008x0034g008x0034.png)
对于每个自定义域,BAZARLOADER调用DnsQuery_A从OpenNIC的服务程序查询DNS资源记录,以解析C2服务程序的IP地址。
![](http://dingyue.ws.126.net/2022/0927/3e387a82j00riup530033d200nz00h5g00it00dg.jpg)
在检查IP地址是否有效后,恶意软件会尝试连接它并请求下载下一阶段的可执行文件,类似于我们在上一步中看到的。
![](http://dingyue.ws.126.net/2022/0927/b2f19100j00riup53002rd200oj00e9g00it00ax.jpg)
![第7步:通过process hollowing技术注入](http://dingyue.ws.126.net/2022/0927/9d287e9dj00riup3x000sd200u0004ug00it0031.jpg)
成功下载下一阶段可执行文件之后,BAZARLOADER开始注入功能,从另一个进程启动它。
对于此功能,BAZARLOADER填充以下结构。
![](http://dingyue.ws.126.net/2022/0927/036a6289j00riup55000id200hh007og00hh007o.jpg)
首先,它检查它的进程是否被提升为管理权限。它调用GetCurrentProcess和OpenProcessToken来检索自己的进程令牌句柄,并调用GetTokenInformation来获取令牌的提升信息。
![](http://dingyue.ws.126.net/2022/0927/e7afc84dj00riup56001xd200o200glg00it00cy.jpg)
如果进程没有被提升,它会解析以下进程的名称并尝试填充注入结构的字段。
![](http://dingyue.ws.126.net/2022/0927/f6e6e6ecj00riup570084d200qu00fag00it00ap.jpg)
对于每个进程名称,恶意软件会枚举进程的快照以检索其ID,并调用OpenProcess以获取其句柄。
为了填充包含进程命令行和完整路径的full_exec_command和thread_curr_directory字段,BAZARLOADER首先从进程环境块(PEB)中提取进程参数。
为了访问PEB,恶意软件调用NtQueryInformationProcess来检索PEB的地址,并调用ReadProcessMemory将PEB读入内存。
![](http://dingyue.ws.126.net/2022/0927/28991d6ej00riup58001hd200kh00eqg00it00di.jpg)
接下来,它调用ReadProcessMemory从进程的内存中读取进程参数。
![](http://dingyue.ws.126.net/2022/0927/b868fb34j00riup59001dd200mg00bug00it009w.jpg)
使用进程参数RTL_USER_PROCESS_PARAMETERS结构,BAZARLOADER读取进程的命令行和完整路径以填充注入结构。
![](http://dingyue.ws.126.net/2022/0927/c5387ec2j00riup5a004hd200u0006mg00it0045.jpg)
同样,它也使用process参数访问浏览程序的环境块并将其写入注入结构。
![](http://dingyue.ws.126.net/2022/0927/b0c6ae4fj00riup5b007ld200gs00k8g00gs00k8.jpg)
如果BAZARLOADER具有管理员权限,而不是浏览程序的进程,它会尝试从以下命令行使用svchost.exe进程填充注入结构。
接下来,利用注入结构,恶意软件调用CreateProcessA来创建处于挂起状态的目标进程以执行process hollowing。
![](http://dingyue.ws.126.net/2022/0927/6ac4447dj00riup5d007ud200jv00k7g00it00j4.jpg)
我们可以通过被调用的WindowsAPI快速发现process hollowing正在发生。调用NtUnmapViewOfSection来取消映射并占用父级的内存。然后调用VirtualAllocEx和WriteProcessMemory在父进程中分配虚拟内存并将恶意负载写入其中。
![](http://dingyue.ws.126.net/2022/0927/8372342dj00riup5e006vd200u000eqg00it0098.jpg)
我们还可以看到,恶意软件遍历父节点的节头以找到“.reloc”节,并对内存中注入的图像执行重定位。
![](http://dingyue.ws.126.net/2022/0927/891962c8j00riup5f007ld200u000djg00it008h.jpg)
最后,BAZARLOADER调用SetThreadContext为父进程设置新的入口点,并调用ResumeThread再次恢复父进程,父进程将执行注入的可执行文件。
![](http://dingyue.ws.126.net/2022/0927/815f0dbfj00riup5g002ad200qa00a3g00it0077.jpg)
在此基础上,我们分析了BAZARLOADER如何下载远程可执行文件并使用进程空心化来执行它。
参考及来源:https://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/
热门跟贴