สรุปสั้น

บริษัท Socket ผู้ให้บริการด้านความปลอดภัยซัพพลายเชนซอฟต์แวร์ เปิดเผยผลวิเคราะห์ว่าแพ็กเกจ npm สองตัวใน namespace @joyfill ถูกฝังโค้ดอันตรายไว้ในรุ่นเบต้า ได้แก่ @joyfill/layouts@0.1.2-2773.beta.0 และ @joyfill/components@4.0.0-rc24-2773-beta.4 โดยโค้ดดังกล่าวเป็น import-time JavaScript implant ที่ทำงานทันทีเมื่อ Node.js โหลด entry point ของแพ็กเกจแบบ CommonJS ไม่ได้อาศัย lifecycle hook ช่วงติดตั้งเหมือนมัลแวร์ npm ทั่วไป จึงหลุดรอดเครื่องมือที่จับพฤติกรรมเฉพาะตอนติดตั้งได้ง่าย ปลายทางของห่วงโซ่การโจมตีคือโทรจันควบคุมระยะไกลที่มีลักษณะใกล้เคียงมัลแวร์ตระกูล DEV#POPPER ซึ่งเป็นเครื่องมือประจำของกลุ่มภัยคุกคามเกาหลีเหนือ

จุดที่ทำให้แคมเปญนี้ต่างจากมัลแวร์แพ็กเกจทั่วไปคือการใช้บล็อกเชนสามเครือข่ายเป็นตัวกลางในการส่งคำสั่งและเพย์โหลด ทั้ง Tron, Aptos และ BNB Smart Chain โดยโครงสร้างแบบหลายชั้นนี้ถูกเชื่อมโยงกับคลัสเตอร์ภัยคุกคามที่ติดตามในชื่อ PolinRider ซึ่งประเมินว่าอยู่ในเครือปฏิบัติการ Contagious Interview การเก็บโค้ดไว้ในธุรกรรมบล็อกเชนทำให้ผู้โจมตีเปลี่ยนเพย์โหลดได้ตลอดเวลาโดยไม่ต้องเผยแพร่แพ็กเกจเวอร์ชันใหม่ และทำให้การถอดโครงสร้างพื้นฐาน C2 ทำได้ยากกว่าการใช้โดเมนหรือไอพีปกติ นอกจากโทรจันแล้ว ยังพบอินโฟสตีลเลอร์ภาษา Python ที่ประเมินว่าเป็นรุ่นพัฒนาต่อของ OmniStealer กวาดข้อมูลรับรองจาก Windows Credential Manager, เบราว์เซอร์, ส่วนขยายประเภทกระเป๋าคริปโต, Git และ GitHub CLI ไปด้วย

บริษัท Socket ระบุว่าเวอร์ชันอันตรายทั้งสองถูกเผยแพร่ด้วยตัวตน npm เดียวกัน และโค้ดอันตรายฝังอยู่ตั้งแต่ขั้นตอนสร้าง bundle แต่ยังไม่ชัดเจนว่าการแทรกโค้ดเกิดจากการยึดเครื่องนักพัฒนา ยึดซอร์สรีโพซิทอรี ยึดระบบ CI หรือขโมยข้อมูลรับรองสำหรับเผยแพร่แพ็กเกจ ทีมที่เคยติดตั้งเวอร์ชันดังกล่าวจึงต้องถือว่าทุกกระบวนการที่โหลดแพ็กเกจนี้มีโอกาสถูกรันโค้ดตามอำเภอใจไปแล้ว

รายละเอียดข่าว

เว็บไซต์ The Hacker News รายงานเมื่อวันที่ 29 กรกฎาคม 2569 ว่าแพ็กเกจ npm รุ่นเบต้าสองตัวใน namespace @joyfill ถูกดัดแปลงให้ส่งมอบโทรจันควบคุมระยะไกลที่เกี่ยวข้องกับมัลแวร์ตระกูล DEV#POPPER โดยอ้างอิงรายงานวิเคราะห์ของบริษัท Socket ซึ่งระบุว่าแพ็กเกจทั้งสอง “มี import-time JavaScript implant ที่คลี่โค้ดซึ่งถูกเข้ารหัสไว้ผ่านธุรกรรมบนเครือข่าย Tron, Aptos และ BNB Smart Chain”

รายงานชี้ว่ารูปแบบ resolver แบบหลายบล็อกเชนนี้เคยถูกเชื่อมโยงกับคลัสเตอร์ PolinRider มาก่อน และเมื่อต้นเดือนกรกฎาคม 2569 บริษัท Checkmarx ร่วมกับโครงการ OpenSourceMalware ก็เคยเปิดโปงชุดแพ็กเกจ npm อันตรายที่เรียกรวมกันว่า ViteVenom ซึ่งเล็งเป้าระบบนิเวศเครื่องมือ frontend อย่าง Vite และใช้โครงสร้าง C2 บนบล็อกเชนแบบเดียวกันเพื่อส่งโทรจันที่เปิด reverse shell เก็บข้อมูลรับรอง ส่งไฟล์ออกนอกเครือข่าย และฝังแบ็กดอร์ถาวรได้

บริษัท Socket ให้ข้อมูลกับ The Hacker News เพิ่มเติมว่า ทั้งแคมเปญ ViteVenom และชุดแพ็กเกจ npm ล่าสุดนี้เป็นส่วนหนึ่งของปฏิบัติการเดียวกันที่ดำเนินการโดยกลุ่มภัยคุกคามเกาหลีเหนือ ไม่ใช่แคมเปญที่แยกจากกัน หลักฐานที่สนับสนุนคือทั้งสองเวอร์ชันถูกเผยแพร่จากตัวตน npm เดียวกัน สร้างด้วย Node.js 18.20.0 และ npm 10.5.0 และพบโค้ดอันตรายอยู่แล้วตั้งแต่ขั้น bundle

ผู้ที่ตกเป็นเป้าหมายโดยตรงคือนักพัฒนาและระบบอัตโนมัติ เพราะโค้ดจะทำงานเมื่อแพ็กเกจถูกโหลด ไม่ว่าจะเป็นเครื่องนักพัฒนา, CI runner, เครื่องมือทดสอบ, การเรนเดอร์ฝั่งเซิร์ฟเวอร์ หรือกระบวนการ build บริษัท Socket ระบุตรง ๆ ว่า “เวอร์ชันของ @joyfill/layouts ที่ปล่อยออกมาควรถูกปฏิบัติเสมือนว่าสามารถรันโค้ดตามอำเภอใจในบริบทของกระบวนการใดก็ตามที่โหลดมัน”

สิ่งที่โค้ดปลายทางทำได้ครอบคลุมตั้งแต่เก็บข้อมูลเครื่อง เปิดช่องควบคุมระยะไกลผ่าน Socket.IO รันคำสั่ง JavaScript หรือคำสั่งเชลล์ที่ผู้โจมตีส่งมา อัปโหลดไฟล์ อ่านข้อมูลในคลิปบอร์ด ไปจนถึงแก้ไขไฟล์ที่เป็นของเครื่องมือนักพัฒนา ส่วนคำแนะนำเร่งด่วนที่บริษัท Socket ให้ไว้คือถอนเวอร์ชันที่ติดเชื้อออกจาก lockfile แคช mirror ภายใน build image และ deployment artifact แล้วหมุนเปลี่ยนข้อมูลรับรองทั้งหมดที่กระบวนการ Node.js นั้นเข้าถึงได้

วิธีการโจมตี

implant ที่ฝังอยู่ในแพ็กเกจแบ่งการทำงานออกเป็นสองสายคู่ขนาน สายแรกเป็น in-process branch ที่คลี่ออกมาเป็นเพย์โหลด JavaScript ขนาด 77 กิโลไบต์ซึ่งมีความคล้ายคลึงกับมัลแวร์ตระกูล DEV#POPPER ส่วนสายที่สองจะแยกกระบวนการ Node.js ออกไปต่างหาก แล้วขอ boot payload จากไอพี 23.27.13[.]43 ถอดรหัสคำตอบที่ได้และรันทันที บริษัท Socket เน้นว่า “นี่คือสายส่งมอบสำรอง ไม่ใช่ fallback ที่ไม่มีพิษภัย” เพราะกระบวนการที่แยกออกไปสามารถทำงานต่อได้แม้คำสั่ง build, test หรือ CLI จะจบไปแล้ว

เมื่อแพ็กเกจถูกโหลด implant จะเริ่มกระบวนการ dispatch บนบล็อกเชนด้วยการดึงค่า transaction hash ของ BSC จากธุรกรรมขาออกล่าสุดของที่อยู่ Tron ที่ฝังไว้แบบ hard-coded หากขั้นตอนนี้ล้มเหลว จะเปลี่ยนไปสอบถามบัญชี Aptos เป็นทางสำรองเพื่อให้ได้ธุรกรรม BSC มาถอดรหัสและดึงโค้ด JavaScript ออกมารัน ทั้งสายในกระบวนการหลักและสายที่แยกออกไปต่างใช้ชุดที่อยู่กระเป๋า บัญชี และธุรกรรมของ Tron, Aptos และ BSC คนละชุดกัน

เพย์โหลดชั้นแรกในกระบวนการหลักทำหน้าที่เป็น loader ที่ใช้วิธีคลี่โค้ดผ่านบล็อกเชนแบบเดียวกันเพื่อดึงมัลแวร์ชั้นที่สองชื่อ clientCode ซึ่งถูกทำให้อ่านยากอย่างหนักและทำหน้าที่เป็น RAT บน Node.js โดยตรง ความสามารถของมันได้แก่ อัปโหลดไฟล์ไปยังโฮสต์ที่กำหนด ดึงโค้ด JavaScript เพิ่มเติมมารัน เก็บข้อมูลพื้นฐานของเครื่อง ส่งข้อความ check-in บอกสถานะ และอ่านข้อมูลคลิปบอร์ดผ่าน PowerShell บน Windows, pbpaste บน macOS และ xclip หรือ xsel บน Linux

ที่น่าสนใจคือมัลแวร์มีตรรกะหลบเลี่ยงการวิเคราะห์ด้วยการไม่ทำงานบนเครื่องที่มีชื่อโฮสต์ github-runner, buildbot, buildkitsandbox และ microsoft-standard-WSL2 ซึ่งเป็นชื่อที่พบบ่อยในสภาพแวดล้อมพัฒนา CI และแซนด์บ็อกซ์ ส่วนกระบวนการที่แยกออกไปพบเพย์โหลดสองแบบ คือ RAT ตัว clientCode และอินโฟสตีลเลอร์ภาษา Python ที่ประเมินว่าเป็นรุ่นพัฒนาต่อของ OmniStealer ซึ่งบริษัท eSentire เคยเปิดเผยรายละเอียดครั้งแรกเมื่อเดือนเมษายน 2569 โดยกวาดข้อมูลสภาพแวดล้อมและโฮสต์, Windows Credential Manager, Secret Service บน Linux, ข้อมูลเบราว์เซอร์ Chromium และ Firefox, พื้นที่เก็บข้อมูลของส่วนขยายประเภทกระเป๋าคริปโตและตัวจัดการรหัสผ่าน, ข้อมูลรับรอง Git, การตั้งค่า GitHub CLI, ล็อกของ GitHub Desktop และพื้นที่เก็บข้อมูลของ Microsoft Visual Studio Code

ผลกระทบ

การโจมตีรูปแบบนี้ย้ายจุดเสี่ยงจาก “ตอนติดตั้งแพ็กเกจ” มาเป็น “ตอนโหลดโค้ด” ซึ่งกระทบกับสมมติฐานการป้องกันที่หลายทีมพัฒนาใช้อยู่ เพราะการสแกนช่วงติดตั้งหรือการบล็อก postinstall script ไม่ช่วยอะไรเลยเมื่อโค้ดอันตรายรอทำงานตอน import ทีมที่รันสคริปต์ build หรือชุดทดสอบอัตโนมัติจึงมีโอกาสถูกรันโค้ดของผู้โจมตีโดยไม่มีสัญญาณเตือน และเนื่องจากเป้าหมายเป็นเครื่องนักพัฒนาและ CI runner ซึ่งมักเก็บโทเคน คีย์ระบบคลาวด์ และข้อมูลรับรองสำหรับ deploy ไว้ ความเสียหายจึงลามจากเครื่องเดียวไปสู่ระบบที่กำลังพัฒนาได้ทันที

การใช้บล็อกเชนสาธารณะเป็นชั้นส่งคำสั่งยังทำให้แนวทางป้องกันเดิมอย่างการบล็อกโดเมนหรือใช้ threat feed มีประสิทธิภาพลดลง เพราะทราฟฟิกที่วิ่งออกไปเป็นการเรียก API ของเครือข่ายบล็อกเชนที่ดูปกติ และผู้โจมตีเปลี่ยนเพย์โหลดได้โดยไม่ต้องแตะต้องแพ็กเกจที่เผยแพร่ไปแล้ว ความเสี่ยงจึงไม่ได้จำกัดอยู่แค่แพ็กเกจ @joyfill สองตัวนี้ แต่คือรูปแบบการโจมตีที่กำลังถูกใช้ซ้ำในหลายแคมเปญของผู้โจมตีกลุ่มเดียวกัน

คำแนะนำ

  • ตรวจสอบ lockfile, แคช npm, mirror ภายในองค์กร, build image และ deployment artifact ว่ามีเวอร์ชัน @joyfill/layouts@0.1.2-2773.beta.0 หรือ @joyfill/components@4.0.0-rc24-2773-beta.4 หรือไม่ หากพบให้ถอนออกทุกจุดและปักหมุด (pin) ไปยังเวอร์ชันที่ตรวจสอบแล้วว่าปลอดภัย
  • ถือว่าเครื่องหรือ runner ที่เคยโหลดแพ็กเกจดังกล่าวถูกยึดครองแล้ว ให้หมุนเปลี่ยนข้อมูลรับรองทั้งหมดที่กระบวนการ Node.js นั้นเข้าถึงได้ ทั้งโทเคน Git/GitHub, คีย์ระบบคลาวด์, ข้อมูลรับรองในตัวจัดการรหัสผ่าน และคีย์กระเป๋าคริปโต
  • หลีกเลี่ยงการใช้แพ็กเกจรุ่น beta หรือ release candidate ในไปป์ไลน์ที่มีสิทธิ์เข้าถึงระบบจริง และตั้งนโยบายให้ต้องผ่านการตรวจสอบก่อนอัปเดตเวอร์ชัน dependency
  • เฝ้าระวังทราฟฟิกขาออกจากเครื่องนักพัฒนาและ CI ที่วิ่งไปยัง API ของเครือข่ายบล็อกเชนสาธารณะโดยไม่มีเหตุผลทางธุรกิจรองรับ รวมถึงการติดต่อไปยังไอพี 23.27.13[.]43 (defang แล้ว)
  • ปรับเครื่องมือ software composition analysis ให้ตรวจพฤติกรรมตอน import ไม่ใช่เฉพาะช่วงติดตั้ง และแยกสิทธิ์ของ CI runner ไม่ให้ job เดียวเข้าถึงข้อมูลลับทั้งหมดขององค์กร

แหล่งอ้างอิง