一、BokBot:代理模块
CrowdStrike在最近的一篇博文中对BokBot的核心模块做了深入分析,而本篇文章作为前篇内容的延伸,将对BokBot代理模块的内部工作原理做深入探讨。BokBot代理模块是一段十分复杂的代码,其主要目的是诱骗受害者将敏感信息发送到命令和控制(C2)服务器。
二、概述
BokBot银行木马(也被称为IcedID)于2017年4月首次被发现,自那时起,CrowdStrike便对其展开了持续跟踪工作。BokBot被攻击者们广泛用于打击全球范围内的金融机构。它能通过检索多个模块来增强其功能,其中一个就包括运行本地代理服务器的模块,此模块能够拦截并潜在地操纵web流量,最终目的是用于金融诈骗。
BokBot核心模块能下载代理模块,并将其注入派生的svchost子进程中,而代理模块能在目标进程中初始化自身。下面是对这个过程的逐步分析。
三、模块初始化
在启动代理服务器线程之前,该代理模块会经历一个初始化的过程。它的大部分内容都跟前篇文章中介绍的其他BokBot模块类似,比如减少错误干扰、构建C2列表或是设置命名事件以与父进程通信。在截获来自用户浏览器的流量之前,需要执行以下步骤。
3.1、Webinject更新
用户模式异步过程调用(APC)对象用于触发进程内存中的webinject数据的更新事件。在初始化期间,将向APC队列发送单独的用户APC对象,每个对象对应一个webinject DAT文件(参见前篇文章)。每个DAT文件都被解码并存储在进程内存中,并将作为参数传递给APC回调函数。处理APC队列之后,web配置将被解析并加载到进程内存中。
3.2、C2通信线程
每当收集到要发送回C2的数据时,就会发信号通知通信线程。当注入的恶意javascript向代理服务器发送特定类型的请求时,都会发生信号事件(参见第九节:流量操作:浏览器视角)。返回的数据可能是收集到的个人信息、屏幕快照或与是代理相关的错误。
3.3、代理服务器初始化
代理服务器在TCP端口57391上被绑定到127.0.0.1。侦听器设置之后,将使用此socket注册Windows Socket API (WSA)事件处理程序,以处理所有连接/发送/接收网络请求。
3.4、SSL证书
为了对SSL连接执行man-In-middle (MITM)攻击,代理服务器需要生成SSL证书,并将其插入到证书库中。证书是通过调用CertCreateSelfSignCertificate创建的,使用的是以下硬编码标识名(DN)的值:
临时证书库在内存中创建,并最终写入到以下位置,文件名用Bot ID生成:
C:\Users\jules\AppData\Local\Temp\ D38D667F.tmp
证书库里将包含一个用于webinject和C2服务器的SSL证书。
完成这些步骤后,代理服务器就可以拦截来自浏览器的请求,但浏览器还尚未被重新配置为指向代理服务器。
四、代理连接
现在,每当用户的浏览器试图连接到一个网站时,请求就会被劫持,并首先由代理服务器处理。本节介绍如何管理连接状态、SSL MITM的工作机制,以及代理服务器采取的相应操作。
4.1、管理连接状态
所有连接都由一系列与WSA回调事件绑定的数据结构管理,这些数据结构跟踪与客户机的内部通信以及与目标网站的外部通信,并确保代理服务器处理的所有请求的完整性。
图1:代理连接状态体系结构
图1中的架构图总结了用于维护代理请求状态的代理服务器组件之间的关系布局。
4.2、SSL MITM
如果用户输入的URL能与webinject目标列表中的URL相匹配,则SSL请求会被代理劫持,代理使用自己的SSL证书将自身插入到通信中。代理服务器接收请求后,将使用代理服务器的SSL证书来建立SSL连接,之后再将请求发送到目标网站,并在代理和目标网站之间建立SSL连接。来自目标网站的响应被解密后再使用代理的证书进行加密,并将其发送给受害者,而流量则由代理的证书来解密。用于维护SSL通信流的状态SSL上下文数据结构类似于图1。
关于浏览器是如何将这些证书视为有效的,请参阅“6.6.4、确认有效证书”一节。
五、代理行为
如果请求的URL主机名与其中一个webinject不匹配,那么代理服务器将在受感染的主机和web服务器之间传递HTTP请求/响应。但是,如果URL与webinject目标站点匹配,则会采取其他操作(参见“八、流量操作:代理视角”一节)。
六、将浏览器重定向到代理
初始化代理服务器之后,任何正在执行的浏览器进程都会被配置为使用代理。为了做到这一步,BokBot会将代码注入浏览器进程。注入的代码将钩子添加到关键函数中,从而劫持浏览器流量。
6.1、浏览器进程选择
首先,BokBot会生成一个循环线程,用以迭代当前执行的所有进程名。而为了获取当前进程列表,使用的是ZwQuerySystemInformation生成的BASIC_PROCESS_INFORMATION结构列表。
6.1.1、进程识别
生成列表后,紧接着是标识浏览器进程的工作。浏览器进程用散列标识,如表1所示。
表1:浏览器标识散列
散列值是使用自定义方法生成的,使用在样本之间变化的常量值进行异或运算,该常数值在不同的样本之间是不同的,因此散列值也是变化的。
6.1.2、代理配置检查
一旦确认了浏览器,就会检查此浏览器进程是否已经由BokBot配置了代理。为了跟踪注入的每个浏览器进程,将创建一个链表数据结构(图2)。如果浏览器本身不在列表中,则创建一个包含目标流程ID和目标流程创建时间的新列表项。
图2:浏览器进程跟踪链表
另外一项检查是尝试打开一个命名事件。代码注入之后,浏览器进程将创建一个命名事件。命名方案的生成方法与前篇关于BokBot核心模块的文章中讨论的方法类似,但不同之处在于流程ID被附加到了名称的末尾。模块调用OpenEvent,如果返回的错误代码是ERROR_FILE_NOT_FOUND,那么注入代码将继续执行。
6.2、打开进程和附加检查
模块通过调用OpenProcess打开浏览器进程的句柄,并检查进程是否为WOW64,如果是,则调用产生相同结果的过程。
同时,为了确定进程是否已配置,会进行双重检查,另一项检查是:
1.使用ZwQueryInformationProcess和ReadProcessMemory获取流程环境字符串。
2.检查每个字符串是否存在:v313235373937=true(3132353739是BotID的ascii表示形式)。
3.如果这个环境字符串存在,则不会发生注入。
6.3、浏览器进程注入和代码执行
代理配置代码的注入方式与BokBot的子进程注入方法大致相同(同样参考上篇文章),但有两点不同:一是调用OpenProcess连接进程;二是会为ZwWaitForSingleObject添加一个钩子。这意味着只要浏览器执行了ZwWaitForSingleObject,注入的代码就会执行删除钩子、配置代理、完成ZwWaitForSingleObject调用的工作,以维护流程执行。
6.3.1、上下文结构
上下文数据结构被注入到浏览器进程中,并为代理配置代码提供必要的信息以确保配置正确。
6.4、浏览器代理配置代码
配置代码实际上是一系列过程钩子,用于将代理模块插入通信通道:
· CertVerifyCertificateChainPolicy
· CertGetCertificateChain
· connect (ws2_32.dll)
以及用于特定浏览器的函数:
· Internet Explorer:MSAFD_ConnectEx
· Firefox:SSL_AuthCertificateHook
· Chrome:ws2_32.WSAEventSelect
6.4.1、插入钩子
大多数钩子都是通过遍历目标模块的导出表、散列程序名,然后将散列与静态值进行比较来插入的。如果散列匹配,则可以放置钩子。
表2:钩子函数名散列
为了获得MSAFD_ConnectEx的地址,使用了另一种方法,我们以“6.6.3、勾住浏览器的特定函数”中的Internet Explorer: MSAEFD_ConnectEx为例进行讨论。
6.6.2、Winsock2 Connect 钩子
Winsock2钩子拦截所有使用connect API发送网络流量的AF_INET网络流量(Firefox和IE)。socket设置为非阻塞模式,使用ioctlsocket将新的connect调用发送到代理服务器。建立连接后,将包含以下数据的12字节数据包发送到代理服务器:
这12个字节将被解析并存储在PROXY_SESSION_CONTEXT数据结构中(图1)。任何使用此文件描述符的网络调用都将发送到代理服务器。无论哪个浏览器发出调用,都不会知道被代理拦截了流量。
6.6.3、勾住浏览器的特定函数
下列的钩子视不同浏览器而定。从本质上讲,无论是浏览器特定的库还是MS共享模块,每个浏览器都以不同的方式处理请求。
· Internet Explorer:MSAFD_ConnectEx
与前面的connect钩子类似,此功能使用包含代理服务器连接数据的socket来交换原始socket。过程地址不在mswsock.dll的导出表中,因此通过调用WSAIoctl套接字获取地址,IO控制代码为SIO_GET_EXTENSION_FUNCTION_POINTER (0xC8000006)。
· FireFox:SSL_AuthCertificateHook
Firefox使用SSL_AuthCertificateHook回调函数来验证证书。如果证书经过身份验证,则返回SECSuccess(null)。 BokBot会试图在“nss3.dll”模块中勾住此函数,如果失败,它将在“ssl3.dll”中补上相同的函数。钩子总是返回SECSuccess。
· Google Chrome:WSAEventSelect
除了勾住ws2_32.connect,BokBot还在WSAEventSelect的ws_32.dll模块中添加了一个额外的钩子。钩子为每个连接事件(FD_CONNECT)抓取socket和事件对象,数据将通过调用钩子连接程序来处理。
· Google Chrome: connect
这个钩子本质上与IE和Firefox的connect钩子相同。主要的区别是,WSAEventSelect钩子收集的所有连接事件都由这个钩子处理的。
6.6.4、确认有效证书
一旦浏览器流量被重定向到代理,Bokbot必须防止浏览器向用户发送证书错误的通知。为了确保证书得到验证和信任,需要连接两个过程:CertVerifyCertificateChainPolicy和GetCertificateChain。
证书链验证
证书链通过调用CertVerifyCertificateChainPolicy进行验证。此过程返回一个布尔函数表示链是否有效。BokBot通过挂钩此函数来确保所有验证SSL证书链(CERT_CHAIN_POLICY_SSL)的尝试都将返回TRUE。
证书链上下文信任
为了确保浏览器看到证书是可信的,BokBot挂钩GetCertificateChain过程。GetCertificateChain将构造一个包含CERT_SIMPLE_CHAIN结构数组的CERT_CHAIN_CONTEXT结构。每个CERT_SIMPLE_CHAIN结构都包含一个CERT_CHAIN_ELEMNT数据结构数组。
这些数据结构都包含一个字段TrustStatus,用于传递证书链的潜在问题。为了确保成功,需要修改TrustStatus字段,以确保链中的所有证书都是可信的。
TrustStatus是一个由标识错误的字段(ErrorStatus)和包含证书信息状态的字段(InfoStatus)组成的结构。在每个结构中,通过修改这两个字段诱使浏览器相信证书都是可信的。
首先,设置ErrorStatus表示证书或链没有错误:
对于所有数据结构,此值都设置为相同的。然而,CERT_CHAIN_ELEMENT结构、CERT_CHAIN_CONTEXT和CERT_SIMPLE_CHAIN结构之间的InfoStatus字段是不同的:
一旦设置了这两个值,证书链就会被浏览器视为可信的。
七、代理与C2的通信
在代理服务器和C2之间传递的大部分通信将由被过滤的数据或用于调试的错误消息组成。表3包含每个请求都要传递的URI参数。而具体发送的数据将在下一节中讨论。
表3:C2 URI参数
下面是请求头的一个示例:
在这种情况下,请求体包含以下Zlib压缩数据:
请求体解压缩为以下内容:
由于篇幅较长,本文将分为两部分,稍后内容敬请期待。
还没有评论,来说两句吧...