חזרה לפיד
articlesמקור: Wiz Blog1.12.2022

Hell's Keychain: פרצת שרשרת אספקה ב-IBM Cloud Databases עבור PostgreSQL

אמ;לק

פרצת אבטחה בשרשרת האספקה של IBM Cloud Databases עבור PostgreSQL אפשרה גישה לא מורשית למסדי נתונים. חשיפה של סודות קוד פתוח הובילה לגישה ולמניפולציה של ארטיפקטים של בנייה, מה שמדגיש את חשיבות אבטחת שרשרת האספקה למפתחי ענן.

סיכום בעברית: מערכת VibeSec · מדיניות המקורות

נוסף ל-VibeSec:

כותרת מקורית: Hell’s Keychain: Supply-chain vulnerability in IBM Cloud Databases for PostgreSQL allows potential unauthorized database access

Hell's Keychain: פרצת שרשרת אספקה ב-IBM Cloud Databases עבור PostgreSQL

התוכן המלא בעברית

תרגום אוטומטי מהמקור; מונחים טכניים נשארו באנגלית. לנוסח המחייב — הכתבה המקורית.

בפוסט זה נדגים כיצד הצלחנו למנף פגיעות של הסלמת הרשאות ב-PostgreSQL כדי לחשוף סוד ארוך טווח. סוד זה היה עלול להיות מנוצל לרעה לצורך אימות לשירותי CI/CD פנימיים של IBM Cloud והתערבות בתהליך בניית התמונה הפנימי של IBM Cloud – מה שעלול היה לחשוף את לקוחות החברה למתקפת שרשרת אספקה. חברות Wiz ו-IBM Cloud עבדו בשיתוף פעולה הדוק כדי לתקן בעיה זו. ניתן לקרוא את הייעוץ הביטחוני של IBM Cloud כאן.

אני מעריך מאוד את השותפות והמקצועיות של צוות מחקרי האבטחה של Wiz ומצפה לשיתוף פעולה עתידי. החריצות והיצירתיות שלהם מסייעות להפוך את סביבות הענן למקום בטוח יותר לפעילות IT. - Jerry Bell, CISO של IBM Cloud.

⁦TL⁩;⁦DR⁩

חברת Wiz Research חשפה את Hell’s Keychain, פגיעות שרשרת אספקה ראשונה מסוגה בספק שירותי ענן, ב-IBM Cloud Databases for PostgreSQL. הפגיעות מורכבת משרשרת של שלושה סודות חשופים (אסימון חשבון שירות של Kubernetes, סיסמת רישום קונטיינרים פרטי, ואישורי שרת CI/CD) יחד עם גישה מוגזמת לרשת של שרתי בנייה פנימיים. וקטור תקיפה זה עלול לאפשר לגורמים זדוניים להריץ קוד מרחוק בסביבות הלקוחות כדי לקרוא ולשנות נתונים המאוחסנים במסד הנתונים PostgreSQL.

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

Hell’s Keychain ממחיש כיצד אישורי טקסט גלוי (plaintext) המפוזרים בסביבת העבודה שלכם עלולים להטיל סיכון עצום על הארגון ולפגוע בשלמות המערכת ובידוד הדיירים (tenant isolation). יתרה מכך, הפגיעות מדגישה את הצורך בבקרות רשת קפדניות ומדגימה כיצד גישה של פוד (pod) ל-Kubernetes API היא תצורה שגויה נפוצה שעלולה להוביל לחשיפה וגרידה (scraping) של הרישום של הקונטיינרים.

בסופו של דבר, Hell’s Keychain מדגיש את החשיבות של מחקר אבטחת ענן פרואקטיבי, חשיפה אחראית ומעקב ציבורי אחר פגיעויות ענן לטובת אבטחת הענן.

מהו Hell’s Keychain?

באוגוסט 2022, Wiz Research גילתה את Hell’s Keychain, פגיעות בשרשרת האספקה של IBM Cloud Databases for PostgreSQL. הפגיעות מורכבת משרשרת של שלושה סודות חשופים יחד עם גישה מוגזמת לרשת אל שרתי בנייה פנימיים. למיטב ידיעתנו, מדובר בווקטור התקפת שרשרת אספקה ראשון מסוגו המשפיע על התשתית של ספק ענן. Hell’s Keychain מדגיש את החשיבות של ניהול סודות תקין, בקרות רשת ובידוד דיירים, במיוחד בסביבות ענן גדולות ומורכבות.

הגילוי של Hell’s Keychain התבסס בחלקו על מחקר קודם של Wiz, שחשף סדרה של פגיעויות ב-PostgreSQL המשפיעות על רוב ספקי הענן, כגון Microsoft Azure ו-Google Cloud Platform.

וקטור התקפת שרשרת אספקה של ספק שירותי ענן

Hell’s Keychain משקף וקטור תקיפה חדשני בענן, שבו תהליך הבנייה של ספק שירותי ענן נפגע דרך שרשרת האספקה שלו. זהו אינו מקרה בודד, אלא בעיה רחבה יותר בקהילת האבטחה – ביצענו בעבר תקיפות דומות ל-Hell’s Keychain אצל מספר ספקים.

מניסיוננו, המתכון למתקפת שרשרת אספקה על ספק שירותי ענן (CSP) כולל שני מרכיבים: 'הקישור האסור' ו'מחזיק המפתחות' (keychain). הקישור האסור מייצג גישה לרשת – ובאופן ספציפי, מדובר בחיבור בין סביבת ייצור לסביבת הבנייה שלה. מחזיק המפתחות, לעומת זאת, מסמל אוסף של סוד אחד או יותר שהתוקף מוצא מפוזרים ברחבי סביבת היעד. אף על פי ששני הרכיבים כשלעצמם בעייתיים, בשילובם הם יוצרים תרכובת קטלנית.

מחזיק המפתחות

ב-Hell’s Keychain, מחזיק המפתחות הכיל שלושה סודות: אסימון חשבון שירות של Kubernetes, סיסמת רישום קונטיינרים פרטי ואישורי שרת CI/CD. בשילוב עם הקישור האסור בין מופע ה-PostgreSQL האישי שלנו לבין סביבת הבנייה של IBM Cloud Databases, מחזיק המפתחות הזה אפשר לנו לבצע אימות לשרתי הבנייה הפנימיים של IBM Cloud ולתפעל את הארטיפקטים שלהם.

השגת המפתח הראשון – אסימון חשבון שירות של Kubernetes

בשלב מוקדם זה של המחקר, המטרה שלנו הייתה זהה לכל ביקורת PostgreSQL-as-a-Service שאנו מבצעים: למצוא דרך להסלים את ההרשאות שלנו בתוך מופע ה-PostgreSQL למשתמש-על (superuser). ברגע שזכינו בהרשאות משתמש-על, זה אמור להיות פשוט יחסית להריץ קוד שרירותי במכונה הווירטואלית הבסיסית ולהמשיך לאתגר את גבולות האבטחה הפנימיים משם.

במקרה של IBM Cloud, מצאנו מספר דרכים לעשות זאת. חלקן היו גרסאות של פגיעויות שעבדו עבורנו בעבר מול ספקי ענן אחרים (שאותן נפרסם בקרוב), וחלקן היו ייחודיות ל-IBM Cloud.

הסלמת הרשאות ב-PostgreSQL באמצעות SQL Injection

אחת התכונות ש-IBM Cloud מציעה ללקוחות ה-PostgreSQL המנוהל שלה היא Logical Replication. תכונה זו מיושמת מאחורי הקלעים באמצעות פונקציות PostgreSQL רבות במסד הנתונים. אחת הפונקציות היא create_subscription. פונקציה זו נמצאת בבעלות המשתמש ibm (משתמש-על במסד הנתונים) וכוללת דגל security definer, מה שאומר שהפונקציה רצה בהרשאות של בעל הפונקציה. בבחינת הקוד, הבחנו בפגיעות SQL Injection המאפשרת ביצוע של שאילתות שרירותיות כמשתמש-על (משתמש ה-ibm):

⁦CREATE OR REPLACE FUNCTION public.create_subscription( IN subscription_name text , IN host_ip text , IN portnum text , IN password text , IN username text , IN db_name text , IN publisher_name text ) RETURNS text LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER PARALLEL UNSAFE COST 100 AS $BODY$ DECLARE persist_dblink_extension boolean ; BEGIN persist_dblink_extension : = create_dblink_extension(); PERFORM dblink_connect( format ( 'dbname=%s' , db_name)); PERFORM dblink_exec( format ( 'CREATE SUBSCRIPTION %s CONNECTION ''host=%s port=%s password=%s user=%s dbname=%s sslmode=require'' PUBLICATION %s' , subscription_name, host_ip, portNum, password , username, db_name, publisher_name)); PERFORM dblink_disconnect(); …⁩

הארגומנטים שהועברו לפונקציה זו לא עברו ניקוי (sanitization) כראוי לפני הרצת הפונקציה dblink_exec. משמעות הדבר היא שיכולנו לספק קלט שרירותי לפונקציה create_subscription, ובכך להחדיר שאילתת SQL משלנו לתוך שאילתת ה-SQL המורשית שעמדה להתבצע כמשתמש-על. כדי להדגים זאת, הרצנו שאילתה שמציגה את שם המשתמש שמריץ אותה:

⁦INSERT INTO public.test3( data ) VALUES (current_user);⁩

לאחר מכן כתבנו שאילתת SQL שניצלה את ה-SQL Injection:

השאילתה הבסיסית שבוצעה על ידי create_subscription הייתה:

⁦CREATE SUBSCRIPTION test3 CONNECTION 'host=127.0.0.1 port=5432 password=a user=ibm dbname=ibmclouddb sslmode=require' PUBLICATION test2_publication WITH (create_slot = false); INSERT INTO public.test3( data ) VALUES (current_user);⁩

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

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

הפעלנו Reverse Shell והתחלנו לחקור את הסביבה. התחלנו בהרצת פקודות סיור בסיסיות: תצפית על רשימת התהליכים במכונה, החיבורים הפעילים שלה וקובץ /etc/passwd. לאחר מכן נקטנו באמצעים יזומים יותר והתחלנו סריקת פורטים רחבה בסביבה הפנימית של שירות ה-PostgreSQL ב-IBM Cloud.

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

בברכת IBM Cloud, המשכנו לחקור את סביבת מופע המחשוב. תוך בחינת משתני הסביבה, שמנו לב לכמה מהם שציינו שאנו מריצים קונטיינר בתוך פוד (pod) של Kubernetes (למשל המשתנה POD_NAME):

⁦KUBERNETES_PORT = tcp://172.21.0.1:443 POD_NAME = c-84aa5d80-ef9b-440e-b4f8-31fd782118b2-m-1 KUBERNETES_SERVICE_PORT = 443⁩

העובדה שפעלנו בתוך אשכול Kubernetes גרמה לנו לתהות האם האשכול מוקדש לחשבון שלנו או משותף בין לקוחות. המשכנו במאמצי הסיור ומצאנו אסימון Kubernetes API בקובץ /var/run/secrets/kubernetes.io/serviceaccount/token. באמצעות אסימון זה, יכולנו לגשת ל-Kubernetes API.

העלאת כלי השירות kubectl למופע אפשרה לנו להשתמש בתכונות שלו ולבצע פעולות במהירות רבה יותר. לאחר מכן הרצנו את פקודת can-i כדי לבדוק את ההרשאות הנוכחיות והמשאבים הזמינים שלנו, וראינו שיש לנו גישה לסודות (secrets), לפודים (pods) ולמשאבי IBM Cloud מותאמים אישית במרחב השמות (namespace) שלנו:

⁦./kubectl auth can-i --list Resources Verbs selfsubjectaccessreviews.authorization.k8s.io [create] selfsubjectrulesreviews.authorization.k8s.io [create] secrets [get create update] pods [get patch update list] endpoints [get patch update] configmaps [get patch] ... deployments.apps [get] replicasets.apps [get] statefulsets.apps [get] formations.crd.compose.com [get] backups.crd.compose.com [patch delete list get] buckets.crd.compose.com [patch] podsecuritypolicies.policy [use] podsecuritypolicies.policy [use] securitycontextconstraints.security.openshift.io [use] recipes.crd.compose.com [watch get update create patch list delete]⁩

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

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

השגת המפתח השני – סיסמת רישום קונטיינרים

בעת יצירת פוד של Kubernetes עם תמונה מרישום קונטיינרים פרטי, יש צורך לספק את השדה imagePullSecrets בתצורת הפוד, המפנה לסוד המכיל את האישורים עבור רישום הקונטיינרים.

במהלך השנה האחרונה, התנסנו בגרידת (scraping) רישום קונטיינרים כטכניקה המסייעת לנו לנוע לרוחב (lateral movement) בתוך סביבות ענן. טכניקה זו הוכיחה את יעילותה במספר הזדמנויות.

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

• אם הרישום ציבורי, ניתן להתחיל למשוך תמונות ולסרוק אותן לאיתור קוד מקור פנימי, ארטיפקטים ואישורים מפוזרים.

• אם הרישום דורש אימות אך אתם יכולים לאחזר בהצלחה את ה-imagePullSecrets, תוכלו להמשיך במשיכת התמונה ובסריקה. עם זאת, כישלון באחזור ה-imagePullSecrets ימנע מכם להתקדם בתהליך.

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

⁦kubectl get pods -o json⁩

גילינו ש-IBM Cloud משך תמונות מותאמות אישית מרישום קונטיינרים פרטי שהאישורים שלו נמצאו בסוד ה-pipeline.

⁦"imagePullSecrets" : [ { "name" : "pipeline" }⁩

#supply-chain#ibm-cloud#postgresql#postgres#vulnerability
קרא במקור

קריאה וכלים קשורים

אבטחת Supabase / PostgreSQLמונחי אבטחה והסברים בעברית