威胁分子滥用ConnectWise签名应用构建恶意软件的技术分析

本文深入分析威胁分子如何滥用合法ConnectWise软件的Authenticode签名机制构建签名恶意软件,详细解析技术实现原理、配置滥用方式,并提供检测和防护建议。

ConnectUnwise:威胁分子滥用ConnectWise作为签名恶意软件构建器

自2025年3月以来,使用有效签名的ConnectWise样本的感染和虚假应用程序明显增加。我们揭示了不良签名实践如何让威胁分子滥用此合法软件来构建和分发自己的签名恶意软件,以及安全供应商可以如何检测它们。

ConnectWise滥用2024-2025

这并非ConnectWise首次被威胁分子使用。早在2024年2月,我们就看到了与两个ConnectWise漏洞相关的勒索软件活动激增:CVE-2024-1708和CVE-2024-1709。

大约在2025年3月,新一波ConnectWise滥用开始出现,现在以"EvilConwi"的名称被追踪。

当人们怀疑感染时,他们经常转向互联网寻求帮助。“UNITE against malware"论坛(如BleepingComputer.com)在这种情况下提供消毒帮助。BleepingComputer论坛上的几个帖子(link1, link2)显示不需要的ConnectWise客户端是感染的罪魁祸首,通常以网络钓鱼电子邮件为起点。几个类似帖子的存在表明安全程序未能防止威胁。即使在2025年5月,大多数防病毒产品也未将恶意使用的ConnectWise样本检测为恶意软件。

在一个BleepingComputer案例中,感染源是一封包含OneDrive链接的网络钓鱼电子邮件,承诺显示一个大文档。该链接重定向到一个Canva页面,带有一个"查看PDF"按钮,可下载并运行ConnectWise安装程序。用户描述了"虚假的Windows更新屏幕"和他们的鼠标"随机自行移动”。除了这些指标外,没有其他可见的活跃远程连接迹象(样本[1])。

Reddit用户也报告了类似事件,例如在一个案例中,恶意制作的ConnectWise样本[2]源自一个提供基于AI的图像转换器的网站。根据原帖作者,该网站曾在Facebook上做广告。

样本比较

为了找出检测机会和设置位置,我们分析了两个ConnectWise样本之间的差异。

下图显示了PortexAnalyzer报告的两个ConnectWise样本[6][7],我们使用Meld进行比较。

图1: 数据目录比较显示两个样本中证书表的大小不同

图2: 此比较显示每个部分具有相同的哈希值,但整个文件的哈希值不同

除了覆盖层中的证书表外,节内容具有相同的哈希值。我们使用二进制差异工具确认,唯一实质性差异存在于证书表中。

因此,我们可以用来区分ConnectWise安装程序的任何自定义必须位于证书表中。此时我们怀疑是Authenticode填充。

Authenticode填充

Authenticode填充是故意滥用证书结构,允许修改可执行文件而不使其签名失效。开发人员使用此技术来避免为微小更改重新签名其应用程序。这是一种相对常见的做法,像Dropbox这样的应用程序使用它。例如,一些安装程序[3]通过在文件下载前不久将用户代理、引荐来源、广告系列ID或来自浏览器cookie的类似数据保存在证书中来跟踪安装统计信息。在这种情况下,Authenticode填充是无害的,因为它不会影响样本的行为。

有多种方式可以滥用Authenticode签名。为了弄清楚ConnectWise使用哪种方法,我们在两个样本上运行了Authenticode linter。

图3: AuthenticodeLint工具的输出

Linter输出显示两个样本的"无未知未签名属性"检查都失败。这意味着ConnectWise具有不应存在的未认证属性。

下图显示了签名Portable Executable文件的结构,以及未认证属性在证书表中的位置。原始图像来自Microsoft的官方Windows Authenticode PE签名格式文档。

图4: Windows Authenticode PE签名格式

为了验证Portable Executable文件的证书,Windows将证书中的认证哈希与文件的实际哈希进行比较。如果这些哈希不同,验证失败,文件不再有效签名。

Windows计算文件内容的认证哈希,不包括图像左侧灰色区域。这意味着可选头中的校验和、可选头中的证书表条目以及证书表本身在认证哈希计算中被省略。这包括未认证属性。它们不会影响证书的有效性。

图像的右侧显示了证书表结构。未认证属性通常保存时间戳,但也可以保存任意数据。

因为我们假设ConnectWise使用未认证属性进行Authenticode填充,我们创建了一个Python脚本来从PE文件中提取未认证属性。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import pefile
from asn1crypto import cms
import sys
import os

def dump_certificate_table(file_path, output_dir):
    pe = pefile.PE(file_path, fast_load=True)

    security_dir_entry = pe.OPTIONAL_HEADER.DATA_DIRECTORY[
        pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_SECURITY']
    ]
    if security_dir_entry.VirtualAddress == 0:
        print("No certificate table found.")
        return

    cert_table_offset = security_dir_entry.VirtualAddress
    cert_table_size = security_dir_entry.Size

    cert_data = pe.__data__[cert_table_offset: cert_table_offset + cert_table_size]

    offset = 0
    attr_counter = 0

    os.makedirs(output_dir, exist_ok=True)

    while offset < len(cert_data):
        length = int.from_bytes(cert_data[offset:offset+4], 'little')
        revision = int.from_bytes(cert_data[offset+4:offset+6], 'little')
        cert_type = int.from_bytes(cert_data[offset+6:offset+8], 'little')

        cert_blob = cert_data[offset+8: offset+length]

        try:
            content_info = cms.ContentInfo.load(cert_blob)

            if content_info['content_type'].native != 'signed_data':
                print("Not a SignedData structure, skipping.")
                offset += ((length + 7) & ~7)
                continue

            signed_data = content_info['content']

            for signer_info in signed_data['signer_infos']:
                unsigned_attrs = signer_info['unsigned_attrs']
                if unsigned_attrs is not None:
                    print("\nUnauthenticated Attributes")
                    for attr in unsigned_attrs:
                        print("\nNext Attribute")
                        print(f"Attribute Type OID: {attr['type'].dotted}")
                        print(f"Attribute Type Name: {attr['type'].native}")

                        for value in attr['values']:
                            attr_counter += 1
                            filename = os.path.join(output_dir, f"attr_{attr_counter}.bin")
                            with open(filename, "wb") as f:
                                # Dump raw bytes
                                f.write(value.dump())
                            print(f"Value dumped to: {filename}")
                else:
                    print("No unauthenticated attributes found in this signer.")

        except Exception as e:
            print(f"Failed to parse certificate blob: {e}")

        offset += ((length + 7) & ~7)

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print(f"Usage: {sys.argv[0]} <input_pe_file> <output_directory>")
        sys.exit(1)

    input_file = sys.argv[1]
    output_directory = sys.argv[2]

    dump_certificate_table(input_file, output_directory)

ConnectWise配置滥用

我们构建了一个配置转储器,从证书中提取设置和嵌入文件。虽然出于法律原因我们不共享脚本,但大多数对威胁检测有用的有意义数据以XML格式保存,并直接可见于转储的属性(使用上面的Python脚本)或样本的字符串列表。

以下是一个恶意样本[4]的配置转储器示例输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Processing: cb8a1a1e90c29461b0503e2c5deac7b673617477128ee3baea4d8134676c8af4 


========= Parsed Client Data ========= 

Is Silent: False 

Components to Exclude: 0x0 
 
--- Instance Identifier Blob --- 

0602000000a40000525341310008000001000100051e42d081b84623245c42be884c3217fb43dd511451b1fbdb5019df867e7672a3e6c5dce4fd41025f2d4ed931d3978f52105bbe293b3be6f4ba476bcdaf1806d456ffa6cc64e005958582793330c3f4dc22385d8afff1e15a1437daa3c3b11c3ad5078b288072a7c42fa0383b5b8f17b4ddab832bc501698714cbfffa569636c46395d0d4c37171a33c710bdb353335d93222a1dad1a26ae65c55a6711bb95a3559826db8c1dacf36df5705002433b7e2967a2b5d1975eb5ada96e627b73b9b62fb915835897b03d61683c68c92e3c77b264990941a9504461549c4a3d07c9f70207525262f8d20c907802a3cfb5dc7fb6886dac164c1080a3425b87f1d10d2 
 
--- Launch Parameters --- 

Launch Parameters: ?e=Access&y=Guest&h=bookinginvoiceview.top&p=8041&k=BgIAAACkAABSU0ExAAgAAAEAAQAFHkLQgbhGIyRcQr6ITDIX%2b0PdURRRsfvbUBnfhn52cqPmxdzk%2fUECXy1O2THTl49SEFu%2bKTs75vS6R2vNrxgG1Fb%2fpsxk4AWVhYJ5MzDD9NwiOF2K%2f%2fHhWhQ32qPDsRw61QeLKIByp8QvoDg7W48XtN2rgyvFAWmHFMv%2f%2blaWNsRjldDUw3FxozxxC9s1MzXZMiKh2tGiauZcVaZxG7laNVmCbbjB2s8231cFACQzt%2bKWeitdGXXrWtqW5ie3O5ti%2b5FYNYl7A9YWg8aMkuPHeyZJkJQalQRGFUnEo9B8n3AgdSUmL40gyQeAKjz7Xcf7aIbawWTBCAo0Jbh%2fHRDS&c=Property%20S%20New&c=Working%20new&c=Property%20Working%20new&c=Working%20Property&c=&c=&c=&c= 

Launch Constraints: ?h=bookinginvoiceview.top&p=8041&k=BgIAAACkAABSU0ExAAgAAAEAAQAFHkLQgbhGIyRcQr6ITDIX%2b0PdURRRsfvbUBnfhn52cqPmxdzk%2fUECXy1O2THTl49SEFu%2bKTs75vS6R2vNrxgG1Fb%2fpsxk4AWVhYJ5MzDD9NwiOF2K%2f%2fHhWhQ32qPDsRw61QeLKIByp8QvoDg7W48XtN2rgyvFAWmHFMv%2f%2blaWNsRjldDUw3FxozxxC9s1MzXZMiKh2tGiauZcVaZxG7laNVmCbbjB2s8231cFACQzt%2bKWeitdGXXrWtqW5ie3O5ti%2b5FYNYl7A9YWg8aMkuPHeyZJkJQalQRGFUnEo9B8n3AgdSUmL40gyQeAKjz7Xcf7aIbawWTBCAo0Jbh%2fHRDS 
 
--- Additional Files --- 

  app.config                     0x970 bytes 
  Client.en-US.resources         0xc3d0 bytes 
  Client.Override.en-US.resources 0x1f6 bytes 
  Client.Override.resources      0x1f12 bytes 
  Client.resources               0x73a8 bytes 
  system.config                  0x3b6 bytes 

--- PNG Icons by Size ---  
16px : 0xed5 bytes  
32px : 0xed5 bytes  
48px : 0x1d8 bytes 

第一个有趣的指标是连接URL和端口,它们是启动参数的一部分,以及此处设置为false的静默安装标志。但还有更多:嵌入的附加资源和配置文件。

此样本提取的附加文件之一是一个名为Client.Override.en-US.resources的.NET资源。在此样本[4]中,它修改了ApplicationTitle,以便ConnectWise伪造Windows更新并指示用户不要关闭系统,可能是为了确保远程连接保持活动一段时间。

图5: 配置文件中的虚假Windows更新消息

另一个名为Client.Override.resources的资源包含Google Chrome图标PNG文件,这些文件覆盖了ApplicationIcon属性。类似样本如[5]使用相同的文件用虚假的Windows更新屏幕JPEG覆盖BlankMonitorBackgroundImage属性。两张图像如下所示。

图6: 设置Google Chrome图标的配置数据,样本[4]

图7: 样本[5]的ConnectWise配置中的虚假Windows更新屏幕JPEG,压缩伪影如样本中所示

还有两个名为system.config和app.config的配置文件。这些是包含更多设置的XML文件。system.config通常包括另一个ClientLaunchParametersConstraint值——除了已使用配置提取器提取的值之外——它保存连接URL、端口和其他参数。

app.config XML对于威胁评估也很有趣。下图显示了恶意ConnectWise样本典型的app.config文件内容:

图8: 具有设置为false的远程连接指标的app.config

此app.config禁用了几个会提醒用户ConnectWise存在的指标,如托盘图标或活动连接期间的黑色壁纸。

总之,ConnectWise证书表中的设置实质上影响了ConnectWise安装程序和客户端的行为。证书保存的内容包括:

  • 静默安装选项
  • 启动参数,包括连接URL和端口
  • 应用程序图标
  • 向用户显示的消息和窗口标题
  • 软件使用的图像,如背景图像
  • 显示活动连接存在的指标

通过修改这些设置,威胁分子创建自己的远程访问恶意软件,假装是像Google Chrome的AI到图像转换器这样的不同软件。他们通常还添加虚假的Windows更新图像和消息,以便用户在威胁分子远程连接到他们时不会关闭系统。

威胁防护建议

我们建议同行防御者禁止任何具有以下多个app.config设置设置为false的ConnectWise样本(使用正则表达式语法):

  • (Support|Access)?HideWallpaperOnConnect
  • (Support|Access)?ShowBalloonOnHide
  • (Support|Access)?ShowBalloonOnConnect
  • (Support|Access)?ShowSystemTrayIcon
  • (Support|Access)?ShowCloseDialogOnExit

Yara规则可能如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
rule SilentConwi : Riskware PUP
{ 
	meta: 
		author = "Karsten Hahn @ G DATA CyberDefense" 
		description = "Settings from app.config that hide the connection of the client. These settings are potentially unwanted" 
		sha256 = "1fc7f1ef95f064b6c6f79fd1a3445902b7d592d4ff9989175b7caae66dd4aa50" 
	 
	strings: 
		$rex_01 = /<setting name="(Access|Support)?ShowBalloonOnConnect"[^>]*>\s*<value>false<\/value>/ 
		$rex_02 = /<setting name="(Access|Support)?HideWallpaperOnConnect"[^>]*>\s*<value>false<\/value>/ 
		$rex_03 = /<setting name="(Access|Support)?ShowBalloonOnHide"[^>]*>\s*<value>false<\/value>/ 
		$rex_04 = /<setting name="(Access|Support)?ShowSystemTrayIcon"[^>]*>\s*<value>false<\/value>/ 
	 
	condition: 
		all of them 
}

我们还建议检测嵌入证书中.NET资源内的虚假应用程序标题、虚假图标和虚假背景图像。

GDATA产品将恶意滥用的ConnectWise样本检测为Win32.Backdoor.EvilConwi.,将具有可疑设置的样本检测为Win32.Riskware.SilentConwi.

供应商实践和最终用户风险

尽管Authenticode填充是常见做法,但ConnectWise决定使用未认证属性影响关键行为及其用户界面显然是危险的。它引诱威胁分子构建自己的具有自定义图标、背景图像和文本的远程访问恶意软件,这些软件由受信任的公司签名。

鉴于ConnectWise的ScreenConnect被广泛(滥)用,关注这些样本是个好主意。在ConnectWise改变其Authenticode填充实践之前,创建和分发签名恶意软件的可能性仍然是一个威胁。

6月12日,我们在本文发布前联系了ConnectWise,以使他们意识到上述问题并给他们发表声明的机会。我们在2025年6月17日星期二注意到用于签署样本的签名已被撤销。在本文发布时,我们尚未收到声明。

2025年6月30日更新

本文发布后,Ken Pyle联系我们,表示EvilConwi可能与以下CVE相关: https://www.cve.org/CVERecord?id=CVE-2023-25718 https://www.cve.org/CVERecord?id=CVE-2023-25719

新的ConnectWise安装程序不再将配置保存在证书中,而是保存在与安装程序一起提供的单独文件中。

这些新的安装程序仍然被威胁分子滥用。

本文引用的样本

[1] 来自BleepingComputer的ConnectWise
7287a53167db901c5b1221137b5a1727390579dffd7098b59e6636596b37bc27

[2] 来自Reddit的ConnectWise
7180238578817d3d62fd01fe4e52d532c8b3d2c25509b5d23cdabeb3a37318fc

[3] 证书中带有跟踪数据的安装文件
a6fb2a4be91f6178d8ba0ca345727d1cb7995c3e4a659a68bef306c9eff4b18e

[4] 配置中带有虚假Windows更新消息和Chrome图标的ConnectWise样本
cb8a1a1e90c29461b0503e2c5deac7b673617477128ee3baea4d8134676c8af4

[5] 配置中带有虚假Windows更新屏幕的ConnectWise样本
28f46446d711208aa7686cdaea60d3a31e2b37b08db7cfb0ce350fcd357a0236

[6] 用于比较的ConnectWise样本
6d9442ae6ba5a9f34a47e234b6047f61d8ac129e269199793ebb0bed1ad7e3ba

[7] 用于比较的ConnectWise样本
277ef6c0dcaf0e76291fbde0199dda1ca521c03e77dc56c54f5b9af8508e6029

按感染向量排序的样本哈希

基于收集的样本及其命名方案,我们观察到某些模式作为可能的感染向量。

虚假安装程序
540c9ae519ed2e7738f6d5b88b29fb7a86ebfce67914691ce17be62a9b228e0a, ZoomInstallerFull.exe
55a228f22f68b8a22967cc5b8b2fcbea66fcaf77bebedfb1f89cd134a0268653, zoom_meetingconnect.exe
C0c48de11bc4b70fb546b9a76b6126a355c0a0f4b45ed6b6564d8f3146c9f0af, ZoomInstaller-x64.exe
67b909bbcce486baba59d66e3b4ec4c74dd64782051a41198085a5b3450d00c9, OneDriveSetup.exe
b1c36552556a69ec4264d54be929e458c985b83bbc42fe09714c6dce825ac9a7, MicrosoftExcel.ClientSetup.exe
D37e804938cf0a11c111832b509fbecf8a0f3e9373133be108d471d45db75de8, Adobe-Update-ClientSetup.wSZQ5iHP.exe.part
b61aed288b4527b15907955c7521ff63cc0171087ac0f7fea6c7019a09c96c04, Adobe.ClientSetup_v7.-2.7.exe
6bce39b7d7552dbacbb4bdf06b76b4fed3fbb9fe4042b81be12fbdff92b8d95c, SSA Viewer.exe

虚假视频或电影客户端
6aa1b9f976624f7965219f1a243de2bebb5a540c7abd4d7a6d9278461d9edc11, Creation_Made_By_CanvaAI.mp4 Canva.com
8fc8727b6ddb28f76e46a0113400c541fb15581d2210814018b061bb250cc0e6, FULL_MOVIE_DOWNLOAD.exe
5da9a0d0830c641ffda6be3be7733de469418abedc6fac0cfcd76ba49f8ade2e, P0RN-vidz.Client.exe
72fe38ad67a26cfd89d1bfc744d33f80277e8eb564b5b92fdac46a9a24d845f3, P0RN-vid.Client.exe
5ccc9ef3e8f7113469f4a46c3aca3939fd53b3561a9fd8ffacd531aa520c5921, FULL_MOVIE_WATCH_NOW.exe
23ff4f91db852b07c7366a3c3b8be0bade2befccbfea7e183daadb5e31d325c0, Schau mir jetzt nackt vor der Webcam zu.exe

虚假文档
41037935246da6f43615d93912bc62811c795ea4082a2bfdbf3eda53a012666e, Social_Security_Statement_873164.exe
98e3f74b733d4d44bec7b1bf29f7b0e83299350143ff1e05f0459571cb49c238, Statement.pdf.Client.exe
d6844a6050d5f6c20a3fe12df28e53a2e46559e6c5017576022372e35ab44ff5, SSA-statement-osu5ma6.PDF`.exe
573f1eefac3079790a9ab40bdd3530ce34b1d2d1c6fa6703a5a8d81cb190a458, BarryStatementPDF.exe
F55c6160ed57a97c4f0e1c6aa6e3f8f01a966e96a99a29e609ec60e63be11889, FATURA-255441144227D55224QO02GX6QL.com
4e5cfd915f44dc263f29e1eaef82b3e2e903ba92b10f88c0eaf89fe5eab82ff5, ANFRAGE FÜR VORSCHLAG.exe
E7f9b9c9205162ddee72a7b7ff86b6524e19c7e8b51f64fdbffc8015c7e8934c, Important Document.exe

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计