Draait PHP onopgemerkt op je ColdFusion-server? Hoe je dit controleert en verwijdert

Ik herinner me een tijd dat ik jaren kon gaan zonder een beveiligingsfix toe te passen. Nu voelt het alsof ik elke paar weken iets moet bijhouden: hier een patch, daar een mitigatie, een bot die hamert op een pagina die niet zou mogen bestaan. Dat is het leven in het AI-tijdperk.

Toen ik onlangs probeerde in te loggen op mijn testblog, weigerde de admin-pagina mij met een eenvoudige IIS-fout: 403 Forbidden, met een melding dat multipart/form-data-verzoeken werden geblokkeerd door een PHP-mitigatie. Mijn blogs draaien op ColdFusion; ze bevatten geen enkele regel PHP. Waarom stopte een PHP-beveiligingsregel mij dan bij het inloggen?

Wat er is gebeurd

De timing was geen toeval. Op 21 oktober 2026 bracht PHP noodpatches uit voor twee kritieke lekken waarmee een ongeauthentiseerde aanvraag code op de server kon uitvoeren, bijgenaamd PHP2Shell. Elke PHP-setup die webverzoeken afhandelt was getroffen: PHP-FPM, Apache's mod_php, php-cgi, FrankenPHP en LiteSpeed. De oplossing is om een nieuwe versie van PHP te installeren (8.5.12, 8.4.27, 8.3.36 of 8.2.35).

Mijn hostingbedrijf reageerde in dezelfde week met een beveiligingsregel voor de webserver. De regel stond in de serverbrede URL Rewrite-regels van IIS, waardoor deze voor elke site op de server gold en elk verzoek blokkeerde waarvan het content-type multipart/form-data was, ongeacht het adres. Dit is de codering die een browser gebruikt voor elk formulier dat een bestand kan uploaden, en veel formulieren gebruiken dit zelfs als ze dat niet doen.

Het eigen advies van PHP bevat het blokkeren van deze verzoeken niet. Het advies is om te patchen en, tot die tijd, session.uploadprogress.enabled uit te schakelen en postmax_size te verlagen. Omdat verschillende officiële mitigaties betrekking hebben op hoe PHP uploads afhandelt, begrijp ik waarom een host voor de meest drastische maatregel zou kiezen. Voor een PHP-site is dat een bot maar begrijpelijk schild. Voor mijn ColdFusion-sites betekende het dat het admin-inlogformulier, elke afbeelding-upload en elke bestands-upload op alle vier de sites tegelijk faalde. De regel matchte elk adres, niet alleen de .php-adressen.

Zodra ik de regel had beperkt tot .php-adressen (zie hieronder), werkte alles weer. Toen stelde ik mezelf de voor de hand liggende vraag: waarom staat PHP überhaupt op deze server? Het antwoord was een phpMyAdmin-installatie die ik jaren geleden had aangevraagd om één MySQL-database te beheren. Het stond er nog steeds, nog steeds in een site-map, en de inlogpagina was open voor het hele internet. De host schakelde de algemene regel uit zodra ik meeldeerde dat PHP niet meer in gebruik was, waarna ik ging zoeken naar alles wat PHP anders had achtergelaten.

Controle 1: Stuurt IIS .php-bestanden naar PHP?

IIS draait PHP alleen als een handler mapping dit aangeeft. Open PowerShell als Administrator op de server:

Import-Module WebAdministration
Get-WebHandler -PSPath 'IIS:\Sites' | Where-Object { $_.path -like '*.php' } | Select-Object name, path, scriptProcessor

Als er niets wordt geprint, draait IIS geen PHP. Als er iets verschijnt zoals hieronder, dan doet het dat wel voor elke site die de serverinstellingen overneemt:

name    path  scriptProcessor
----    ----  ---------------
FastCGI *.php C:\php\php-cgi.exe

Noteer de naam van de handler en het pad naar de scriptProcessor. Je hebt beide nodig als je deze verwijdert.

Controle 2: Staan er PHP-bestanden in je sites?

Get-ChildItem -Recurse van PowerShell werkt, maar op een server met jaren aan geüploade afbeeldingen kan dit minuten duren. De Windows dir is veel sneller. Dit telt de PHP-bestanden onder je webroot:

cmd /c "dir C:\inetpub\wwwroot\*.php /s /b" 2>$null | Measure-Object | Select-Object Count

Als het aantal niet nul is, laat dit zien in welke mappen ze staan, met de drukste mappen bovenaan:

cmd /c "dir C:\inetpub\wwwroot\*.php /s /b" 2>$null | ForEach-Object { Split-Path $_ -Parent } | Group-Object | Sort-Object Count -Descending | Select-Object -First 25 Count, Name | Format-Table -AutoSize

In mijn geval werden ongeveer 4.500 bestanden gevonden in twee mappen, beide van phpMyAdmin: één in een site en een tweede kopie in de webroot, die door de Default Web Site van IIS werd geserveerd aan iedereen die het kale IP-adres van de server bezocht.

Als je PHP-bestanden vindt die je niet herkent, vooral als ze verspreid liggen door afbeeldingen- of uploadmappen, of onlangs zijn gewijzigd, stop dan en behandel dit als een mogelijke inbraak. Aanvallers plaatsen graag kleine PHP "web shells" in uploadmappen. Dit lijst de meest recent gewijzigde bestanden op:

cmd /c "dir C:\inetpub\wwwroot\*.php /s /b" 2>$null | Get-Item | Sort-Object LastWriteTime -Descending | Select-Object -First 15 LastWriteTime, Length, FullName | Format-Table -AutoSize

Controle 3: Is PHP geïnstalleerd of actief?

Get-Process php* -ErrorAction SilentlyContinue | Select-Object Name, Id, StartTime
Test-Path C:\php

Het ontbreken van een php-cgi.exe-proces betekent alleen dat er onlangs geen PHP-pagina is opgevraagd. IIS start dit on-demand. De handler uit Controle 1 is wat echt telt.

Controle 4: Wat is er zichtbaar vanaf het internet?

Probeer vanaf een willekeurige computer de gebruikelijke adressen op je eigen sites:

foreach ($path in "phpmyadmin/", "phpMyAdmin/", "pma/", "info.php") {
    $url = "https://www.mysite.com/$path"
    try { $r = Invoke-WebRequest $url -UseBasicParsing -TimeoutSec 15; "$($r.StatusCode) $url" }
    catch { "$($_.Exception.Response.StatusCode.value__) $url" }
}

Alles wat met een 200 antwoordt, verdient een inspectie. Een phpMyAdmin-inlogpagina die openstaat naar het internet is een open uitnodiging: bots proberen de hele dag wachtwoorden, en elke poging start PHP en communiceert met je database.

Veilig verwijderen

Voer deze stappen in de opgegeven volgorde uit en maak eerst een back-up. Elke stap is omkeerbaar.

1. Back-up van de IIS-configuratie

IIS kan een snapshot maken van de eigen configuratie en deze met één commando herstellen:

& "$env:windir\System32\inetsrv\appcmd.exe" add backup "before-php-removal"

Om alles ongedaan te maken: appcmd.exe restore backup "before-php-removal".

2. Verplaats phpMyAdmin (en andere PHP-apps) uit de webmappen

Verplaats ze, verwijder ze niet. Het configuratiebestand kan een database-wachtwoord bevatten; bewaar het dus een paar weken op een privélocatie voor het geval dat iets het toch nodig blijkt te hebben:

New-Item -ItemType Directory -Force C:\Temp\removed-php | Out-Null
Move-Item C:\inetpub\wwwroot\mysite\phpmyadmin C:\Temp\removed-php\phpmyadmin-mysite

Als Move-Item meldt dat een bestand in gebruik is, dan heeft PHP het openstaan. Voer iisreset /stop uit, verplaats het bestand, en voer dan iisreset /start uit (je sites zijn dan enkele seconden offline). Als de melding "Could not find a part of the path" verschijnt, dan ontbreekt de doelmap, niet de bronmap.

Voor het beheren van MySQL kun je daarna beter een desktoptool op de server gebruiken via Remote Desktop, zoals HeidiSQL of MySQL Workbench. Deze doen alles wat phpMyAdmin deed, maar zonder een publieke inlogpagina.

3. Blokkeer .php bij de deur

De request filtering van IIS kan een bestandsextensie afwijzen voordat een handler deze ziet. Door dit op serverniveau toe te voegen, geldt het voor elke site:

Add-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter 'system.webServer/security/requestFiltering/fileExtensions' -Name '.' -Value @{ fileExtension = '.php'; allowed = 'false' }

Nu krijgt elk .php-adres een "404 - the request filtering module is configured to deny the file extension", of het bestand nu bestaat of niet.

4. Verwijder de handler en de FastCGI-entry

Gebruik de handlernaam uit Controle 1 (bij mij was dit FastCGI) en het pad naar php-cgi.exe:

Remove-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter 'system.webServer/handlers' -Name '.' -AtElement @{ name = 'FastCGI' }
Remove-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter 'system.webServer/fastCgi' -Name '.' -AtElement @{ fullPath = 'C:\php\php-cgi.exe' }

Voer Controle 1 opnieuw uit. Er zou nu niets geprint moeten worden.

5. Deinstalleer PHP als laatste stap

Als PHP via een installatieprogramma is geïnstalleerd, verwijder het dan via Apps > Geïnstalleerde apps. Als het slechts een map is zoals C:\php, hernoem deze dan naar C:\php-removed voor een paar weken voordat je hem definitief verwijdert. Als er iets klaagt, weet je het meteen en is het slechts één hernoeming om het terug te zetten.

Als PHP door je host is geïnstalleerd, vraag dan eerst toestemming voordat je stap 5 uitvoert. Hun eigen monitoringscripts hebben het waarschijnlijk niet nodig, maar het is hun installatie.

Als je een dergelijke regel toch moet behouden

Misschien draai je ergens wel PHP, of wil je host de regel behouden. Beperk de regel dan tot PHP-adressen in plaats van elk adres. De regel <match url=".*" /> was het hele probleem. Dit verandert de regel naar alleen .php-adressen, waardoor de formulieren van ColdFusion met rust worden gelaten (gebruik de eigen naam van de regel):

Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter "system.webServer/rewrite/globalRules/rule[@name='PHP Mitigation']/match" -Name url -Value '\.php($|/)'

Let op de enkele aanhalingstekens rond het patroon. Set-WebConfigurationProperty met enkele aanhalingstekens werkte in één keer. Controleer het resultaat met Select-String op C:\Windows\System32\inetsrv\config\applicationHost.config.

Lucee op Linux en Apache

Dezelfde vragen, maar andere commando's:

php -v                          ## Is de PHP command-line geïnstalleerd?
apachectl -M | grep -i php      ## Draait Apache PHP (php_module, proxy_fcgi naar php-fpm)?
find /var/www /home -name "*.php" 2>/dev/null | head -50

Op Debian en Ubuntu stop je Apache in het draaien van PHP met sudo a2dismod php8.3 (vervang door jouw versie) en sudo systemctl restart apache2. Verwijder daarna de pakketten met je package manager zodra je zeker weet dat niets ze nodig heeft. Controlepanelen zoals Virtualmin installeren vaak PHP voor hun eigen tools, dus controleer dit eerst.

Valkuilen

  • Serverbrede regels: Een serverbrede regel vangt elke site. Een regel geschreven voor PHP blokkeerde mijn ColdFusion-inloggegevens en uploads. Als er plotseling een 403-fout verschijnt, lees dan de volledige IIS-foutpagina; bij mij werd de naam van de regel genoemd.
  • Host-scripts: Hosts voeren hun scripts opnieuw uit. Die van mij maakte de regel bij elke run opnieuw aan, waardoor een lokale fix ongemerkt ongedaan kon worden gemaakt. Meld je host wat je hebt gewijzigd en waarom.
  • Configuratie-aanpassingen: Een bewerking kan in de verkeerde web.config terechtkomen. Mijn eerste fix ging in de web.config van een specifieke site, en er veranderde niets.
  • Trusted Cache: Als je tijdens het diagnosticeren handmatig een .cfm-bestand vervangt, blijft ColdFusion de oude gecompileerde kopie draaien totdat je de cache wist. Een gloednieuwe bestandsnaam is een snelle workaround.
  • Patchen vs. Verwijderen: Het verwijderen van PHP is geen vervanging voor patchen. Als je PHP wel gebruikt, update het dan nu naar 8.5.12, 8.4.27, 8.3.36 of 8.2.35 (of nieuwer), en zet session.upload_progress.enabled = 0 in php.ini totdat je dat kunt. PHP 8.1 en oudere versies krijgen geen updates meer van het PHP-project. Verwijderen is alleen het juiste antwoord als er niets gebruik van maakt.

Verdere lectuur

  • PHP-aankondigingen oktober 2026, inclusief beveiligingsreleases en mitigaties: php.net news archive, 2026
  • BleepingComputer: PHP ships emergency patches for critical PHP2Shell flaws
  • DEVCORE-waarschuwing voor het PHP-CGI lek van 2024: Security Alert: CVE-2024-4577, PHP CGI Argument Injection Vulnerability
  • Charlie Arehart: ColdFusion Lockdown/Security guides (diverse gidsen over lockdown en IIS request filtering).
  • Adobe lockdown guides: ColdFusion 2025 Lockdown Guide en ColdFusion 2023 Lockdown Guide (PDF's).
  • Microsoft IIS referentie: File Name Extensions (request filtering), Handlers and FastCGI.