Actuele situatie: PHP2Shell. Twee kritieke PHP-kwetsbaarheden (CVSS 9.2) maken schadelijke code zonder inloggen mogelijk. Patches sinds 21-10-2026.Wat u nu moet doen →

Versluierde PHP-code herkennen

Onleesbare PHP-code met eval en base64_decode is een klassiek teken van ingebrachte schadelijke code. Welke patronen u zoekt, hoe u ze ongevaarlijk vindt en wanneer versluiering legitiem is.

Stand 5 min. leestijdDetectie en forensisch onderzoek

Kort gezegd: Versluierde PHP-code is code die opzettelijk onleesbaar is gemaakt, meestal door codering en compressie die pas tijdens de uitvoering wordt opgelost. Typische herkenningspatronen zijn eval samen met base64_decode, gzinflate of str_rot13, zeer lange regels, hex-tekenreeksen en functienamen die uit onderdelen worden samengesteld. Zoek met ongevaarlijke grep-opdrachten, voer de code nooit uit en vergelijk vondsten met het oorspronkelijke pakket.

Waarom aanvallers hun code verbergen

Wie een webshell of achterdeur op een server plaatst, wil dat die lang onontdekt blijft. Leesbare code zou elke beheerder opvallen die het bestand opent, en elke scanner zou haar vinden. Daarom verpakken aanvallers hun code: ze wordt gecodeerd, gecomprimeerd en pas bij de aanroep weer samengesteld en uitgevoerd.

Voor PHP2Shell bestaan geen bevestigde Indicators of Compromise. Versluierde code is geen kenmerk van dit lek, maar een algemeen teken dat iemand code heeft ingebracht, ongeacht langs welke weg. Hoe u webshells in het algemeen vindt en verwijdert, beschrijft Webshell herkennen en verwijderen. Dit artikel richt zich op de vraag waaraan u versluierde code herkent.

eval, base64 en co.: de typische bouwstenen

Versluiering volgt bijna altijd hetzelfde principe: een onleesbaar datablok wordt door een of meer functies teruggezet in code, die dan wordt uitgevoerd. De volgende bouwstenen duiken daarbij steeds weer op.

Bouwsteen Voorbeelden Waarom hij opvalt
Uitvoering eval, assert met tekenreeks (tot PHP 7.x), create_function (tot PHP 7.x) voert tekst uit als code
Decodering base64_decode, str_rot13, hex2bin, strrev, convert_uudecode maakt gegevens weer leesbaar
Decompressie gzinflate, gzuncompress, gzdecode pakt ingebedde code uit
Samenstellen chr()-ketens, aaneenschakeling van korte stukjes, \x-escapes verbergt functienamen
Dynamische aanroep variabelen als functienaam, call_user_func, array_map met tekenreeks aanroep staat nergens in klare tekst
Systeemtoegang system, exec, shell_exec, passthru, proc_open, popen opdrachten op de server

Volgens de PHP-handleiding evalueert assert() sinds PHP 8.0 geen tekenreeksen meer als code, en is create_function() in PHP 8.0 verwijderd. Op servers met oudere PHP-versies blijven beide relevante zoektermen.

Een afzonderlijke bouwsteen is zelden verdacht, base64_decode gebruiken veel toepassingen bijvoorbeeld legitiem. Verdacht wordt de combinatie: decodering waarvan het resultaat rechtstreeks in een uitvoering vloeit.

Ongevaarlijk zoeken: onschuldige grep-opdrachten

De volgende opdrachten doorzoeken bestanden alleen als tekst. Ze voeren geen PHP-code uit. Pas het pad aan.

# Uitvoering gecombineerd met decodering of decompressie
grep -rlE "(eval|assert)\s*\(\s*(base64_decode|gzinflate|gzuncompress|str_rot13|hex2bin)" /var/www --include="*.php*"

# Zeer lange regels (vaak ingepakte code)
grep -rlE ".{2000,}" /var/www --include="*.php*"

# Veel hex-escapes of chr()-ketens in één regel
grep -rlE "(\\\\x[0-9a-fA-F]{2}){20,}" /var/www --include="*.php*"
grep -rlE "(chr\s*\(\s*[0-9]+\s*\)\s*\.\s*){8,}" /var/www --include="*.php*"

# Functie-aanroep via een variabele direct na een toewijzing uit tekenreeksen
grep -rnE "\\\$[a-zA-Z_]+\s*=\s*['\"][a-z_]{4,}['\"]\s*;\s*\\\$[a-zA-Z_]+\s*\(" /var/www --include="*.php*" | head -50

Controleer treffers eerst met ls -l en de tijdstempel en open ze dan alleen als tekst, bijvoorbeeld met less. Roep verdachte bestanden nooit via de browser aan, want daarmee zou de server ze uitvoeren.

Waar versluierde code typisch zit

Versluierde code staat zelden in een eigen, opvallend bestand. Vaker wordt ze in bestaande bestanden ingevoegd, helemaal aan het begin of helemaal aan het eind, vaak na veel lege regels, zodat ze bij het openen niet meteen opvalt. Geliefd zijn bestanden die bij elke aanroep worden geladen: de centrale index.php, configuratiebestanden en de functiebestanden van een thema.

Een bijzonder onopvallende weg loopt via de configuratie. Met de instelling auto_prepend_file laadt PHP vóór elk script een extra bestand. Staat ze in een .user.ini of .htaccess die een aanvaller heeft aangemaakt, dan draait zijn code bij elke pagina-aanroep mee, zonder dat één enkel toepassingsbestand is gewijzigd. Het ingesloten bestand draagt daarbij graag een onschuldige extensie zoals .ico of .png.

# Wordt er vóór of na elk script extra code geladen?
grep -rnE "auto_(prepend|append)_file" /var/www --include=".user.ini" --include=".htaccess" --include="*.conf" 2>/dev/null

# PHP-code in bestanden met afbeeldings- of icoonextensie
grep -rlE "<\?php" /var/www --include="*.ico" --include="*.png" --include="*.jpg" --include="*.gif" 2>/dev/null

Legitieme versluiering van schadelijke code onderscheiden

Niet elke onleesbare code is kwaadaardig. Drie gevallen komen vaak voor:

  1. Commerciële encoders: Sommige plug-in- en softwarefabrikanten beschermen hun code met hulpmiddelen zoals ionCube of SourceGuardian. De bestanden zijn onleesbaar, maar verwijzen typisch naar de benodigde loader. Vergelijk ze met het oorspronkelijke pakket.
  2. Geminificeerde of gegenereerde code: Caches en sjabloonengines produceren lange regels zonder regeleinden, echter zonder uitvoering van gedecodeerde tekst.
  3. Ingebedde gegevens: Afbeeldingen of lettertypen als base64-tekenreeks in een PHP-bestand zijn ongewoon, maar onschuldig zolang het resultaat niet wordt uitgevoerd.

De betrouwbaarste test is de vergelijking met de bron: komt het bestand ongewijzigd uit het pakket van de fabrikant, dan is het legitiem. Staat het in geen enkel oorspronkelijk pakket of wijkt het ervan af, dan moet het worden onderzocht.

Belangrijk

Probeer versluierde code niet op de productieserver te ontsleutelen, bijvoorbeeld door eval te vervangen door een uitvoer en het bestand aan te roepen. Al een fout daarbij voert de schadelijke code uit. De analyse hoort in een geïsoleerde omgeving.

Grenzen van de patroonzoektocht

Aanvallers kennen de gangbare zoekopdrachten. Ze splitsen functienamen, stellen ze tijdens de uitvoering samen of verplaatsen de eigenlijke code naar de database, afbeeldingsbestanden of configuratievermeldingen. Een patroonzoektocht vindt daarom veel, maar niet alles. Waarom ook scanners hier tegen grenzen aanlopen, legt Malwarescanners voor websites: wat ze vinden en wat niet uit.

Een vondst is bovendien zelden de enige. Aanvallers gebruiken in meerdere bestanden vaak dezelfde bouwsteen, zoals een opvallende variabelenaam of een markante tekenreeks aan het begin van het gecodeerde blok. Zoek na een bevestigde vondst daarom gericht naar precies die tekenreeks in de hele webmap, ook in andere websites op dezelfde server. Zo vindt u broertjes die geen van de algemene patroonzoekopdrachten heeft opgespoord.

Vul de zoektocht aan met de vergelijking met originele bestanden en een blik in de database, zie De database controleren op ingebrachte code. Preventief kunnen niet benodigde systeemfuncties worden geblokkeerd, zoals beschreven in de gids disable_functions correct gebruiken.

Hoe helpt PHP SOS concreet?

  • Zoeken: Wij doorzoeken bestanden en database met uitgebreide patronen en vergelijken met oorspronkelijke pakketten.
  • Analyseren: Wij onderzoeken verdachte code in een geïsoleerde omgeving, zonder uw systeem in gevaar te brengen.
  • Opschonen: Met de malwareverwijdering verwijderen wij alle onderdelen en dichten wij de toegangsweg.
  • Beveiligen: Wij beperken PHP-functies en schrijfrechten en bewaken nieuwe of gewijzigde bestanden.

Veelgestelde vragen

Is eval met base64_decode altijd schadelijke code?

Niet altijd, maar heel vaak. Legitieme code heeft deze combinatie nauwelijks nodig. In bestanden die niet bij uw toepassing of een bekende plug-in horen, is ze een sterk waarschuwingssignaal.

Mag ik versluierde code decoderen om te lezen?

Alleen zonder haar uit te voeren en niet op de productieserver. Al een onbedoelde uitvoering kan schade aanrichten. Laat de analyse in geval van twijfel over aan specialisten die met geïsoleerde omgevingen werken.

Waarom vindt mijn malwarescanner de code niet?

Scanners zoeken naar bekende patronen. Aanvallers wijzigen hun code voortdurend, splitsen functienamen of stellen ze tijdens de uitvoering samen. Een lege scan is daarom geen bewijs voor een schone server.

Hoe zit het met commercieel versleutelde plug-ins?

Sommige fabrikanten beschermen hun code met encoders zoals ionCube of SourceGuardian. Zulke bestanden zijn onleesbaar, maar legitiem als ze van de fabrikant komen. Vergelijk ze met het oorspronkelijke pakket.

Helpt disable_functions tegen versluierde code?

Gedeeltelijk. Functies zoals exec of system kunnen worden geblokkeerd, eval daarentegen niet, omdat het een taalconstructie is en geen functie. De blokkade bemoeilijkt de volgende stap voor aanvallers, maar voorkomt niet elke schadelijke code.

Bronnen

Direct contact

Elk uur telt. Schrijf ons nu.

Beschrijf kort het systeem, de PHP-versie en wat u opmerkt. Wij nemen contact op, brengen de situatie in kaart en werken op afstand tot het incident is afgerond en gedocumenteerd.

Directe hulp