Εν συντομία: Στο Nginx με PHP-FPM η ευπάθεια του PHP2Shell βρίσκεται στο PHP-FPM και όχι στο Nginx. Κάντε patch σε όλες τις εκδόσεις PHP-FPM, επανεκκινήστε πλήρως κάθε υπηρεσία FPM και τεκμηριώστε το με τις ώρες εκκίνησης των διεργασιών. Για τη μακροπρόθεσμη ασφάλεια Nginx PHP-FPM μετράνε τα ξεχωριστά pools, οι τιμές που δεν αντικαθίστανται και μια διαμόρφωση Nginx που δεν εκτελεί αρχεία που έχουν ανέβει.
Πώς συνεργάζονται το Nginx και το PHP-FPM
Το Nginx παραδίδει το ίδιο τα στατικά αρχεία και προωθεί τα αιτήματα προς σενάρια PHP μέσω FastCGI στο PHP-FPM. Το PHP-FPM αποτελείται από μια κύρια διεργασία (master) και πολλές διεργασίες workers, ομαδοποιημένες σε pools. Ένας worker εξυπηρετεί διαδοχικά πολλά αιτήματα.
Αυτό ακριβώς είναι σημαντικό για το PHP2Shell. Στο CVE-2026-109619 εσωτερική κατάσταση ενός αιτήματος μπορεί να παραμείνει μετά την αποδέσμευση της μνήμης και να χρησιμοποιηθεί από ένα μεταγενέστερο αίτημα στον ίδιο worker. Στο CVE-2026-109618 μια κατάσταση Out of Memory μπορεί να διακόψει την PHP στη μέση της αρχικοποίησης ενός αιτήματος. Και οι δύο ευπάθειες βαθμολογούνται με CVSS v4.0 9,2 και έχουν διορθωθεί στις PHP 8.5.12, 8.4.27, 8.3.36 και 8.2.35.
Έλεγχος αποθέματος: εκδόσεις, pools, διεργασίες
Πολλοί διακομιστές έχουν παράλληλα περισσότερες εκδόσεις PHP-FPM. Οι παρακάτω εντολές μόνο διαβάζουν· τα ονόματα πακέτων και υπηρεσιών είναι παραδείγματα για Debian/Ubuntu και την οικογένεια RHEL.
# Ποιες υπηρεσίες FPM εκτελούνται;
systemctl list-units --type=service | grep -i fpm
# Ποια έκδοση βρίσκεται πίσω τους; (παράδειγμα Debian/Ubuntu)
php-fpm8.3 -v
# Οικογένεια RHEL
php-fpm -v
# Σε ποια sockets ή θύρες προωθεί το Nginx;
nginx -T 2>/dev/null | grep -E 'fastcgi_pass'
# Pools και χρήστες τους
grep -RhE '^\[|^user|^listen' /etc/php/*/fpm/pool.d/ 2>/dev/null
Αντιστοιχίστε κάθε καταχώριση fastcgi_pass με ένα pool που εκτελείται. Έτσι βλέπετε ποια έκδοση PHP εξυπηρετεί ποιον ιστότοπο. Στα πακέτα διανομής το patch το τεκμηριώνει το changelog με τους αριθμούς CVE και όχι μόνο ο αριθμός έκδοσης.
Ένα συχνό εύρημα σε τέτοιες καταγραφές είναι διακομιστές όπου με τα χρόνια εγκαταστάθηκαν πολλές εκδόσεις PHP, από τις οποίες χρησιμοποιείται πραγματικά μόνο μία. Οι υπόλοιπες υπηρεσίες FPM εξακολουθούν να εκτελούνται, συχνά με τυπικά pools που ακούν σε τοπικό socket ή θύρα. Συνήθως δεν είναι προσβάσιμες απευθείας απ' έξω, αποτελούν όμως περιττό κίνδυνο και επιμηκύνουν κάθε έκτακτη ενημέρωση. Απενεργοποιήστε και αφαιρέστε τις εκδόσεις που δεν χρησιμοποιεί κανένας ιστότοπος, αφού ελέγξετε την αντιστοίχιση μέσω των καταχωρίσεων fastcgi_pass.
Αξίζει επίσης μια ματιά στον χρήστη των pools. Αν όλα τα pools εκτελούνται ως www-data ή nginx, ο διαχωρισμός μεταξύ των ιστοτόπων υπάρχει μόνο στα χαρτιά. Όποιος αναλαμβάνει έναν ιστότοπο μπορεί τότε να διαβάσει τα αρχεία όλων των άλλων, για παράδειγμα αρχεία διαμόρφωσης με κωδικούς βάσης δεδομένων. Ξεχωριστοί χρήστες συστήματος ανά pool και κατάλληλα δικαιώματα αρχείων δημιουργούν εδώ ένα πραγματικό όριο. Αυτό δεν αποτελεί λύση για το PHP2Shell, περιορίζει όμως σημαντικά την πιθανή ζημιά μιας επιτυχημένης επίθεσης.
Εφαρμογή του patch και ανανέωση όλων των workers
Μετά την ενημέρωση των πακέτων επανεκκινήστε κάθε υπηρεσία PHP-FPM. Ένα reload αντικαθιστά μεν τους workers, μια πλήρης επανεκκίνηση όμως ανανεώνει και την κύρια διεργασία και είναι ο ασφαλής δρόμος μετά από ενημερώσεις ασφαλείας.
# Παράδειγμα Debian/Ubuntu, για κάθε εγκατεστημένη έκδοση
systemctl restart php8.3-fpm
# Οικογένεια RHEL
systemctl restart php-fpm
# Έλεγχος: ώρα εκκίνησης του master και των workers
ps -eo pid,lstart,cmd | grep -E 'php-fpm' | grep -v grep
Κάθε διεργασία πρέπει να έχει ξεκινήσει μετά την ενημέρωση. Αναλυτική περιγραφή υπάρχει στη σελίδα Επανεκκίνηση του PHP-FPM και όλων των workers.
Ένα patch δεν αφαιρεί κακόβουλο λογισμικό που εισήχθη νωρίτερα. Διατηρήστε τα αρχεία καταγραφής πρόσβασης και σφαλμάτων του Nginx από τις 20/10/2026 και ελέγξτε τους ιστοτόπους για ίχνη.
Ορισμός προσωρινών τιμών στο pool
Όσο μια έκδοση δεν έχει patch, το php.net συνιστά προσωρινά μέτρα. Δεν προσφέρουν πλήρη προστασία. Στο PHP-FPM ορίζετε τις τιμές με php_admin_value ή php_admin_flag στο pool, ώστε οι εφαρμογές να μην μπορούν να τις αντικαταστήσουν μέσω ini_set().
; Παράδειγμα: /etc/php/8.3/fpm/pool.d/website.conf
php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[post_max_size] = 32M
php_admin_value[upload_max_filesize] = 24M
Χωρίς λειτουργία upload το php.net αναφέρει post_max_size = 8M. Στην PHP 8.5 προστίθεται το fatal_error_backtraces=0. Για την υπόδειξη σχετικά με το memory_limit=-1 χρειάζεστε όριο μνήμης σε επίπεδο cgroup, για παράδειγμα μέσω MemoryMax σε συμπλήρωμα του systemd για την υπηρεσία FPM. Προσαρμόστε στο Nginx το client_max_body_size στο νέο post_max_size, ώστε οι χρήστες να λαμβάνουν κατανοητά μηνύματα σφάλματος. Στη συνέχεια επανεκκινήστε το FPM.
Μόνιμη βελτίωση της ασφάλειας Nginx PHP-FPM
Πέρα από την οξεία περίπτωση, βοηθούν ορισμένοι βασικοί κανόνες που περιορίζουν τη ζημιά σε μελλοντικές ευπάθειες:
- Ένα pool ανά ιστότοπο με δικό του χρήστη συστήματος, δικό του socket και δικό του όριο
open_basedir. Περισσότερα στη σελίδα open_basedir και απομόνωση ανά ιστότοπο. - Δικαιώματα socket ώστε να έχει πρόσβαση μόνο το Nginx, χωρίς άνοιγμα θυρών FPM προς τα έξω.
- Εκτέλεση μόνο υπαρχόντων σεναρίων: ορίστε στο location της PHP
try_files $uri =404;, ώστε το Nginx να μην προωθεί στην PHP διαδρομές που δεν υπάρχουν. - Καμία εκτέλεση uploads: απαγορεύστε την εκτέλεση PHP στους καταλόγους uploads. Υποδείξεις υπάρχουν στη σελίδα Ασφαλής υλοποίηση των uploads αρχείων.
- Προστασία σελίδων κατάστασης: κάντε τα
pm.status_pathκαιping.pathπροσβάσιμα μόνο εσωτερικά.
# Παράδειγμα: καμία εκτέλεση PHP στον κατάλογο uploads
location ~* ^/uploads/.*\.php$ {
deny all;
}
Ελέγχετε κάθε αλλαγή με nginx -t, προτού επαναφορτώσετε το Nginx. Καταγράψτε επιπλέον ποια pools, εκδόσεις και ειδικοί κανόνες υπάρχουν στον διακομιστή. Αυτή η σύντομη τεκμηρίωση εξοικονομεί πολύτιμο χρόνο στην επόμενη κρίσιμη ευπάθεια, επειδή κανείς δεν χρειάζεται να ψάξει πρώτα ποιος ιστότοπος ανήκει σε ποιο pool.
Πώς βοηθά συγκεκριμένα το PHP SOS;
- Αντιστοιχίζουμε κάθε ιστότοπο στο pool και στην έκδοση PHP του και ελέγχουμε το πραγματικό επίπεδο των πακέτων.
- Κάνουμε patch, επανεκκινούμε όλες τις υπηρεσίες FPM και τεκμηριώνουμε τις ώρες εκκίνησης των διεργασιών ως απόδειξη.
- Μέχρι το patch ορίζουμε τις προσωρινές τιμές ανά pool και περιορίζουμε τη μνήμη μέσω cgroup.
- Στο πλαίσιο της σκλήρυνσης διακομιστών διαχωρίζουμε σωστά pools, δικαιώματα και καταλόγους uploads.
- Σε περίπτωση υποψίας παραβίασης αναλαμβάνουμε το Incident Response.
Συχνές ερωτήσεις
Αρκεί το systemctl reload για το PHP-FPM μετά από ενημέρωση;
Ένα reload ανανεώνει τους workers, η κύρια διεργασία (master) όμως μπορεί να κρατήσει τον παλιό κώδικα. Μετά από ενημέρωση ασφαλείας ο ασφαλής δρόμος είναι η πλήρης επανεκκίνηση της υπηρεσίας. Ελέγξτε στη συνέχεια την ώρα εκκίνησης του master και των workers.
Πρέπει να επανεκκινηθεί το Nginx μετά από ενημέρωση της PHP;
Το ίδιο το Nginx δεν περιέχει PHP και δεν χρειάζεται επανεκκίνηση για το patch της PHP. Πρέπει να επανεκκινηθούν όλες οι υπηρεσίες PHP-FPM. Αν αλλάξετε ταυτόχρονα τη διαμόρφωση του Nginx, ελέγξτε την πριν από την επαναφόρτωση με nginx -t.
Γιατί ξεχωριστά pools ανά ιστότοπο;
Κάθε pool εκτελείται με δικό του χρήστη και δικά του όρια. Αν παραβιαστεί ένας ιστότοπος, ο επιτιθέμενος δεν φτάνει εύκολα στα αρχεία των υπολοίπων. Επιπλέον, οι προσωρινές τιμές μπορούν να οριστούν στοχευμένα ανά pool.
Αποτελεί το pm.max_requests προστασία κατά του PHP2Shell;
Όχι, δεν αντικαθιστά κάποιο patch. Η τιμή περιορίζει πόσα αιτήματα εξυπηρετεί ένας worker προτού αντικατασταθεί. Αυτό μπορεί να συντομεύσει τη διάρκεια ζωής καταστάσεων μέσα στη διεργασία, δεν αποτελεί όμως μέτρο που αναφέρει το php.net.