AppSuite PDF编辑器后门:详细技术分析
一些威胁行为者大胆到将自己的恶意软件作为误报提交给防病毒公司,并要求移除检测。这正是AppSuite PDF Editor发生的情况。最初,自动化系统将其标记为潜在不受欢迎程序——这一判定通常适用于具有可疑功能的合法软件,如不需要的广告或未经适当同意安装第三方程序。然而,在AppSuite案例中,我们发现了一个后门。
高排名网站
威胁行为者利用在搜索结果中排名靠高的网站,诱使用户下载功能欺骗性的"生产力工具"或PDF管理"命令中心"。这些网站与我们之前在此博客文章中描述的JustAskJacky和其他经典特洛伊木马的下载页面有相似之处。这些不同的网站下载完全相同的MSI安装程序[1]。
图1:PDF编辑器在各种设计不同的网站上做广告
AppSuite Microsoft安装程序
可下载的安装程序[1]是一个Microsoft安装程序(MSI)文件,使用WiX的开源版本创建。执行并接受EULA后,安装程序立即从vault[.]appsuites[.]ai将PDF编辑器程序下载到’%USERPROFILE%\PDF Editor’目录。
然后它无参数执行主应用程序,相当于启动–install例程(我们将在后面描述)。它还创建了一个自动运行条目,为恶意应用程序的下一次运行提供命令行参数–cm=–fullupdate。
图2:MSI文件的元数据信息显示WiX Toolset构建(点击放大)
图3:PDF编辑器的下载源(点击放大)
AppSuite PDF编辑器
编辑器本身是一个Electron应用程序,这是一个允许开发人员使用JavaScript构建跨平台桌面应用程序的框架。程序安装到’%USERPROFILE%\PDF Editor’或’%LOCALAPPDATA%\Programs\PDF Editor’。
组件概述
以下组件是我们分析中最重要的,您可以在底部的危害指标部分找到样本哈希值:
| 文件名 | 路径 | 描述 |
|---|---|---|
| pdfeditor.js[2] | PDF Editor\resources\app\w-electron\bin\release | 主代码,包含后门 |
| packages.json | PDF Editor\resources\app | pdfeditor.js的主代码执行参考 |
| UtilityAddon.node[3] | PDF Editor\resources\app\w-electron\bin\release\lib | 辅助DLL,除其他外用于通过计划任务实现持久化 |
| LOG1 | PDF Editor\resources\app\w-electron\bin\release\default | 包含设置的编码JSON文件 |
| LOG0 | PDF Editor\resources\app\w-electron\bin\release\default | 临时JSON文件 |
| PDFEditorSetup.exe[4] | PDF Editor\ | 包含所有相关文件的NSIS安装程序,向注册表添加RUN条目,使用命令行开关–cm=–fullupdate执行应用程序 |
| PDF Editor.exe[5] | PDF Editor\ | 标准Electron应用程序启动器 |
| Uninstall PDF Editor.exe[6] | PDF Editor\ | 程序的卸载程序 |
主要组件是文件pdfeditor.js[2],其中包含使用Obfuscator.io混淆的JavaScript代码,并具有自定义字符串混淆例程。
命令行开关和GUI
脚本pdfeditor.js[2]接受以下命令行参数(另请参见图4):
| 命令行开关 | 含义 | 后门例程 |
|---|---|---|
| –c和–cm缺失 | 启动安装 | –install |
| –c=0 | 如果文件\mode.data存在,跳过主后门代码并立即运行GUI | 无 |
| –cm=–cleanup | 从服务器注销并删除计划任务PDFEditorScheduledTask和PDFEditorUScheduledTask | –cleanup |
| –cm=–partialupdate | 联系服务器获取配置,读取浏览器密钥并更改浏览器设置,可以执行任意命令 | –check |
| –cm=–fullupdate | 联系服务器获取配置,读取浏览器密钥并更改浏览器设置,可以执行任意命令,另外杀死特定进程 | –reboot |
| –cm=–enableupdate | 添加带有–cm=–fullupdate命令行开关的RUN键PDFEditorUpdater | 无 |
| –cm=–disableupdate | 移除RUN键PDFEditorUpdater | 无 |
| –cm=–backupupdate | 轮询服务器要执行的操作,这些操作允许除其他外下载额外的恶意软件、数据泄露和注册表更改,命令行开关通常通过重复计划任务运行 | –ping |
AppSuite将许多看似无害的命令行参数转换为所谓的"wc例程":–install、–ping、–check、–reboot、–cleanup。我们认为这些可能是原始的命令行开关,被包装成更无害的命令。它们代表了后门的核心例程,我们将在以下部分描述。
图4:命令行开关的处理
除了–c开关外,所有其他命令行开关都会创建主后门代码的实例并运行它。在后门代码之后,名为mode.data的文件切换是否显示GUI或应用程序是否静默。文件mode.data必须存在于"工作目录"中,即:
|
|
如果是这种情况,程序将打开一个图形用户界面(GUI),允许用户编辑PDF文件(参见图5)。GUI内部是一个浏览器窗口,打开URL hxxps://pdf-tool.appsuites(dot)ai/en/pdfeditor,用户代理为PDFFusion/93HEU7AJ。没有该特定用户代理,网站保持空白,可能是为了强制人们使用AppSuite程序而不是他们自己的浏览器。
由于PDF编辑是通过浏览器窗口完成的,pdfeditor.js代码的大部分专门用于后门和广告软件例程。在3661行去混淆代码中,只有17行打开浏览器窗口并因此运行诱饵应用程序。
图5:PDF编辑器的GUI实际上是一个浏览器窗口
后门例程–install
如果调用者没有提供任何命令行开关–c或–cm,后门会调用–install例程。脚本检查是否已有安装ID,在脚本中缩写为’iid’。此安装ID与其他设置一起保存在LOG1文件中,默认情况下为空。
如果没有安装ID,脚本检查SID是否存在。如果不存在,它通过UtilityAddon.node[3] DLL函数get_sid()获取。如果SID存在,它将通过向C2服务器注册应用程序继续,首先通过node-fetch在:
|
|
图6:在appsuites(dot)ai /api/s3/new上的Node-fetch请求
如果不起作用,它会尝试:
|
|
提供的版本是后门的硬编码版本。服务器响应一个JSON,提供安装ID。
后门将SID转换为十六进制字符串表示,并将安装ID和SID值保存到LOG1。在LOG1中,SID值称为’usid’,安装ID称为’iid’。
之后,无论获取SID和安装ID是否成功,pdfeditor.js还触发两个计划任务的创建:
- PDFEditorScheduledTask使用–cm=–partialupdate运行应用程序,触发–check例程一次
- PDFEditorUScheduledTask使用–cm=–backupupdate运行应用程序,重复触发–ping例程
图7:通过UtilityAddon.node创建计划任务
脚本调用UtilityAddon.node的导出函数来创建计划任务。如果导出函数mutate_task_schedule返回false,它会调用create_task_schedule和repeat_task_schedule,这些函数提供参数来启动一次–check和重复的–ping。
跟随mutate_task_schedule中的函数FUN_1800006940,两个十六进制值被类型转换为’IID *’(接口标识符),这是一个GUID结构(全局唯一标识符)。
这些十六进制数据转换为GUID时实际上是任务计划程序组件对象模型:
- c7a4ab2fa94d1340969720cc3fd40f85 {2FABA4C7-4DA9-4013-9697-20CC3FD40F85969720CC3FD40F85} COM接口ITaskService
- 9f36870fe5a4fc4cbd3e73e6154572dd {0F87369F-A4E5-4CFC-BD3E-73E6154572DDBD3E73E6154572DD} COM类Schedule.Service
图8:识别COM类和COM接口,两者都用于以编程方式管理Windows计划任务(点击放大)
图9:检查以下GUID上是否存在PDFEditorScheduledTask(点击放大)
函数mutate_task_schedule检查任务计划程序和计划任务类对象是否已有PDFEditorScheduledTask任务名,并相应地返回true或false。
create_task_schedule函数的第六个参数0x5a2(十进制1442)乘以600,000,000(100纳秒滴答),相当于1分钟,并添加到当前本地/系统时间,这将是计划任务的执行时间。这意味着使用–cm=–partialupdate开关的PDF Editor.exe的计划执行将在1天0小时2分钟后进行。
这种行为确保在自动沙箱系统中不显示可疑活动,这些系统通常不会等待一天来执行计划任务。
图10:UtilityAddon.node dll的create_task_schedule导出函数的反编译代码
后门例程–cleanup和感染修复
–cleanup例程通常从卸载程序调用,这是一个与程序一起分发的单独NSIS可执行文件。卸载程序确实会移除后门文件,可能是为了避免引起怀疑。毕竟,威胁行为者试图对潜在不受欢迎的判定提出上诉,可能希望我们无法去混淆代码而仅依赖动态分析。一个无法正常工作的卸载程序会破坏他们的上诉。
清理例程通过以下之一将其安装ID发送到远程服务器:
|
|
之后它删除两个计划任务PDFEditorScheduledTask和PDFEditorUScheduledTask。
此时您可能想知道官方的AppSuite卸载程序是否会完全修复感染。但这是一个谬误。首先,后门有时在–check或–reboot例程中创建额外的计划任务。其次,任何后门感染都为威胁行为者提供对系统的未经授权访问,这意味着他们可以安装额外的恶意软件和自动运行例程。第三,我们不信任卸载程序对所有版本的后门都按描述工作,因为威胁行为者创建了它。
由于这种未经授权的访问,任何成功联系命令和控制服务器的后门感染都应通过重新铺设系统来清理,这意味着格式化受影响的驱动器并重新安装操作系统。对于AppSuite,如果后门的计划任务已执行,则重新铺设是必要的。
图11:NSIS设置脚本显示在卸载期间设置–cm=–cleanup开关
后门例程–ping
–ping例程仅在程序已收到安装ID时工作。如果是这种情况,它构建一个ActionRequest对象(我们命名的对象名称),由以下字段组成:
- Progress
- Activity
- Session
- Timezone
- Version
- NextURL
- Value 包含列表:File、Reg、URL和Proc
后门使用AES-128-CBC加密加密此ActionRequest对象,使用0x10随机字节作为初始化向量或IV。后门从安装ID派生加密密钥。为此,它从安装ID字符串中移除所有’-‘字符,并通过将'276409396fcc0a23’与处理后的安装ID的前0x10字节连接来构建加密密钥。
然后该函数将四个魔术字节和大写的IV前置到加密缓冲区,并将其作为数据blob返回:
|
|
图12:用于AES-128-CBC加密和加密ActionRequest结构的去混淆代码(点击放大)
后门通过POST将此数据blob与’iid’作为参数一起发送到hxxps://on.appsuites(dot)ai/ping。
脚本使用AES-128-CBC解密服务器响应,再次使用安装ID派生密钥。消息的前0x20字节是IV。
后门将解密后的响应再次解包到ActionRequest对象中。ActionRequest.Value成员中的每个列表包含后门应执行的操作或活动。
- File – 文件相关操作列表
- Reg – 注册表相关操作列表
- Url – URL相关操作列表
- Proc – 进程相关操作列表
对于每个列表,脚本调用一个处理程序一个接一个地执行排队的操作。活动枚举确定执行哪种类型的操作。枚举具有以下值之一:
- EXISTS 0x1
- READ 0x2
- WRITE 0x3
- DELETE 0x4
- EXTRACT 0x5
以下函数可用于每个活动列表,由活动枚举控制:
| 活动列表 | 活动枚举 | 命令含义 |
|---|---|---|
| File | EXISTS | 检查文件或文件夹是否存在 |
| READ | 读取文件到十六进制字符串 | |
| WRITE | 写入文件 | |
| DELETE | 删除文件 | |
| EXTRACT | 提取chromium首选项 | |
| Reg | EXISTS | 检查注册表值是否存在 |
| READ | 读取注册表值 | |
| WRITE | 写入注册表值 | |
| DELETE | 删除注册表值 | |
| URL | WRITE | 下载并保存文件 |
| Proc | EXISTS | 检查进程是否存在并返回true或false |
| READ | 返回进程映像路径和存在标志 |
脚本通过调用UtilityAddon.node GetPsList()函数获取进程列表。
这些命令允许后门将额外的恶意软件加载到系统上,并通过注册表活动持久化或运行它。读取文件和注册表允许威胁行为者从系统泄露任何文件或设置。进程列表有助于评估哪些安全软件可能在系统上以及系统是真实的还是仅仅是分析沙箱。这样威胁行为者可以决定是否值得采取任何行动,如下载额外的恶意软件。
活动列表不允许任意命令执行;这反而是–check和–reboot核心例程的一部分。
后门例程–check和–reboot
对于–check和–reboot两个例程,后门调用相同的内部函数。如果提供了–reboot命令,后门将在稍后杀死某些进程,但其他所有内容对于–check和–reboot都是相同的。
首先,脚本通过验证文件的存在和最后修改时间来防止多次运行:
|
|
如果该文件比900,000毫秒(15分钟)新,后门将自行终止。如果文件较旧,它将删除state文件并继续。如果state文件不存在,后门创建该文件并向其中写入空字符串。
接下来,后门解码LOG0文件(如果存在)并将SID和安装ID复制到LOG1。然后检查LOG1中是否有安装ID,如果没有则中止。
之后它启动一个引导函数以从服务器获取选项配置。根据错误消息,该函数可能被恶意软件开发人员称为GetRtc。
图12:从服务器获取命令行模板的引导或GetRtc函数
引导函数使用硬编码的XOR混淆’e-key’值和安装ID来派生AES-256-CBC加密密钥。e-key值是:
|
|
密钥由以下组成:
|
|
然后函数使用先前派生的密钥加密安装ID、版本和’isSchedule’标志(设置为0)。后门将结果作为十六进制字符串保存在数据blob中。然后它通过POST将数据blob、安装ID和IV作为参数发送到hxxps://sdk.appsuites(dot)ai/api/s3/options。
C2服务器的响应是一个JSON对象,包含文件路径、设置和命令模板。除其他外,它包含Wave浏览器、Shift浏览器和OneLaunch配置文件和设置的路径。命令模板在代码的其他部分中使用,例如与cmd.exe或reg.exe一起执行。由于命令是通过从C2获取的选项配置设置的,后门有一种灵活的方式来动态调整其可用命令。坦率地说:这意味着AppSuite威胁行为者可能在受感染系统上执行任意命令。这也是我们将此恶意软件分类为后门而不仅仅是加载程序或窃取程序的主要原因。此时,后门的以下操作取决于提供的命令模板,但我们没有模板的情况下推断了一些含义。
后门检查Wave浏览器、Shift浏览器、OneLaunch和另外两个可配置路径是否存在于系统上,并相应地设置标志,如果应为这些应用程序创建计划任务或其他自动运行方法,这些标志将在稍后触发。这些计划任务的名称是ShiftLaunchTask、OneLaunchLaunchTask、WaveBrowser-StartAtLogin。
图13:命令模板和参数提供给字符串格式函数以创建最终命令并执行它。这里我们从解密的字符串及其使用推断,两个命令模板可能包含reg add和reg query命令
后门继续从服务器请求另一个配置,更具体地从:
|
|
这次服务器提供以下值的标志和字符串:
| 标志或字段 | 含义或目标 | 保存到LOG1的键 |
|---|---|---|
| wc | 如果设置为false,一次禁用下面所有标志的处理程序 | - |
| wcs | 对于Chromium浏览器:将pref和spref发送到C2,获取修改版本并写回 | c-key |
| 未使用 | - | - |
| wdc | 对于Chromium浏览器:将pref和spref发送到C2,获取修改版本并写回 | cw-key |
| wde | 对于Chromium浏览器:将pref和spref发送到C2,获取修改版本并写回 | ce-key |
| ol和ol_deep | 读取和写入OneLaunch设置和数据 | ol-key |
| wv和wv_deep | 读取和写入Wave浏览器设置和数据 | wv-key |
| sf和sf_deep | 读取和写入Shift浏览器设置和数据 | sf-key |
| pas和pas_deep | 可能OneLaunch密码管理器 | pas-key |
| code | 未使用 | - |
| reglist | 要添加的注册表键和值列表 | - |
除code和reglist外,所有先前的项目都是布尔标志。每个标志触发特定的处理程序函数,这意味着这些是由C2服务器提供的开关,可以打开或关闭某些功能。我们根据计划任务使用的字符串推断标志ol、wv、sf及其*_deep变体的含义。对于其他开关如wdc和wde,我们怀疑Edge和Chrome是目标。但我们不确定,因为它取决于选项配置及其命令模板。
当前样本中未使用code字段。reglist应该是后门应用于系统的注册表值列表。处理reglist的所有条目后,脚本调用标志的特殊处理程序。
wv、sd和ol的处理程序读取应用程序OneLaunch、Wave Browser和Shift Browser的设置文件并从中提取密钥。这些密钥作为ol-key、sf-key和wv-key保存在LOG1文件中。处理程序还为其相应的应用程序添加计划任务。
pas处理程序可能处理OneLaunch密码管理器。我们这样假设是因为与OneLaunch相关的注册表值。pas-key也保存到LOG1文件。
wdc、wcs和wde的处理程序针对基于Chromium的浏览器。每个处理程序可能针对这些浏览器的不同风格,例如Edge或Chrome。它们将pref和spref文件发送到服务器,从服务器获取修改版本并写回。它们对浏览器缓存文件执行自定义查询并将结果发送到服务器。此外,处理程序获取profile.info_cache和保存的os_crypt.encrypted_key值,并使用UtilityAddon.node的GetOsCKey()函数解码它们。获取的密钥保存在LOG1中,名称为c-key(对于wcs)、cw-key(对于wdc)和ew-key(对于wde)。
总之,这些处理程序允许后门查询、泄露和操纵这些浏览器的任何数据或设置,包括保存的凭据、浏览器历史记录、cookie或设置自定义搜索引擎。
图14:wcs处理程序同步Chromium pref和spref文件并应用注册表值列表。
事件日志记录
AppSuites有一个事件日志记录机制,具有68个事件代码和三个日志级别。它将所有执行步骤和任何异常发送到服务器。
事件对象具有以下值:
- bid – 编解码器
- c – 上下文信息
- e – 异常对象的字符串表示
- i – 安装ID(iid)或字符串’initialization’(如果尚不存在)
- l – 日志级别,INFO(1)、ERROR(-1)或DEBUG(0)
- m – 68个事件代码之一
- p – 含义未知的标志,当前始终设置为1
- s – 当前命令字符串
- v – 版本字符串
c中的上下文信息是列表的字符串表示,其中每个元素由’|‘分隔。事件记录器将布尔值转换为字符'1’或'0’。上下文用于提供附加信息,例如,AppSuite在发生异常时尝试解析的JSON对象。
此事件对象使用AES-256-CBC加密,使用e-key的前0x18字节后跟安装ID的前0x8字节作为密钥。如果安装ID尚不存在,脚本使用字符串’initialization’代替。
后门通过POST请求将加密的数据blob、IV(初始化向量)和安装ID作为参数发送到hxxps://appsuites(dot)ai/api/s3/event。
LOG1和LOG0的取证价值
LOG1和LOG0驻留在以下文件夹中:
|
|
LOG1是一个编码的JSON文件,保存安装ID(‘iid’)、SID(‘usid’)、后门特定加密密钥(’e-key’)和浏览器密钥(‘c-key’、‘wv-key’、‘sf-key’、‘ol-key’、‘cw-key’、‘pas-key’)。
默认情况下只有size有值,任何其他值最初为空,可能在执行后门期间稍后添加。
我们创建了以下Python脚本来解码LOG1:
|
|
解码的LOG1告诉分析人员后门是否已收到安装ID以及是否提取了应用程序密钥。
LOG0不是直接在代码中创建的。它的唯一引用是从–check和–reboot例程调用的函数,并将’usid’(SID)和’iid’(安装ID)值从LOG0复制到LOG1。我们怀疑恶意软件开发人员可能将其用于本地调试,因为在大多数后门代码正确执行之前需要安装ID。使用LOG0文件,开发人员可以立即设置安装ID和SID,而不必等待服务器的响应。
它也可能是通过后门的文件下载操作远程更改这些值的一种方式,而不会在程序运行时引起任何同步问题。
恶意软件分类与OneStart的关系
我们的观点毫无疑问:AppSuite PDF Editor是恶意的。它是一个经典的特洛伊木马,带有后门,目前被大量下载。例如,上周我们在遥测中看到28,689次下载尝试。
我们早早在社交媒体如X、LinkedIn、Bluesky和Mastodon上宣布了我们的发现(见[P4]、[P5])。尽管如此,许多安全供应商将程序分类为潜在不受欢迎应用程序而不是恶意软件。潜在不受欢迎也意味着软件有时是需要的。是的,AppSuite包括一个正常工作的PDF编辑器,但谁会明知故犯地用它交换一个后门?我们希望本文改变这种看法。
一些安全专家指出了AppSuite和OneStart PDF Editor之间的联系,表明相同的威胁行为者在两个应用程序背后[P1,P2]。在现阶段,我们既不能确认也不能排除这种联系。然而,清楚的是,两个程序在代码库上不同,OneStart需要自己专门的分析。
AppSuite威胁行为者将其恶意软件作为误报提交的大胆行为并非孤立事件。最近几周,我们有多起威胁行为者挑战我们判定的尝试,同时冒充合法软件发布者。安全供应商必须意识到这种策略并对此类文件保持怀疑。
毫无疑问的是:免费的PDF编辑器非常受欢迎,如果最令人信服的选项来自威胁行为者,我们确实有一个问题。
相关社交媒体帖子
[P1] https://x.com/SquiblydooBlog/status/1959991434893046101 [P2] https://x.com/SquiblydooBlog/status/1958247261055725891 [P3] https://x.com/TeamDreier/status/1959370588599787956 [P4] https://x.com/struppigel/status/1958184871207047257 [P5] https://www.linkedin.com/feed/update/urn:li:activity:7363954525402984448/
危害指标
以下文件和URL是我们分析的基础,并揭示了下面的文件位置和持久化指标。
此外,我们为研究人员提供去混淆脚本[7]。我们手动重命名了函数和变量名,因此它们不应用作检测签名的基础。样本的大多数字符串在原始文件中加密,并且仅出现在内存中。
安装位置
|
|
样本哈希值
[1] MSI: fde67ba523b2c1e517d679ad4eaf87925c6bbf2f171b9212462dc9a855faa34b [2] pdfeditor.js: b3ef2e11c855f4812e64230632f125db5e7da1df3e9e34fdb2f088ebe5e16603 [3] UtilityAddon.node: 6022fd372dca7d6d366d9df894e8313b7f0bd821035dd9fa7c860b14e8c414f2 [4] PDFEditorSetup.exe: da3c6ec20a006ec4b289a90488f824f0f72098a2f5c2d3f37d7a2d4a83b344a0 [5] PDF Editor.exe: cb15e1ec1a472631c53378d54f2043ba57586e3a28329c9dbf40cb69d7c10d2c [6] Uninstall PDF Editor.exe: 956f7e8e156205b8cbf9b9f16bae0e43404641ad8feaaf5f59f8ba7c54f15e24 [7] 去混淆pdfeditor.js: 104428a78aa75b4b0bc945a2067c0e42c8dfd5d0baf3cb18e0f6e4686bdc0755
持久化值和用户代理
- 用户代理 - PDFFusion/93HEU7AJ
- 计划任务1 – PDFEditorScheduledTask 执行
%USERPROFILE%\PDF Editor\PDF Editor.exe --cm=--partialupdate - 计划任务2 – PDFEditorUScheduledTask 执行
%USERPROFILE%\PDF Editor\PDF Editor.exe --cm=--backupupdate - 计划任务3 – ShiftLaunchTask
- 计划任务4 – OneLaunchLaunchTask
- 计划任务5 – WaveBrowser-StartAtLogin
- RUN键PDFEditorUpdater 值
%USERPROFILE%\PDF Editor\PDF Editor.exe
C2 URL
- hxxps://appsuites(dot)ai
- hxxps://sdk.appsuites(dot)ai
- hxxps://log.appsuites(dot)ai
- hxxps://on.appsuites(dot)ai
下载URL
- hxxps://vault.appsuites(dot)ai/AppSuite-PDF-1.0.28.exe
- [D1] hxxps://pdfmeta(dot)com
- [D2] hxxps://pdfartisan(dot)com
- [D3] hxxps://appsuites(dot)ai
- [D4] hxxps://pdfreplace(dot)com