執行摘要
Slow Pisces(又名 Jade Sleet、TraderTraitor、PUKCHONG)是北韓國家支持的威脅組織,主要著重於為北韓政權創造財政收入,通常以加密貨幣領域相關的大型組織為攻擊目標。本文分析他們的活動,我們認為這與最近的加密貨幣搶劫案有關。
在此活動中, Slow Pisces 在 LinkedIn 上與加密貨幣開發人員接洽,冒充潛在雇主,並傳送偽裝成「編碼挑戰」的惡意軟體。這些挑戰需要開發人員執行已經遭到惡意植入的專案案,進而在系統上安裝我們命名為 RN Loader 和 RN Stealer 的惡意軟體。
據報導,該組織在 2023 年從加密貨幣產業竊取超過 10 億美元。他們使用各種方法達成此目標,包括虛假的交易應用程式、透過節點套件管理員 (Node Package Manager ,NPM) 散佈的惡意軟體,以及供應鏈攻擊。
2024 年 12 月,一家日本加密貨幣公司的 3.08 億美元失竊案被FBI 將歸咎 於 Slow Pisces。最近,該組織因涉嫌參與一起杜拜加密貨幣交易所高達 15 億美元的盜竊案 而成為頭條新聞。
針對這波行動,我們已將威脅情報分享給 GitHub 和 LinkedIn 的分析團隊,以協助下架攻擊者的相關帳號和惡意程式碼儲存庫。
他們提供以下聲明作為回應:
GitHub 和 LinkedIn 因這些惡意帳戶違反各自的服務條款而將其移除。在我們所有的產品中,我們使用自動化技術,結合調查專家團隊和使用者舉報機制來打擊不良行為者和強制執行服務條款。我們將不斷地優化和改善我們的流程,並鼓勵我們的客戶和會員用戶主動舉報任何可疑的活動。
其他資訊
- GitHub 使用者可以參考在我們的 可接受使用政策和 舉報濫用和垃圾郵件頁面以獲得更多資訊。
- LinkedIn 使用者可在此瞭解更多關於識別和報告濫用的資訊:識別和報告垃圾郵件、不當和濫用內容 | LinkedIn 說明。
本報告詳細介紹 Slow Pisces 如何將惡意軟體隱藏在其發送的編碼挑戰中,並描述該團體的後續工具,目的是讓更多業界人士更了解此威脅。
透過我們的具有進階 URL 篩選和進階 DNS 安全性訂閱的新一代防火牆,Palo Alto Networks 客戶可以更好地免受本文討論的威脅。
如果您認為自己可能已受到危害或有緊急情況,請聯絡 Unit 42 事件回應團隊.
相關 Unit 42 課題 | Cryptocurrency, DPRK |
技術分析
我們對這項活動的可視性大致遵循三個步驟,如下圖 1 所示。

第 1 階段 - PDF 誘餌
Slow Pisces 一開始在 LinkedIn 上冒充招聘人員與潛在目標接觸,並傳送一份看似無害的 PDF 檔案給他們,內容是一份工作職缺的描述,如下圖 2 所示。如果潛在目標提出申請,攻擊者就會向他們提出編碼程式挑戰作為應徵的一部分,其中包括多個任務或題目,要求應徵者在本地端下載並執行專案程式碼。

我們觀察到 Slow Pisces 冒充多個企業組織進行這些誘騙,這些組織主要是在加密貨幣領域。攻擊者提供的城市挑戰說明文件包括一般的軟體開發任務和一個「真實專案」的編碼挑戰,並連結到下圖 3 所示的 GitHub 程式碼儲存庫。

第 2 階段 - GitHub 儲存庫
Slow Pisces 以 GitHub 程式碼儲存庫中的專案為目標,提出所謂的編碼挑戰。程式碼儲存庫包含改編自開放源碼專案的程式碼,其表面功能是用來檢視和分析下列類型的資料:
- 股票市場資訊
- 歐洲足球聯賽的統計資料
- 天氣數據
- 加密貨幣價格
攻擊者主要使用 Python 或 JavaScript 的專案,推測是根據受害者申請的職務類型來調整,分別對應前端或後端開發者的技能偏好。我們在曾經在這次活動中也看到少數以 Java 為基礎的儲存庫案例,,其中兩個帳號冒充了一個名為 jCoin 的加密貨幣應用程式。
這種顯示攻擊者可能會依據目標偏好的程式語言,按需要來建立儲存庫。因此,該團體更常使用在加密貨幣領域更受歡迎的語言,例如 JavaScript 和 Python。因此我們合理推測還可能存在尚未被發現的、使用其他程式語言的惡意儲存庫
階段 3a - Python 儲存庫
2024 年底,該小組使用下圖 4 所示的專案,標題為「Stocks Pattern Analyzer」,其程式碼大多改編自合法的開源儲存庫。

程式碼儲存庫中的大部分程式碼都是看似正常無害的。當目標嘗試根據問題表執行專案時,程式會從三個遠端位置擷取資料:
- hxxps://en.wikipedia[.]org/wiki/List_of_S%26P_500_companies
- hxxps://en.wikipedia[.]org/wiki/Currency_pair
- hxxps://en.stockslab[.]org/symbols/sp500
其中兩個 URL 從 Wikipedia 的合法網址取得資料。第三個 URL 使用由 Slow Pisces 控制的惡意網域。這種「混合合法與惡意來源」的手法,是該組織在 Python 攻擊儲存庫中很常見的模式。
為了提高隱匿性,這個惡意的命令與控制 (C2) 伺服器被設定為模仿合法來源的格式。在這種情況下,其使用 .en 子域和 .org 頂層網域 (TLD),就像我們在上面看到的合法維基百科網域一樣。
YAML 反序列化攻擊 (Deserialization)
Slow Pisces 可以簡單地直接將惡意軟體置入程式碼儲存庫,或使用 Python 內建的 eval 或 exec 函數執行 C2 伺服器上的程式碼。然而,這些技術很容易被偵測出來容易被人工審查或防毒引擎識別。
取而代之的方法是,Slow Pisces 會先確保 C2 伺服器回應看似正常的應用程式資料。例如 S&P 500 公司的代號清單,格式為標準的 JSON。
只有當確認連線者是預期的攻擊對象,(很可能是根據 IP 位址、地理位置、時間和 HTTP 請求標頭),C2才會發送真正的惡意載荷。相較於廣泛的網路釣魚活動,攻擊者專注於透過 LinkedIn 聯繫的個人,讓該組織可以嚴格控制攻擊流程,並只向預期的受害者傳送載荷。
為了避免可疑的 eval 和 exec 函數,Slow Pisces 使用 YAML 反序列化來執行其載荷,如圖 5 所示。

此程式碼透過 HTTPS 從 C2 伺服器取得資料,並檢查 Content-Type 回應標頭。如果標頭指示 JSON 資料(application/json),程式碼會解析並將 JSON 傳回給應用程式。
如果回應顯示 YAML 資料(application/yaml),程式碼會使用 PyYAML 套件中的 yaml.load() 函數來解析資料。這個函數本質上是不安全的,PyYAML 官方文件明確建議 針對不可信的輸入應該使用yaml.safe_load(),以避免執行任意程式碼。
YAML 通常用於撰寫設定檔,例如下圖所示的範例:
1 2 3 4 5 6 7 8 9 |
使用者名稱: slow 密碼: pisces api: 關鍵字: 超級機密 url: example.com |
然而, yaml.load() 可以還原(deserialize)任意的 Python 物件,而不僅限於純粹的的 YAML 格式資料。舉例來說,以下 Python 程式碼會列印數字 0-4:
1 |
range(0, 5) |
如果使用 yaml.dump() 將此程式碼序列化,則會變成以下內容:
1 2 3 4 5 6 7 |
!!python/object/apply:builtins.range - 0 - 5 - 1 |
當這些資料傳給 yaml.load() 時,它會執行原始程式碼:range(0, 5)。
這類攻擊手法突顯一個行為特徵點:若惡意的YAML載荷使用Python內建函式,則 反序列化的惡意軟體就會包含 !!python/object/apply:builtins。
表 1 中的下列階段主要存在於記憶體中(in-memory),通常不會在硬碟上留下任何足跡。為了協助資安社群偵測和提高警覺,我們已將這些載荷上傳至 VirusTotal。YAML 反序列化載荷會執行我們根據在 RN Stealer 中觀測到的 C2 權仗格式而命名為 RN Loader 和 RN Stealer 的惡意軟體,我們會在下文討論。
階段 | SHA256 雜湊 |
YAML 反序列化承載 | 47e997b85ed3f51d2b1d37a6a61ae72185d9ceaf519e2fdb53bf7e761b7bc08f |
RN Loader | 937c533bddb8bbcd908b62f2bf48e5bc11160505df20fea91d9600d999eafa79 |
RN Stealer | e89bf606fbed8f68127934758726bbb5e68e751427f3bcad3ddf883cb2b50fc7 |
表 1.Python 儲存庫承載。
Slow Pisces 的攻擊鏈中, YAML 反序列化載荷首先會在受害者的主目錄中建立一個名為 Public的資料夾,並在該目錄中建立一個名為 __init__ .py 的新檔案。這個檔案包含了經過 Base64 解碼的資料,這些資料構成了下個階段的惡意程式 (RN Loader),並會立刻被執行。
RN Loader
這個新建立的 RN Loader 檔案位於 ~/Public/__init__.py,會在執行後自行刪除以確保它只存在於記憶體中。它會透過 HTTPS 將受害機器和作業系統的基本資訊傳送至 en.stockslab[.]org 的同一個 C2,接著是一個命令迴圈,其中包含表 2 中的下列選項。
代碼 | 說明 |
0 | 睡眠 20 秒 |
1 | 對傳送的內容進行 Base64 解碼,並將其儲存至 Windows 的 init.dll 檔案或所有其他作業系統的 init 檔案。
設定環境變數 X_DATABASE_NAME 為空白字串。 使用 ctypes.cdll.LoadLibrary 載入並執行下載的 DLL。 |
2 | Base64 解碼傳送的內容,並使用 Python 內建的 exec 執行。 |
3 | 對傳送內容和參數進行 Base64 解碼。內容會儲存到 dockerd 檔案,而參數則儲存為 docker-init。
然後,dockerd 會在一個新的進程中執行,並提供 docker-init 作為命令列的參數。 |
9 | 終止執行。 |
表 2.RN Loader 指令表。
表 2 中使用選項 1 和選項 3 的指令迴圈的承載目前尚不清楚,很可能是由特定條件觸發。然而,我們復原一個由選項 2 傳送的 Python-based 資訊竊取程式,我們將此惡意軟體追蹤為 RN Stealer。
RN Stealer
RN竊取程式首先會產生一個隨機受害者 ID,隨後在與 C2 伺服器的所有通訊中作為 Cookie 使用。然後,它會向伺服器請求 XOR 金鑰,以加密外洩的資料。
與 C2 伺服器的通訊透過 HTTPS 進行,使用 Base64 編碼權仗來識別要求和回應類型。分析的承載包括四種權杖類型:
- R0 - 請求 XOR 金鑰
- R64 - 資料外洩
- R128 - 竊取壓縮資料
- R256 - 資訊竊取完成
這些權杖類型的格式—字母 R 跟整數 N—導致我們為此載荷命名。我們稱承載為 RN Stealer,前一階段為 RN Loader。
我們從 macOS 系統中復原這個 RN Loader 範例的指令碼。因此,威脅作者量身打造此範例,以竊取 MacOS 裝置的特定資訊,包括
- 受害者基本資訊:使用者名稱、機器名稱和架構
- 已安裝的應用程式
- 目錄清單和受害者主目錄的頂層內容
- 在 macOS 系統中儲存已儲存憑證的 login.keychain-db 檔案
- 儲存的 SSH 金鑰
- 適用於 AWS、Kubernetes 和 Google Cloud 的組態檔案
RN Stealer 收集的資料可能會決定是否需要持續存取。如果是的話,我們可以推斷這個 Python 感染鏈的步驟如下:
- C2 伺服器會根據未知標準檢查指標受害者。有效的受害者會收到 YAML 反序列化載荷。無效的受害者會收到無害的 JSON 資料。
- 解序列化載荷會與 C2 伺服器建立指令迴圈,滲透受害者的基本資訊,並透過表 2 中的選項代碼 2 傳送自訂 Python 資訊竊取程式。
- 資訊竊取程式會收集更詳細的受害者資訊,攻擊者很可能利用這些資訊來決定是否需要不斷地存取。
- 如果需求不斷地存取,C2 伺服器會透過選項代碼 1 或 3 傳送承載。
- 如果不再需要存取權限,選項代碼 9 會終止惡意軟體的執行,移除所有存取權限,因為承載只存在於記憶體中。
第 3b 階段 - JavaScript 儲存庫
如果目標受害者申請的是 JavaScript 職缺,他們可能會遇到「加密貨幣儀表板(Cryptocurrency Dashboard)」專案,類似於下圖 6 的範例。

此應用程式包含一個 .env 設定檔案,裡面定義了 C2 和合法的資料來源:
- PORT=3000
- COINGECKO_API_URL=hxxps://api.coingecko[.]com/api/v3
- JQUERY_API_URL=hxxps://update.jquerycloud[.]io/api/v1
COINGECKO_API_URL 值用於擷取加密貨幣儀表板的資料,而 JQUERY_API_URL 值則代表由 Slow Pisces 所控制的 C2 伺服器。與 Python 儲存庫相似,JavaScript C2 伺服器只會將載荷傳送給已驗證的目標,否則只會回傳一個版本號碼。
此儲存庫使用嵌入式 JavaScript (EJS) 模板工具,並將 來自C2 伺服器的回應傳送至 ejs.render() 函式,如下圖 7 所示。

這種用法與 yaml.load()一樣,是 Slow Pisces 用來隱藏來自 C2 伺服器執行任意程式碼的另一種技術,而且這種方法可能只有在檢視有效的載荷時才會顯現出來。
EJS render 函數接受各種參數,其中之一稱為檢視選項(view options)。在此物件內,可以透過escapeFunction 鍵來提供並執行任意 JavaScript 程式碼。
台灣研究人員 Huli 在 CTF 發表的文章中討論過這個漏洞如何導致任意程式碼執行的技術細節。不過,我們可以充分了解的是,如圖 8 所示結構的 payload 在傳給 ejs.render() 時,位於escapeFunction 中的程式碼被執行。

不幸的是,我們無法完全還原這個惡意載荷的全部內容。因此,我們只能推測其行為,包括使用者的主目錄下會建立一個新的 .jql目錄 ,並在其中放置一個名為 helper.js 的檔案,內容為 Base64 編碼的資料。
基礎建設
下圖 9 中的時間軸詳述 2024 年 2 月至 2025 年 2 月這場行動中所使用的 C2 基礎架構,並按所支援的儲存庫類型 (JavaScript 或 Python) 分類。

如前所述,此活動基礎架構中的網域名稱,常仿效其搭配使用的合法資料來源格式,例如 api 或 cdn等子網域。截至本文發表前,我們至今仍持續發現與此攻擊活動相關的基礎建設。
總結
本報告介紹了 Slow Pisces 近期的攻擊活動,透過 LinkedIn 冒充招聘人員,針對加密貨幣領域的開發人員進行惡意的編碼挑戰。雖然我們無法復原 JavaScript 儲存庫的完整攻擊鏈,但 Python 版本的活動提供兩個新的惡意載荷,我們將其命名為 RN Loader 和 RN Stealer。
以這種方式使用 LinkedIn 和 GitHub 並非獨一無二。多個隸屬於朝鮮的團體,例如 Alluring Pisces 和 Contagious Interview也使用了類似的手段。
這些組織在運作上沒有實際的行動重疊。然而,值得注意的是,這些活動使用類似的初始感染方式。
Slow Pisces 在作業安全方面與其他組織相比更為出色。每個階段的載荷傳送都受到嚴密的控管,多數只存在於記憶體中。而該集團的後期工具也只會在必要時才會部署。
該小組特別使用兩種隱藏功能的技術:
- YAML 反序列化
- EJS的 escapeFunction
這兩種技術都會大大妨礙分析、偵測和追捕工作的難度。同樣地,加密貨幣領域中相對較新或經驗較淺的開發人員也很難將這些儲存庫識別為惡意儲存庫。
根據有關加密貨幣竊案的公開報告,這項活動似乎非常成功,而且很可能在 2025 年持續下去。雖然這篇文章強調 YAML deserialization 和 EJS escapeFunction 荷載的兩個潛在偵測機會,但最有效的緩解方法仍然是嚴格分隔公司和個人裝置的使用。這將有助於防止企業系統受到有針對性的社交工程攻擊。
Palo Alto Networks 保護和緩解功能
Palo Alto Networks 客戶可透過下列產品,更好地保護免受上述威脅:
如果您認為自己可能已受到攻擊或有緊急情況,請聯絡 Unit 42 事件回應團隊或致電
- 北美洲:免費電話:+1 (866) 486-4842 (866.4.unit42)
- 英國:+44.20.3743.3660
- 歐洲和中東:+31.20.299.3130
- 亞洲:+65.6983.8730
- 日本:+81.50.1790.0200
- 澳洲:+61.2.4062.7950
- 印度:00080005045107
Palo Alto Networks 跟我們的 Cyber Threat Alliance (CTA) 同業分享這些發現。CTA 會員利用這些情報,迅速為客戶部署保護措施,並有系統地瓦解惡意的網路行為者。進一步瞭解 Cyber Threat Alliance.
入侵指標
網域 | IP 位址 | 初見 | 最後看到 | 儲存庫 |
getstockprice[.]com | 70.34.245[.]118 | 2025-02-03 | 2025-02-20 | Python |
cdn[.]clubinfo[.]io | 5.206.227[.]51 | 2025-01-21 | 2025-02-19 | Python |
getstockprice[.]info | 131.226.2[.]120 | 2025-01-21 | 2025-01-23 | Python |
api[.]stockinfo[.]io | 136.244.93[.]248 | 2024-10-30 | 2024-11-11 | Python |
cdn[.]logoeye[.]net | 54.39.83[.]151 | 2024-10-29 | 2024-11-03 | Python |
en[.]wfinance[.]org | 195.133.26[.]32 | 2024-10-12 | 2024-11-01 | Python |
en[.]stocksindex[.]org | 185.236.231[.]224 | 2024-09-11 | 2024-10-04 | Python |
cdn[.]jqueryversion[.]net | 194.11.226[.]16 | 2024-08-23 | 2024-09-23 | JavaScript |
en[.]stockslab[.]org | 91.103.140[.]191 | 2024-08-19 | 2024-09-12 | Python |
update[.]jquerycloud[.]io | 192.236.199[.]57 | 2024-07-03 | 2024-08-22 | JavaScript |
cdn[.]soccerlab[.]io | 146.70.124[.]70 | 2024-08-07 | 2024-08-21 | Python |
api[.]coinpricehub[.]io | 45.141.58[.]40 | 2024-05-06 | 2024-08-06 | Java |
cdn[.]leaguehub[.]net | 5.133.9[.]252 | 2024-07-15 | 2024-07-21 | Python |
cdn[.]clublogos[.]io | 146.19.173[.]29 | 2024-06-24 | 2024-07-12 | Python |
api[.]jquery-release[.]com | 146.70.125[.]120 | 2024-06-10 | 2024-06-28 | JavaScript |
cdn[.]logosports[.]net | 185.62.58[.]74 | 2024-05-08 | 2024-06-23 | Python |
skypredict[.]org | 80.82.77[.]80 | 2024-05-06 | 2024-06-16 | JavaScript |
api[.]bitzone[.]io | 192.248.145[.]210 | 2024-04-25 | 2024-05-13 | Python |
weatherdatahub[.]org | 194.15.112[.]200 | 2024-04-05 | 2024-05-03 | JavaScript |
api[.]ethzone[.]io | 91.234.199[.]90 | 2024-04-16 | 2024-04-24 | Python |
api[.]fivebit[.]io | 185.216.144[.]41 | 2024-04-08 | 2024-04-14 | Python |
blockprices[.]io | 91.193.18[.]201 | 2024-03-15 | 2024-04-09 | JavaScript |
api[.]coinhar[.]io | 185.62.58[.]122 | 2024-03-26 | 2024-04-09 | Python |
mavenradar[.]com | 23.254.230[.]253 | 2024-02-21 | 2024-03-26 | JavaScript |
indobit[.]io | 146.70.88[.]126 | 2024-03-19 | 2024-03-20 | Python |
api[.]thaibit[.]io | 79.137.248[.]193 | 2024-03-07 | 2024-03-09 | Python |
chainanalyser[.]com | 38.180.62[.]135 | 2024-02-23 | 2024-03-06 | JavaScript |
其他資源
- 北韓對價值 15 億美元的 Bybit 駭客行為負責 - 網際網路犯罪申訴中心 (IC3)
- FBI、DC3 和 NPA 識別北韓網路騙徒,追蹤其為 TraderTraitor,對 Bitcoin.DMM.com 3.08 億美元失竊案負責 – 聯邦調查局
- 安全警示:社會工程活動針對科技產業員工 - GitHub 部落格
- 北韓利用 SaaS 供應商進行針對性的供應鏈攻擊 - Mandiant、Google 雲端