21. oktoobril 2026 avaldas PHP versioonid 8.5.12, 8.4.27, 8.3.36 ja 8.2.35, mis parandavad kaks kriitilist turvaviga, CVE-2026-109618 ja CVE-2026-109619 (CVSS v4.0 9.2). Mõlemad võimaldavad serveris koodi käivitada ilma autentimiseta, ja haavatav pole mõni plugin, vaid interpretaator ise: iga PHP-l töötav veebileht, alates WordPressist kuni eraldi arendatud koodini.
Tavalises serveris on lugu lühike: uuenda pakett ja taaskäivita PHP. ispmanageri ja CloudLinuxiga majutusserverites osutus see huvitavamaks. Ühe öö ja hommikuga parandasime kõik oma serverid ning astusime teel peaaegu kõigile rehadele, mida ei maini ei PHP turvateade ega paneeli dokumentatsioon.
See ei ole turvateate ümberjutustus, vaid nimekiri sellest, mis ei läinud juhendi järgi, ja kuidas me selle lahendasime. Kui haldate ispmanageriga serverit, eriti CloudLinuxil, kontrollige iga punkti oma süsteemis: osa probleeme jääb nähtamatuks, kuni õigesse kohta ei vaata.
Ajutised meetmed enne parandusi
Kuni pakette pole, ei saa turvavigu täielikult sulgeda, saab ainult ära lõigata teadaolevad ründeteed. Avalikud eksploidid, mis ilmusid juba enne väljalaset, kasutasid failide üleslaadimise edenemise käsitlejat, mis käivitub iga multipart/form-data päringu korral, isegi kui veebilehel pole ühtegi üleslaadimisvormi.
Tegime kaks asja:
- Lülitasime välja
session.upload_progress.enabledkõigis PHP versioonides. See on PHP enda soovitus, seda funktsiooni ei kasuta peaaegu keegi ja veebilehed selle väljalülitamisest ei kannata. Oluline: väärtus peab olema määratud failisphp.inivõi basseini (pool) seadistuses, mitteini_set()ega.user.inikaudu, muidu rakendub see liiga hilja. - Blokeerisime
multipartpäringud nginxi tasemel kõigil veebilehtedel. ispmanageris kaasab iga vhost faili/etc/nginx/vhosts-includes/*.conf, nii et ühest failist piisab kogu serveri jaoks:
if ($http_content_type ~* "multipart") {
return 403;
}
Teise meetme hind: lakkavad töötamast failide üleslaadimine vormide kaudu, manused veebipostis ja import phpMyAdminis. Seega on see meede tundideks, mitte päevadeks.
Kaks kohta, mida on lihtne märkamata jätta:
- Vaikimisi
serverfailis/etc/nginx/nginx.conf. See püüab kinni päringud IP-aadressile ja tundmatuHostpäisega ning suunab need ispmanageris Apache’ile, kuidvhosts-includesfaile ei kaasa. Ilma eraldiincludereata läheb rünnak IP-aadressi kaudu blokeeringust mööda. - Apache avalikul aadressil. Kui Apache kuulab mitte
127.0.0.1, vaid avalikku IP-aadressi, saab päringu saata otse sellele, nginxist mööda. Kontroll:ss -ltnp | grep httpd.
CageFS-i lõks: paneeli seadistus ei jõua veebilehtedeni
Päeval lülitasime session.upload_progress.enabled välja tavapärasel viisil: „Veebiserveri seaded → PHP → versioon → seaded“. Paneel näitas, et väärtus on salvestatud. Õhtul näitas kontroll CageFS-i puuri seest, et veebilehtede jaoks oli see endiselt sisse lülitatud.
Põhjus peitub selles, kuidas alt-php CloudLinuxil töötab:
- ispmanager kirjutas väärtuse faili
/opt/alt/phpXX/etc/php.d.all/session.ini, st session-laienduse ini-faili; - alt-php-s on session-laiendus sisse ehitatud ja seda ei laadita PHP Selectori kaudu, nii et puuri sees seda ini-faili keegi ei loe;
- puuri sees loeb PHP põhifaili
/opt/alt/phpXX/etc/php.inija kasutajaalt_php.inifaili kataloogist/opt/alt/phpXX/link/conf, mis on hoopis teine kataloog kui see, mida näeb root.
Siit peamine õppetund: PHP seadeid tuleb kontrollida kasutaja nimel puuri seest, mitte root’ina:
su -s /bin/bash -c "/opt/alt/php83/usr/bin/php -r 'var_dump(ini_get(\"session.upload_progress.enabled\"));'" KLIENDI_KASUTAJANIMI
Mis toimis:
- Lisada direktiiv iga versiooni tegelikult laaditava
php.inifaili lõppu (tee näitabphp --ini, ridaLoaded Configuration File). - Käivitada
cagefsctl --rebuild-alt-php-ini, et kasutajatealt_php.inifailid uuesti koostada. - Käivitada
cagefsctl --update: puuri sees on süsteemi enda PHP-l CageFS-i skeletis oma koopia failist/etc/php.inija ilma skeleti uuendamiseta muudatus veebilehtedeni ei jõua. - Mitte unustada CGI-režiimis veebilehtede isiklikke
php.inifaile: ispmanager hoiab neid kataloogis/var/www/KASUTAJA/data/php-bin*/php.ini. - Taaskäivitada httpd ja FPM.
Veel üks detail: samal ööl kell 03:37 koostas miski kõigi alt-php versioonide php.ini failid mallist uuesti. Kui muudatus on ainult failis php.ini, tasub seda kindlustada cron-ülesandega, mis kontrollib ja taastab rea, kuni parandused välja tulevad. Nii me tegimegi ja cron taastas rea tõepoolest mitu korda, näiteks pärast alt-php pakettide uuendamist.
Multipart-blokeering lõhub sisselogimise paneeli
Paar tundi pärast blokeeringut kirjutas klient, et ei saa paneeli sisse logida: sisselogimispäring sai vastuseks 403 ja liides näitas lõputult laadimisindikaatorit. Kliendi IP-aadressi ei olnud keegi blokeerinud.
ispmanageri paneel töötab oma veebiserveril ihttpd pordil 1500 ja otse sellesse porti sisse logides ei ole nginx tõesti asjasse puutuv. Kuid kui moodul nginx_proxy on sisse lülitatud, on paneel kättesaadav ka pordi 443 kaudu aadressil https://HOST/ispmgr ja sisselogimisvorm saadetakse kui multipart/form-data. Meie blokeering vastas 403 juba nginxis ja paneeli kasutajaliides ei oska sellist viga näidata.
Moodul on kaasatud ainult paneeli hosti vhostis (/etc/nginx/modules-includes/nginx_proxy/) ja kõik selle teed lähevad ihttpd-le, mitte PHP-le. Seetõttu on erandit turvaline teha hosti ja tee kombinatsiooni järgi:
set $cve_mp 0;
if ($http_content_type ~* "multipart") { set $cve_mp 1; }
set $cve_hu "$host:$uri";
if ($cve_hu ~* "^panel\.example\.com:/(ispmgr|mancgi|manimg|long|shell|notify)(/|$)") { set $cve_mp 0; }
if ($cve_mp = 1) { return 403; }
Erand ainult tee järgi, ilma hostita, oleks viga: päring aadressile kliendi-leht/ispmgr läheks Apache’ile, WordPress suunaks selle ümber failile index.php ja PHP töötleks multipart-sisu. Paneeli hostil läheb see tee garanteeritult ihttpd-le.
Teede nimekiri tasub võtta moodulist endast (grep location /etc/nginx/modules-includes/nginx_proxy/*.conf), mitte mälu järgi. Ja kohe pärast nginxi uuesti laadimist ei tasu kontrollida: esimesi päringuid võib veel teenindada vana protsess vana seadistusega.
Unustatud Roundcube ja phpMyAdmin
Kui alt-php parandused välja tulid, uuendasime paketid ja eemaldasime blokeeringu. Alles siis meenus meile, et veebipost ja phpMyAdmin töötavad ispmanageris mitte sellel PHP versioonil, mille valisite veebilehtedele. alt-php uuendamine neid ei puuduta.
Mõlemad rakendused on kaasatud vhosts-includes kaudu, st kättesaadavad serveri igal domeenil (/roundcube, /webmail, /phpmyadmin või juhusliku eesliitega tee). Millist PHP-d need kasutavad, näitab nendes failides rida fastcgi_pass:
grep -E 'location|fastcgi_pass' /etc/nginx/vhosts-includes/*roundcube*.conf /etc/nginx/vhosts-includes/*phpmyadmin*.conf
Meie serverites leidus korraga mitu varianti:
| Rakendus | nginxi kaudu | Apache kaudu |
|---|---|---|
Roundcube /roundcube | süsteemi PHP-FPM (php-fpm.apache.sock) või isp-php74 | isp-php74 oma sokli kaudu |
Roundcube /webmail | süsteemi PHP-FPM | mod_php |
| phpMyAdmin | süsteemi PHP-FPM | mod_php |
Teine veerg on sama oluline kui esimene. Apache saab need päringud kahel juhul:
- päring IP-aadressile või tundmatu
Hostpäisega läheb nginxi vaikimisi serveri kaudu otse Apache’ile, kusAlias /webmailja/phpmyadminkehtivad globaalselt; - nginxi seadistuses on
/webmailja/phpmyadminjaoks readerror_page 404 @apachejaerror_page 502 = @apache. PATH_INFO-ga aadress, näiteks/webmail/index.php/x, ei vasta mustrilelocation ~ \.php$, saab vastuseks 404 ja läheb Apache’ile, kus selle käivitab mod_php.
Ühes serveris oli süsteemi PHP versioon 5.4 CentOS 7-st, millele parandusi ei tule kunagi. Kuni viisime need rakendused alt-php peale, jäi multipart-blokeering ainult nende teedele, veebilehed töötasid juba piiranguteta:
if ($uri !~* "^/(roundcube|webmail|phpmyadmin)(/|$)") { set $cve_mp 0; }
Sel ajal ei saanud kliendid veebipostis manuseid lisada ja märkasid seda peaaegu kohe.
Miks CloudLinuxil versiooninumber ei muutu
CloudLinux avaldas parandused kõigile alt-php harudele korraga, 5.4-st kuni 8.5-ni, kuid mitte versioonidena 8.3.36 või 8.4.27, vaid olemasolevate versioonide uute ehitustena: alt-php83-8.3.35-6, alt-php84-8.4.26-5, alt-php85-8.5.11-5 ja nii edasi. Parandus lisatakse paigaldatud versioonile, kasvab ainult paketi väljalaske number.
Seetõttu näitavad kontrollskriptid, mis võrdlevad PHP_VERSION väärtust versiooniga 8.3.36, ka pärast uuendamist „haavatav“. Ja kliendid, kes paneeli vaatavad, näevad samu numbreid ning küsivad, miks midagi pole uuendatud. Usaldusväärseid tunnuseid on kaks.
Paketi muudatuste logi (changelog). Vanemate harude puhul eemaldas CloudLinux lisaks üleslaadimise edenemise käsitleja täielikult:
for p in $(rpm -qa --qf '%{NAME}\n' 'alt-php[0-9]*' | grep -E '^alt-php(5[4-9]|[78][0-9])$' | sort -V); do
printf '%-10s %-16s ' $p "$(rpm -q --qf '%{VERSION}-%{RELEASE}' $p)"
rpm -q --changelog $p | head -10 | grep -c 'CVE-2026-10961[89]'
done
Build Date phpinfo() väljundis. Parandatud ehitustel on seal 21. oktoober 2026, eelmistel varasemad kuupäevad. Seda saab klientidele öelda: kontrollida saab igaüks, ilma serveri ligipääsuta.
Süsteemi enda PHP-ga on sama lugu teisest küljest. RHEL 9 ja selle ümberehituste puhul on parandatud 8.0 versioon php-8.0.30-8.el9_8.1 (Red Hati turvateade RHSA-2026:87151), kuid muudatuste logis olid CVE numbrid kleepunud loendi viimase punkti külge, millel on hoopis teine kirjeldus. Ilma turvateateta on seda lihtne pidada tavaliseks uuenduseks.
ispmanageri pakettidel (isp-phpXX) on muudatuste logi üldse mallipõhine, ühe 2019. aasta kirjega. Paranduse tunnused on seal kaudsed: ehituse number (meil 1781 versioonidel 8.2-8.5, 1782 versioonil 7.4, 1786 versioonil 7.1) ja Build Date 22. oktoober.
Uuendamise enda ohukohad
dnf --best --allowerasing ispmanageriga serveris. CloudLinux 9-l väljastas dnf update pika konfliktide nimekirja: repositooriumis on süsteemi PHP 8.3.36 moodulivoost ja dnf peab seda paigaldatud 8.0 parimaks kandidaadiks. Kuid ispmanageri Apache moodul (isp-httpd-mod_php) nõuab rangelt PHP 8.0.x versiooni ning sellest sõltuvad coremanager-pkg-php ja ispmanager-pkg-php, st paneel ise. dnf-i vihje lisada --best --allowerasing on siin ohtlik: see eemaldaks paneeli paketid. Konflikt on kahjutu, lõpus kirjutab dnf Nothing to do. Müra eemaldamiseks kuni 8.0 ehituse ilmumiseni: dnf update --exclude='php,php-*'.
ispmanageril on oma Apache PHP moodul. See laaditakse failist modules/isp-libphp8.so ja kuulub paketile isp-httpd-mod_php, mitte süsteemi paketile php. Nende CVE-de parandused asuvad PHP tuumas, st mooduli enda sees, ja paketi php uuendamine seda ei muuda. Kontroll:
grep -rhE 'LoadModule\s+php' /etc/httpd/conf.modules.d/ /etc/httpd/conf.d/
rpm -qf /etc/httpd/modules/isp-libphp8.so
strings /etc/httpd/modules/isp-libphp8.so | grep -m1 -E '[A-Z][a-z]{2} [ 0-9][0-9] 20[0-9]{2}'
Kui moodul on ehitatud enne 21. oktoobrit, jäävad kõik „Apache mooduli“ režiimis veebilehed haavatavaks. Nende leidmiseks: grep -lE 'SetHandler\s+application/x-httpd-php\s*$' /etc/httpd/conf/vhosts/*/*. Viisime sellised veebilehed alt-php peale ja seal, kus see polnud võimalik (liides, mis vajab ligipääsu väljaspool CageFS-i), piirasime ligipääsu IP-aadressi järgi.
Väljalülitatud PHP on halvem kui sisselülitatud. Osa endistest mod_php veebilehtedest osutus staatiliseks ja lülitasime neil PHP välja. Ühel neist oli kohatäitelehe kõrval 61 vana veebilehe faili ja väljalülitatud PHP korral anti nende lähtekood, sealhulgas andmebaasi parooliga seadistusfail, välja tavalise tekstina. Enne PHP väljalülitamist kontrollige: find JUURKATALOOG -name '*.php*' | wc -l.
SSH-ühenduse katkemine keset tehingut. 160 alt-php paketi uuendamine kestis mitu minutit ja ühendus katkes. Tehing õnneks lõpetati, kuid seda tuleb kontrollida: dnf history list, dnf check (CentOS 7-l: package-cleanup --problems, package-cleanup --dupes). Pikad uuendused tasub käivitada tmux-is.
ispmanageri vaiksed ümberehitused. Parandatud isp-php paketid tulid välja ööpäeva jooksul ükshaaval: kõigepealt 8.2-8.5, siis 7.4, siis 7.1. CentOS 7 jaoks ei olnud 7.4 ehitust selle kirjutamise ajaks ilmunud. Mõistlik on mitu korda päevas kontrollida: dnf check-update 'isp-php*'.
Kuidas viia Roundcube ja phpMyAdmin alt-php peale
Süsteemi PHP 5.4-ga serveris viisime teenindava FPM-basseini apache alt-php56 peale, säilitades sama sokli. Nii ei pea nginxi seadistust muutma ja tagasipööramine tähendab lihtsalt vana teenuse käivitamist. Valik 5.6 kasuks 7.4 asemel oli lihtne: Roundcube 1.4 ja vana phpMyAdmin töötasid versioonil 5.4, 5.6 on sellele kõige lähemal ja CloudLinux avaldas sellele tagasipordi.
Sammud:
- Oma ini-kataloog. Väljaspool CageFS-i laadib alt-php root’i all ainult minimaalse laienduste komplekti, ülejäänud asuvad kataloogis
php.d.all. Koostasime ühe failiextensions.inivajalikest moodulitest (session, json, dom, xml*, mbstring, intl, gd, mcrypt, zip, pdo, nd_mysql*). CloudLinuxi ini-failid laadivad ise oma sõltuvused, seega tuleb topeltextension=read eemaldada. - FPM-i seadistus basseiniga
apachesoklil/var/run/php-fpm.apache.sock, samadeuser,groupjalisten.ownerväärtustega ning selgesõnalisesession.save_pathväärtusega, sest süsteemiphp.inifailis polnud see määratud. - Kontroll enne ümberlülitamist:
PHP_INI_SCAN_DIR=… php -milma vigadeta japhp-fpm -t -y …tulemusegatest is successful. - systemd-üksus ridadega
Environment=PHP_INI_SCAN_DIR=…jaExecStart=… php-fpm --nodaemonize -y …. - Ümberlülitamine: nimetada ümber
/etc/php-fpm.d/apache.conf, taaskäivitada süsteemi FPM (sellele jääb basseinwww) ja käivitada uus. Katkestus mõni sekund. - Ka Apache samale soklile. Failides
roundcube-webmail.confjaphpmyadmin-httpd.confasendadaSetHandler application/x-httpd-phpreagaSetHandler "proxy:unix:/var/run/php-fpm.apache.sock|fcgi://localhost/", failisroundcube-isp.confasendada isp-php74 sokkel. Veenduda, etSetHandlerasub ploki<FilesMatch "\.php$">sees, muidu läheb FPM-i ka staatiline sisu.
Topeltlaienduste eemaldamine sammust 1:
awk '/^[[:space:]]*(zend_)?extension[[:space:]]*=/ { k=$0; gsub(/[[:space:]]/,"",k); if (seen[k]++) next } { print }' $FILES > conf.d/extensions.ini
Kontroll, milline PHP igal teel tegelikult töötab, sealhulgas otsepäring Apache’ile ja PATH_INFO:
echo '<?php echo PHP_VERSION, " ", php_sapi_name();' > /usr/share/roundcubemail/_v.php
curl -s -H 'Host: nonexistent.invalid' http://127.0.0.1:8080/webmail/_v.php
curl -sk https://DOMEEN/webmail/_v.php/x
rm -f /usr/share/roundcubemail/_v.php
Igal pool peab olema 5.6.40 fpm-fcgi. Pärast seda võib nginxi blokeeringu eemaldada.
Lahendusel on kaks miinust: Apache kaudu kaovad mod_php seadistustes olnud open_basedir piirangud ja roundcube-isp.conf on ispmanageri poolt märgitud paketi uuendamisel ülekirjutatavaks. Pärast paneeli uuendusi tasub kontrollida, et soklid pole tagasi muutunud ja et /etc/php-fpm.d/apache.conf pole uuesti tekkinud.
Kontrollnimekiri ispmanageriga serverile
Kui teil on ispmanageriga server ja te pole veel kindel, et PHP2Shell on täielikult suletud, käige läbi see nimekiri:
- Kõik kasutusel olevad alt-php harud on uuendatud, muudatuste logis on CVE-2026-109618/109619 või
Build Dateon 21. oktoober 2026 või hilisem. - Paketid
isp-php*on uuendatud ja teenusedphp-fpm*taaskäivitatud (pärast üksuse faili muutumist esmaltsystemctl daemon-reload). - Operatsioonisüsteemi enda PHP on uuendatud või ei teeninda midagi (kontrollige basseine kataloogis
/etc/php-fpm.d/ja seda, kes nende soklitega ühendub). - Apache moodul
isp-libphp8.soon ehitatud pärast 21. oktoobrit või ükski veebileht ei tööta „Apache mooduli“ režiimis. - Roundcube ja phpMyAdmin töötavad parandatud PHP-l nii nginxi kui ka Apache kaudu.
- PHP seaded on kontrollitud kasutaja nimel CageFS-i seest, mitte root’ina.
- CageFS-i skelett on uuendatud (
cagefsctl --update). - Ajutised nginxi blokeeringud on eemaldatud, sealhulgas rida vaikimisi
serverplokis failisnginx.conf. - Väljalülitatud PHP-ga veebilehtedel pole
.phpfaile. - Klientidele on selgitatud, miks versiooninumber paneelis ei muutunud.
Selle öö peamine järeldus on lihtne: juhtpaneeliga majutusserveris ei tähenda „PHP uuendamine“ ühte paketti, vaid viit-kuut erinevat PHP ehitust kolmelt tarnijalt (algversioon CloudLinuxi kaudu, ispmanager, distributsioon), ja osa neist ei teeninda veebilehti, vaid paneeli enda rakendusi. Tasub ette teada, milline PHP millise tee taga asub, enne kui seda öösel vaja läheb.



