# Verschleierten PHP-Code erkennen

> eval, base64_decode und Co.: Woran Sie verschleierten PHP-Code erkennen, wie Sie gefahrlos suchen und legitime Encoder von Schadcode unterscheiden.

Quelle: https://phpsos.de/blog/verschleierter-php-code/  
Stand: 25.10.2026  
Anbieter: PHP SOS, PHP-Notfallhilfe und Server-Sicherheit. Soforthilfe per WhatsApp: https://wa.me/491736494914?text=Hallo%20PHP%20SOS%2C%20wir%20brauchen%20Hilfe%20mit%20unserem%20PHP-Server.%20Firma%3A%20%E2%80%A6%20Website%3A%20%E2%80%A6

**Kurz gesagt:** Verschleierter PHP-Code ist Code, der absichtlich unlesbar gemacht wurde, meist durch Kodierung und Kompression, die erst zur Laufzeit aufgelöst wird. Typische Erkennungsmuster sind `eval` zusammen mit `base64_decode`, `gzinflate` oder `str_rot13`, sehr lange Zeilen, Hex-Zeichenketten und Funktionsnamen, die aus Einzelteilen zusammengesetzt werden. Suchen Sie mit harmlosen grep-Befehlen, führen Sie den Code nie aus und gleichen Sie Funde mit dem Originalpaket ab.

## Warum Angreifer ihren Code verstecken

Wer eine Webshell oder Hintertür auf einem Server ablegt, will, dass sie lange unentdeckt bleibt. Lesbarer Code würde jedem Admin auffallen, der die Datei öffnet, und jeder Scanner fände ihn. Deshalb verpacken Angreifer ihren Code: Er wird kodiert, komprimiert und erst beim Aufruf wieder zusammengesetzt und ausgeführt.

Für PHP2Shell gibt es keine bestätigten Indicators of Compromise. Verschleierter Code ist kein Merkmal dieser Lücke, sondern ein allgemeines Zeichen dafür, dass jemand Code eingeschleust hat, ganz gleich auf welchem Weg. Wie Sie Webshells insgesamt finden und entfernen, beschreibt [Webshell erkennen und entfernen](https://phpsos.de/ratgeber/webshell-erkennen/). Dieser Beitrag konzentriert sich auf die Frage, woran Sie verschleierten Code erkennen.

## eval, base64 und Co.: die typischen Bausteine

Verschleierung folgt fast immer demselben Prinzip: Ein unlesbarer Datenblock wird von einer oder mehreren Funktionen in Code zurückverwandelt, der dann ausgeführt wird. Die folgenden Bausteine tauchen dabei immer wieder auf.

| Baustein | Beispiele | Warum er auffällt |
|---|---|---|
| Ausführung | `eval`, `assert` mit Zeichenkette (bis PHP 7.x), `create_function` (bis PHP 7.x) | führt Text als Code aus |
| Dekodierung | `base64_decode`, `str_rot13`, `hex2bin`, `strrev`, `convert_uudecode` | macht Daten wieder lesbar |
| Dekompression | `gzinflate`, `gzuncompress`, `gzdecode` | entpackt eingebetteten Code |
| Zusammensetzen | `chr()`-Ketten, Verkettung kurzer Teilstücke, `\x`-Escapes | verbirgt Funktionsnamen |
| Dynamischer Aufruf | Variablen als Funktionsname, `call_user_func`, `array_map` mit Zeichenkette | Aufruf erscheint nirgends im Klartext |
| Systemzugriff | `system`, `exec`, `shell_exec`, `passthru`, `proc_open`, `popen` | Befehle auf dem Server |

Laut PHP-Handbuch wertet `assert()` seit PHP 8.0 keine Zeichenketten mehr als Code aus, und `create_function()` wurde in PHP 8.0 entfernt. Auf Servern mit älteren PHP-Versionen bleiben beide relevante Suchbegriffe.

Ein einzelner Baustein ist selten verdächtig, `base64_decode` etwa nutzen viele Anwendungen legitim. Verdächtig wird die Kombination: Dekodierung, deren Ergebnis direkt in eine Ausführung fließt.

## Gefahrlos suchen: harmlose grep-Befehle

Die folgenden Befehle durchsuchen Dateien nur als Text. Sie führen keinen PHP-Code aus. Passen Sie den Pfad an.

```bash
# Ausführung kombiniert mit Dekodierung oder Dekompression
grep -rlE "(eval|assert)\s*\(\s*(base64_decode|gzinflate|gzuncompress|str_rot13|hex2bin)" /var/www --include="*.php*"

# Sehr lange Zeilen (oft gepackter Code)
grep -rlE ".{2000,}" /var/www --include="*.php*"

# Viele Hex-Escapes oder chr()-Ketten in einer Zeile
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*"

# Funktionsaufruf über eine Variable direkt nach einer Zuweisung aus Zeichenketten
grep -rnE "\\\$[a-zA-Z_]+\s*=\s*['\"][a-z_]{4,}['\"]\s*;\s*\\\$[a-zA-Z_]+\s*\(" /var/www --include="*.php*" | head -50
```

Prüfen Sie Treffer zuerst mit `ls -l` und dem Zeitstempel und öffnen Sie sie dann nur als Text, etwa mit `less`. Rufen Sie verdächtige Dateien nie über den Browser auf, denn damit würde der Server sie ausführen.

## Wo verschleierter Code typischerweise sitzt

Verschleierter Code steht selten in einer eigenen, auffälligen Datei. Häufiger wird er in vorhandene Dateien eingefügt, ganz am Anfang oder ganz am Ende, oft nach vielen Leerzeilen, damit er beim Öffnen nicht sofort ins Auge fällt. Beliebt sind Dateien, die bei jedem Aufruf geladen werden: die zentrale `index.php`, Konfigurationsdateien und die Funktionsdateien eines Themes.

Ein besonders unauffälliger Weg führt über die Konfiguration. Mit der Einstellung `auto_prepend_file` lädt PHP vor jedem Skript eine zusätzliche Datei. Steht sie in einer `.user.ini` oder `.htaccess`, die ein Angreifer angelegt hat, läuft sein Code bei jedem Seitenaufruf mit, ohne dass eine einzige Anwendungsdatei verändert wurde. Die eingebundene Datei trägt dabei gern eine harmlose Endung wie `.ico` oder `.png`.

```bash
# Wird vor oder nach jedem Skript zusätzlicher Code geladen?
grep -rnE "auto_(prepend|append)_file" /var/www --include=".user.ini" --include=".htaccess" --include="*.conf" 2>/dev/null

# PHP-Code in Dateien mit Bild- oder Icon-Endung
grep -rlE "<\?php" /var/www --include="*.ico" --include="*.png" --include="*.jpg" --include="*.gif" 2>/dev/null
```

## Legitime Verschleierung von Schadcode unterscheiden

Nicht jeder unlesbare Code ist bösartig. Drei Fälle kommen häufig vor:

1. **Kommerzielle Encoder:** Manche Plugin- und Software-Hersteller schützen ihren Code mit Werkzeugen wie ionCube oder SourceGuardian. Die Dateien sind unlesbar, verweisen aber typischerweise auf den benötigten Loader. Gleichen Sie sie mit dem Originalpaket ab.
2. **Minifizierter oder generierter Code:** Caches und Vorlagen-Engines erzeugen lange Zeilen ohne Umbrüche, allerdings ohne Ausführung von dekodiertem Text.
3. **Eingebettete Daten:** Bilder oder Schriftarten als Base64-Zeichenkette in einer PHP-Datei sind ungewöhnlich, aber harmlos, solange das Ergebnis nicht ausgeführt wird.

Der verlässlichste Test ist der Abgleich mit der Quelle: Stammt die Datei unverändert aus dem Paket des Herstellers, ist sie legitim. Liegt sie in keinem Originalpaket oder weicht davon ab, gehört sie untersucht.

> **Wichtig:**
> Versuchen Sie nicht, verschleierten Code auf dem Produktivserver zu entschlüsseln, etwa indem Sie `eval` durch eine Ausgabe ersetzen und die Datei aufrufen. Schon ein Fehler dabei führt den Schadcode aus. Die Analyse gehört in eine isolierte Umgebung.

## Grenzen der Mustersuche

Angreifer kennen die gängigen Suchbefehle. Sie teilen Funktionsnamen auf, setzen sie zur Laufzeit zusammen oder lagern den eigentlichen Code in die Datenbank, in Bilddateien oder in Konfigurationseinträge aus. Eine Mustersuche findet deshalb viel, aber nicht alles. Warum auch Scanner hier an Grenzen stoßen, erklärt [Malware-Scanner für Websites: Was sie finden und was nicht](https://phpsos.de/blog/grenzen-von-malware-scannern/).

Ein Fund ist zudem selten der einzige. Angreifer verwenden in mehreren Dateien oft denselben Baustein, etwa eine auffällige Variablenbezeichnung oder eine markante Zeichenfolge am Anfang des kodierten Blocks. Suchen Sie nach einem bestätigten Fund deshalb gezielt nach genau dieser Zeichenfolge im gesamten Webverzeichnis, auch in anderen Websites auf demselben Server. So finden Sie Geschwister, die keine der allgemeinen Mustersuchen erfasst hat.

Ergänzen Sie die Suche um den Abgleich mit Originaldateien und um einen Blick in die Datenbank, siehe [Die Datenbank auf eingeschleusten Code prüfen](https://phpsos.de/blog/datenbank-auf-schadcode-pruefen/). Vorbeugend lassen sich nicht benötigte Systemfunktionen sperren, wie im Ratgeber [disable_functions richtig nutzen](https://phpsos.de/ratgeber/disable-functions/) beschrieben.

## Wie hilft PHP SOS konkret?

- **Suchen:** Wir durchsuchen Dateien und Datenbank mit erweiterten Mustern und gleichen gegen Originalpakete ab.
- **Analysieren:** Wir untersuchen verdächtigen Code in einer isolierten Umgebung, ohne Ihr System zu gefährden.
- **Bereinigen:** Mit der [Malware-Entfernung](https://phpsos.de/leistungen/malware-entfernung/) entfernen wir alle Bestandteile und schließen den Einfallsweg.
- **Absichern:** Wir begrenzen PHP-Funktionen und Schreibrechte und überwachen neue oder veränderte Dateien.


## Häufige Fragen

**Ist eval mit base64_decode immer Schadcode?**  
Nicht immer, aber sehr oft. Legitimer Code braucht diese Kombination kaum. In Dateien, die nicht zu Ihrer Anwendung oder einem bekannten Plugin gehören, ist sie ein starkes Warnsignal.

**Darf ich verschleierten Code zum Lesen dekodieren?**  
Nur ohne ihn auszuführen und nicht auf dem Produktivserver. Schon ein versehentliches Ausführen kann Schaden anrichten. Überlassen Sie die Analyse im Zweifel Fachleuten, die mit isolierten Umgebungen arbeiten.

**Warum findet mein Malware-Scanner den Code nicht?**  
Scanner suchen nach bekannten Mustern. Angreifer verändern ihren Code ständig, teilen Funktionsnamen auf oder setzen sie zur Laufzeit zusammen. Ein leerer Scan ist deshalb kein Beweis für einen sauberen Server.

**Was ist mit kommerziell verschlüsselten Plugins?**  
Manche Hersteller schützen ihren Code mit Encodern wie ionCube oder SourceGuardian. Solche Dateien sind unlesbar, aber legitim, wenn sie vom Hersteller stammen. Gleichen Sie sie mit dem Originalpaket ab.

**Hilft disable_functions gegen verschleierten Code?**  
Teilweise. Funktionen wie exec oder system lassen sich sperren, eval dagegen nicht, weil es ein Sprachkonstrukt und keine Funktion ist. Die Sperre erschwert Angreifern den nächsten Schritt, verhindert aber nicht jeden Schadcode.

## Quellen

- [PHP-Handbuch: assert()](https://www.php.net/manual/de/function.assert.php)
- [PHP-Handbuch: create_function()](https://www.php.net/manual/de/function.create-function.php)
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
