קבצי PHP בתיקיית uploads – סימן לפריצה והדרך לטיפול

מצאת קובץ PHP ב-wp-content/uploads? זה כמעט תמיד web-shell של תוקף. ככה מאתרים, מסירים ומונעים בעתיד.

תיקיית wp-content/uploads מיועדת אך ורק לקבצי מדיה – תמונות, וידאו, PDF, קבצי אודיו. WordPress עצמו לעולם לא כותב לשם קובץ PHP, ושום תוסף תקין לא צריך לעשות זאת. כשהאודיט מאתר קבצי PHP בתוך התיקייה הזו, ההסבר ההסתברותי הגבוה ביותר הוא שתוקף הצליח להעלות web-shell – קובץ קטן שמעניק לו שליטה מרחוק על השרת.

למה זה משנה

Web-shell בתיקיית uploads הוא לא איום תיאורטי. ברגע שהקובץ עולה, התוקף יכול להריץ פקודות שרת, לקרוא את wp-config.php ולשלוף את סיסמת ה-DB, להוסיף משתמש מנהל חדש, להזריק קוד ספאם לתוך פוסטים קיימים, או להפוך את האתר לחלק מ-botnet ששולח דואר זבל. במקרים גרועים יותר ראינו שתילת קוד שגונב פרטי כרטיסי אשראי בעמודי checkout של WooCommerce, או שמירה של גיבויי DB מלאים בתיקייה ציבורית כך שכל אחד יכול להוריד אותם. גם אחרי שתמחק את הקובץ הראשון, סביר שהתוקף השאיר backdoor שני או שלישי במקום אחר – לכן ניקוי חלקי אינו פתרון.

איך לזהות

סימני זיהוי טיפוסיים: שמות אקראיים בני 5–10 תווים (a8f2k.php), שמות שמתחזים לקובץ ליבה (wp-cache.php, wp-tools.php, class-wp.php), קבצים בתוך uploads/YYYY/MM/, או סיומות חריגות כמו .phtml, .phar ו-.php7. בתוך הקבצים תראו לרוב שילוב של eval, base64_decode, gzinflate ו-str_rot13 – פונקציות שמשמשות להסתרת הקוד האמיתי. דוגמה קלאסית: eval(base64_decode($_POST["cmd"])) – שורה אחת שמעניקה לתוקף ביצוע פקודות מלא.

איך לתקן

אל תתחיל ממחיקה. סדר הפעולות הנכון: גיבוי מלא של הקבצים והמסד (גם של הקוד הזדוני – הוא ראיה משפטית פוטנציאלית), הורדה מקומית של כל קובץ חשוד לבחינה בעורך טקסט מבודד, סריקה כוללת עם Wordfence או MalCare כדי לאתר backdoors נוספים, ורק אז מחיקה. אחרי הניקוי החלף סיסמאות (DB, מנהלים, FTP, הוסטינג), הסר salts ב-wp-config.php, ועדכן את כל התוספים והליבה.

כדי למנוע הישנות, חסום הרצת PHP בכל תיקיית uploads ברמת השרת:

<FilesMatch "\.(php|phtml|phar|php7|php8)$">
    Require all denied
</FilesMatch>
location ~* /wp-content/uploads/.*\.(php|phtml|phar)$ {
    deny all;
}

טעויות נפוצות

טעות ראשונה: למחוק רק את הקובץ שהאודיט הציג ולחשוב שזה הסוף. תוקף מנוסה מפזר 3–5 backdoors במיקומים שונים – בתיקיית theme, בקובץ functions.php, ולפעמים גם בתוך טבלת wp_options. טעות שנייה: לסמוך על שם הקובץ. wp-cron-fix.php נראה תמים אבל הוא לא קובץ ליבה. כל קובץ PHP בתוך uploads חשוד עד שיוכח אחרת. טעות שלישית: לדלג על שינוי הסיסמאות בהנחה ש"רק קובץ אחד נמחק" – לפני המחיקה התוקף קרא את wp-config.php, ולכן הסיסמה הקיימת חשופה.

בדיקה לאחר תיקון

הרצה של find wp-content/uploads -name "*.php" -type f בשרת אמורה להחזיר רק קבצי index.php ריקים ("Silence is golden"). בדוק עם curl: curl -I https://example.com/wp-content/uploads/test.php – אם תיצור קובץ בדיקה זמני, צריך להחזיר 403. הרץ סריקת Wordfence מלאה ואשר ש"Critical issues" עומד על 0.

שווה גם להוסיף ניטור: כלי כמו tripwire, aide או אפילו cron שמריץ find wp-content/uploads -name "*.php" -newer /tmp/last-check כל שעה ושולח מייל אם נמצא משהו חדש – זיהוי מיידי במקום אחרי שהאודיט השבועי הבא ירוץ. מבחינה משפטית, אם האתר מטפל בפרטי לקוחות, חובה לתעד את התקרית: תאריך, קבצים שהיו מעורבים, פעולות שננקטו, ולמי הודעת. לקוחות שדליפת המידע שלהם נחשבת לאירוע אבטחה רציני – שווה ליידע אותם ב-72 שעות הראשונות.

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