# Genkend tilsløret PHP-kode

> eval, base64_decode og lignende: sådan genkender I tilsløret PHP-kode, søger risikofrit og skiller legitime encodere fra skadelig kode.

Kilde: https://phpsos.de/da/blog/verschleierter-php-code/  
Status: 25.10.2026  
Udbyder: PHP SOS, PHP-nødhjælp og serversikkerhed. Akut hjælp på WhatsApp: https://wa.me/491736494914?text=Hej%20PHP%20SOS%2C%20vi%20har%20brug%20for%20hj%C3%A6lp%20med%20vores%20PHP-server.%20Firma%3A%20%E2%80%A6%20Website%3A%20%E2%80%A6

**Kort sagt:** Tilsløret PHP-kode er kode, der med vilje er gjort ulæselig, oftest ved kodning og komprimering, som først opløses under kørslen. Typiske genkendelsesmønstre er `eval` sammen med `base64_decode`, `gzinflate` eller `str_rot13`, meget lange linjer, hex-tegnstrenge og funktionsnavne, der sættes sammen af enkeltdele. Søg med harmløse grep-kommandoer, udfør aldrig koden, og afstem fund med den oprindelige pakke.

## Hvorfor angribere skjuler deres kode

Den, der lægger en webshell eller bagdør på en server, vil have, at den forbliver uopdaget længe. Læselig kode ville falde i øjnene på enhver administrator, der åbner filen, og enhver scanner ville finde den. Derfor pakker angribere deres kode ind: Den kodes, komprimeres og sættes først sammen igen og udføres ved kaldet.

For PHP2Shell findes der ingen bekræftede indicators of compromise. Tilsløret kode er ikke et kendetegn ved denne sårbarhed, men et generelt tegn på, at nogen har smuglet kode ind, uanset ad hvilken vej. Hvordan I overordnet finder og fjerner webshells, beskriver [Genkend og fjern webshells](https://phpsos.de/da/ratgeber/webshell-erkennen/). Dette indlæg koncentrerer sig om spørgsmålet, hvordan I genkender tilsløret kode.

## eval, base64 og lignende: de typiske byggesten

Tilsløring følger næsten altid samme princip: En ulæselig datablok forvandles af en eller flere funktioner tilbage til kode, der så udføres. Følgende byggesten dukker op igen og igen.

| Byggesten | Eksempler | Hvorfor den falder i øjnene |
|---|---|---|
| Udførelse | `eval`, `assert` med tegnstreng (til og med PHP 7.x), `create_function` (til og med PHP 7.x) | udfører tekst som kode |
| Afkodning | `base64_decode`, `str_rot13`, `hex2bin`, `strrev`, `convert_uudecode` | gør data læselige igen |
| Dekomprimering | `gzinflate`, `gzuncompress`, `gzdecode` | pakker indlejret kode ud |
| Sammensætning | `chr()`-kæder, sammenkædning af korte delstykker, `\x`-escapes | skjuler funktionsnavne |
| Dynamisk kald | variabler som funktionsnavn, `call_user_func`, `array_map` med tegnstreng | kaldet optræder ingen steder i klartekst |
| Systemadgang | `system`, `exec`, `shell_exec`, `passthru`, `proc_open`, `popen` | kommandoer på serveren |

Ifølge PHP-manualen vurderer `assert()` siden PHP 8.0 ikke længere tegnstrenge som kode, og `create_function()` blev fjernet i PHP 8.0. På servere med ældre PHP-versioner forbliver begge relevante søgebegreber.

En enkelt byggesten er sjældent mistænkelig, `base64_decode` bruger mange applikationer f.eks. legitimt. Mistænkelig bliver kombinationen: afkodning, hvis resultat flyder direkte ind i en udførelse.

## Søg risikofrit: harmløse grep-kommandoer

Følgende kommandoer gennemsøger filer kun som tekst. De udfører ingen PHP-kode. Tilpas stien.

```bash
# Udførelse kombineret med afkodning eller dekomprimering
grep -rlE "(eval|assert)\s*\(\s*(base64_decode|gzinflate|gzuncompress|str_rot13|hex2bin)" /var/www --include="*.php*"

# Meget lange linjer (ofte pakket kode)
grep -rlE ".{2000,}" /var/www --include="*.php*"

# Mange hex-escapes eller chr()-kæder i én linje
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*"

# Funktionskald via en variabel direkte efter en tildeling af tegnstrenge
grep -rnE "\\\$[a-zA-Z_]+\s*=\s*['\"][a-z_]{4,}['\"]\s*;\s*\\\$[a-zA-Z_]+\s*\(" /var/www --include="*.php*" | head -50
```

Kontrollér først fund med `ls -l` og tidsstemplet, og åbn dem derefter kun som tekst, f.eks. med `less`. Kald aldrig mistænkelige filer via browseren, for dermed ville serveren udføre dem.

## Hvor tilsløret kode typisk sidder

Tilsløret kode står sjældent i en egen, påfaldende fil. Hyppigere indsættes den i eksisterende filer, helt i begyndelsen eller helt til sidst, ofte efter mange tomme linjer, så den ikke straks falder i øjnene ved åbningen. Populære er filer, der indlæses ved hvert kald: den centrale `index.php`, konfigurationsfiler og et temas funktionsfiler.

En særligt upåfaldende vej går via konfigurationen. Med indstillingen `auto_prepend_file` indlæser PHP en ekstra fil før hvert script. Står den i en `.user.ini` eller `.htaccess`, som en angriber har oprettet, kører hans kode med ved hvert sidekald, uden at en eneste applikationsfil er ændret. Den indbundne fil har gerne en harmløs endelse som `.ico` eller `.png`.

```bash
# Indlæses der ekstra kode før eller efter hvert script?
grep -rnE "auto_(prepend|append)_file" /var/www --include=".user.ini" --include=".htaccess" --include="*.conf" 2>/dev/null

# PHP-kode i filer med billed- eller ikonendelse
grep -rlE "<\?php" /var/www --include="*.ico" --include="*.png" --include="*.jpg" --include="*.gif" 2>/dev/null
```

## Skel legitim tilsløring fra skadelig kode

Ikke enhver ulæselig kode er ondsindet. Tre tilfælde forekommer hyppigt:

1. **Kommercielle encodere:** Nogle plugin- og softwareproducenter beskytter deres kode med værktøjer som ionCube eller SourceGuardian. Filerne er ulæselige, men henviser typisk til den nødvendige loader. Afstem dem med den oprindelige pakke.
2. **Minificeret eller genereret kode:** Cacher og skabelonmotorer producerer lange linjer uden linjeskift, dog uden udførelse af afkodet tekst.
3. **Indlejrede data:** Billeder eller skrifttyper som Base64-tegnstreng i en PHP-fil er usædvanligt, men harmløst, så længe resultatet ikke udføres.

Den mest pålidelige test er afstemningen med kilden: Stammer filen uændret fra producentens pakke, er den legitim. Ligger den i ingen oprindelig pakke eller afviger fra den, bør den undersøges.

> **Vigtigt:**
> Forsøg ikke at dekryptere tilsløret kode på produktionsserveren, f.eks. ved at erstatte `eval` med et output og kalde filen. Allerede en fejl derved udfører den skadelige kode. Analysen hører hjemme i et isoleret miljø.

## Mønstersøgningens grænser

Angribere kender de gængse søgekommandoer. De deler funktionsnavne op, sætter dem sammen under kørslen eller udlægger den egentlige kode i databasen, i billedfiler eller i konfigurationsposter. En mønstersøgning finder derfor meget, men ikke alt. Hvorfor også scannere støder på grænser her, forklarer [Malware-scannere til websites: Hvad de finder, og hvad de ikke finder](https://phpsos.de/da/blog/grenzen-von-malware-scannern/).

Et fund er desuden sjældent det eneste. Angribere bruger i flere filer ofte den samme byggesten, f.eks. en påfaldende variabelbetegnelse eller en markant tegnfølge i begyndelsen af den kodede blok. Søg derfor efter et bekræftet fund målrettet efter netop denne tegnfølge i hele webmappen, også i andre websites på samme server. Sådan finder I søskende, som ingen af de generelle mønstersøgninger har fanget.

Suppler søgningen med afstemningen mod originalfiler og et kig i databasen, se [Kontrollér databasen for indsmuglet kode](https://phpsos.de/da/blog/datenbank-auf-schadcode-pruefen/). Forebyggende kan ikke nødvendige systemfunktioner spærres, som beskrevet i vejledningen [Brug disable_functions korrekt](https://phpsos.de/da/ratgeber/disable-functions/).

## Hvordan hjælper PHP SOS konkret?

- **Søg:** Vi gennemsøger filer og database med udvidede mønstre og afstemmer mod originale pakker.
- **Analysér:** Vi undersøger mistænkelig kode i et isoleret miljø uden at bringe jeres system i fare.
- **Ryd op:** Med [malwarefjernelsen](https://phpsos.de/da/leistungen/malware-entfernung/) fjerner vi alle bestanddele og lukker indfaldsvejen.
- **Sikr:** Vi begrænser PHP-funktioner og skriverettigheder og overvåger nye eller ændrede filer.


## Ofte stillede spørgsmål

**Er eval med base64_decode altid skadelig kode?**  
Ikke altid, men meget ofte. Legitim kode har næppe brug for denne kombination. I filer, der ikke hører til jeres applikation eller et kendt plugin, er den et stærkt advarselstegn.

**Må jeg afkode tilsløret kode for at læse den?**  
Kun uden at udføre den og ikke på produktionsserveren. Allerede en utilsigtet udførelse kan gøre skade. Overlad i tvivlstilfælde analysen til fagfolk, der arbejder med isolerede miljøer.

**Hvorfor finder min malware-scanner ikke koden?**  
Scannere søger efter kendte mønstre. Angribere ændrer hele tiden deres kode, deler funktionsnavne op eller sætter dem sammen under kørslen. En tom scanning er derfor intet bevis for en ren server.

**Hvad med kommercielt krypterede plugins?**  
Nogle producenter beskytter deres kode med encodere som ionCube eller SourceGuardian. Sådanne filer er ulæselige, men legitime, hvis de stammer fra producenten. Afstem dem med den oprindelige pakke.

**Hjælper disable_functions mod tilsløret kode?**  
Delvist. Funktioner som exec eller system kan spærres, eval derimod ikke, fordi det er en sprogkonstruktion og ikke en funktion. Spærringen gør angribernes næste skridt sværere, men forhindrer ikke al skadelig kode.

## Kilder

- [PHP-manualen: assert()](https://www.php.net/manual/de/function.assert.php)
- [PHP-manualen: create_function()](https://www.php.net/manual/de/function.create-function.php)
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
