# Reconnaître le code PHP obfusqué

> eval, base64_decode et consorts : comment reconnaître du code PHP obfusqué, le rechercher sans danger et distinguer les encodeurs légitimes du code malveillant.

Source : https://phpsos.de/fr/blog/verschleierter-php-code/  
État : 25/10/2026  
Fournisseur : PHP SOS, Assistance d'urgence PHP et sécurité des serveurs. Aide immédiate par WhatsApp : https://wa.me/491736494914?text=Bonjour%20PHP%20SOS%2C%20nous%20avons%20besoin%20d%27aide%20avec%20notre%20serveur%20PHP.%20Entreprise%20%3A%20%E2%80%A6%20Site%20web%20%3A%20%E2%80%A6

**En bref :** le code PHP obfusqué est un code rendu volontairement illisible, le plus souvent par encodage et compression qui ne sont résolus qu'à l'exécution. Les motifs de détection typiques sont `eval` associé à `base64_decode`, `gzinflate` ou `str_rot13`, des lignes très longues, des chaînes hexadécimales et des noms de fonctions assemblés à partir de morceaux. Cherchez avec des commandes grep inoffensives, n'exécutez jamais le code et comparez les découvertes avec le paquet d'origine.

## Pourquoi les attaquants cachent leur code

Qui dépose un webshell ou une porte dérobée sur un serveur veut qu'il reste longtemps indétecté. Un code lisible se remarquerait chez tout administrateur qui ouvre le fichier, et tout scanner le trouverait. Les attaquants emballent donc leur code : il est encodé, compressé et ne se reconstitue et ne s'exécute qu'à l'appel.

Pour PHP2Shell, il n'existe pas d'indicateurs de compromission (Indicators of Compromise) confirmés. Le code obfusqué n'est pas une caractéristique de cette faille, mais un signe général que quelqu'un a injecté du code, quelle que soit la voie. La façon de trouver et de supprimer l'ensemble des webshells est décrite dans [Reconnaître et supprimer un webshell](https://phpsos.de/fr/ratgeber/webshell-erkennen/). Cet article se concentre sur la question de savoir à quoi reconnaître du code obfusqué.

## eval, base64 et consorts : les composants typiques

L'obfuscation suit presque toujours le même principe : un bloc de données illisible est retransformé par une ou plusieurs fonctions en code, qui est ensuite exécuté. Les composants suivants reviennent sans cesse.

| Composant | Exemples | Pourquoi il se remarque |
|---|---|---|
| Exécution | `eval`, `assert` avec chaîne de caractères (jusqu'à PHP 7.x), `create_function` (jusqu'à PHP 7.x) | exécute du texte comme code |
| Décodage | `base64_decode`, `str_rot13`, `hex2bin`, `strrev`, `convert_uudecode` | rend de nouveau les données lisibles |
| Décompression | `gzinflate`, `gzuncompress`, `gzdecode` | décompresse du code intégré |
| Assemblage | chaînes de `chr()`, concaténation de petits fragments, échappements `\x` | dissimule les noms de fonctions |
| Appel dynamique | variables comme nom de fonction, `call_user_func`, `array_map` avec chaîne de caractères | l'appel n'apparaît nulle part en clair |
| Accès au système | `system`, `exec`, `shell_exec`, `passthru`, `proc_open`, `popen` | commandes sur le serveur |

Selon le manuel PHP, `assert()` n'évalue plus de chaînes de caractères comme code depuis PHP 8.0, et `create_function()` a été supprimée dans PHP 8.0. Sur les serveurs avec d'anciennes versions de PHP, les deux restent des termes de recherche pertinents.

Un composant isolé est rarement suspect, `base64_decode` étant par exemple utilisé légitimement par de nombreuses applications. C'est la combinaison qui devient suspecte : un décodage dont le résultat alimente directement une exécution.

## Chercher sans danger : des commandes grep inoffensives

Les commandes suivantes parcourent les fichiers uniquement comme texte. Elles n'exécutent aucun code PHP. Adaptez le chemin.

```bash
# Exécution combinée avec décodage ou décompression
grep -rlE "(eval|assert)\s*\(\s*(base64_decode|gzinflate|gzuncompress|str_rot13|hex2bin)" /var/www --include="*.php*"

# Lignes très longues (souvent du code compacté)
grep -rlE ".{2000,}" /var/www --include="*.php*"

# Nombreux échappements hexadécimaux ou chaînes de chr() sur une ligne
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*"

# Appel de fonction via une variable directement après une affectation de chaînes de caractères
grep -rnE "\\\$[a-zA-Z_]+\s*=\s*['\"][a-z_]{4,}['\"]\s*;\s*\\\$[a-zA-Z_]+\s*\(" /var/www --include="*.php*" | head -50
```

Vérifiez d'abord les occurrences avec `ls -l` et l'horodatage, puis ouvrez-les uniquement comme texte, par exemple avec `less`. N'appelez jamais des fichiers suspects via le navigateur, car le serveur les exécuterait.

## Où se trouve typiquement le code obfusqué

Le code obfusqué se trouve rarement dans un fichier propre et voyant. Plus souvent, il est inséré dans des fichiers existants, tout au début ou tout à la fin, souvent après de nombreuses lignes vides, afin de ne pas sauter aux yeux à l'ouverture. Sont prisés les fichiers chargés à chaque appel : l'`index.php` central, les fichiers de configuration et les fichiers de fonctions d'un thème.

Une voie particulièrement discrète passe par la configuration. Avec le réglage `auto_prepend_file`, PHP charge un fichier supplémentaire avant chaque script. S'il figure dans un `.user.ini` ou `.htaccess` créé par un attaquant, son code s'exécute à chaque affichage de page sans qu'un seul fichier de l'application ait été modifié. Le fichier inclus porte volontiers une extension anodine comme `.ico` ou `.png`.

```bash
# Du code supplémentaire est-il chargé avant ou après chaque script ?
grep -rnE "auto_(prepend|append)_file" /var/www --include=".user.ini" --include=".htaccess" --include="*.conf" 2>/dev/null

# Code PHP dans des fichiers à extension d'image ou d'icône
grep -rlE "<\?php" /var/www --include="*.ico" --include="*.png" --include="*.jpg" --include="*.gif" 2>/dev/null
```

## Distinguer l'obfuscation légitime du code malveillant

Tout code illisible n'est pas malveillant. Trois cas sont fréquents :

1. **Encodeurs commerciaux :** certains éditeurs d'extensions et de logiciels protègent leur code avec des outils comme ionCube ou SourceGuardian. Les fichiers sont illisibles, mais renvoient typiquement au chargeur (loader) nécessaire. Comparez-les avec le paquet d'origine.
2. **Code minifié ou généré :** les caches et les moteurs de modèles produisent de longues lignes sans retours à la ligne, mais sans exécution de texte décodé.
3. **Données intégrées :** des images ou des polices sous forme de chaîne Base64 dans un fichier PHP sont inhabituelles, mais inoffensives tant que le résultat n'est pas exécuté.

Le test le plus fiable est la comparaison avec la source : si le fichier provient inchangé du paquet de l'éditeur, il est légitime. S'il ne figure dans aucun paquet d'origine ou s'en écarte, il doit être examiné.

> **Important:**
> N'essayez pas de déchiffrer du code obfusqué sur le serveur de production, par exemple en remplaçant `eval` par une sortie et en appelant le fichier. Une seule erreur suffit à exécuter le code malveillant. L'analyse relève d'un environnement isolé.

## Limites de la recherche par motifs

Les attaquants connaissent les commandes de recherche courantes. Ils scindent les noms de fonctions, les assemblent à l'exécution ou externalisent le code proprement dit dans la base de données, dans des fichiers image ou dans des entrées de configuration. Une recherche par motifs trouve donc beaucoup, mais pas tout. Pourquoi les scanners eux aussi atteignent ici leurs limites, [Scanners de logiciels malveillants pour sites web : ce qu'ils trouvent et ce qu'ils ne trouvent pas](https://phpsos.de/fr/blog/grenzen-von-malware-scannern/) l'explique.

Une découverte est en outre rarement la seule. Les attaquants utilisent souvent le même composant dans plusieurs fichiers, par exemple un nom de variable remarquable ou une séquence de caractères marquante au début du bloc encodé. Après une découverte confirmée, cherchez donc précisément cette séquence dans tout le répertoire web, y compris dans d'autres sites du même serveur. Vous trouvez ainsi des fichiers frères qu'aucune des recherches générales par motifs n'a saisis.

Complétez la recherche par la comparaison avec les fichiers d'origine et par un coup d'œil dans la base de données, voir [Vérifier la présence de code injecté dans la base de données](https://phpsos.de/fr/blog/datenbank-auf-schadcode-pruefen/). À titre préventif, on peut bloquer les fonctions système inutiles, comme décrit dans le guide [Bien utiliser disable_functions](https://phpsos.de/fr/ratgeber/disable-functions/).

## Comment PHP SOS aide-t-il concrètement ?

- **Chercher :** nous parcourons fichiers et base de données avec des motifs étendus et comparons avec les paquets d'origine.
- **Analyser :** nous examinons le code suspect dans un environnement isolé, sans mettre votre système en danger.
- **Nettoyer :** avec la [suppression de logiciels malveillants](https://phpsos.de/fr/leistungen/malware-entfernung/), nous retirons tous les composants et fermons la voie d'entrée.
- **Sécuriser :** nous limitons les fonctions PHP et les droits d'écriture et surveillons les fichiers nouveaux ou modifiés.


## Questions fréquentes

**eval avec base64_decode est-il toujours du code malveillant ?**  
Pas toujours, mais très souvent. Un code légitime a rarement besoin de cette combinaison. Dans des fichiers qui n'appartiennent ni à votre application ni à une extension connue, c'est un signal d'alerte fort.

**Puis-je décoder du code obfusqué pour le lire ?**  
Seulement sans l'exécuter et pas sur le serveur de production. Même une exécution par inadvertance peut causer des dégâts. En cas de doute, laissez l'analyse à des spécialistes qui travaillent avec des environnements isolés.

**Pourquoi mon scanner de logiciels malveillants ne trouve-t-il pas le code ?**  
Les scanners cherchent des motifs connus. Les attaquants modifient sans cesse leur code, scindent les noms de fonctions ou les assemblent à l'exécution. Un scan vide n'est donc pas la preuve d'un serveur sain.

**Qu'en est-il des extensions chiffrées commercialement ?**  
Certains éditeurs protègent leur code avec des encodeurs comme ionCube ou SourceGuardian. De tels fichiers sont illisibles, mais légitimes s'ils proviennent de l'éditeur. Comparez-les avec le paquet d'origine.

**disable_functions aide-t-il contre le code obfusqué ?**  
En partie. Des fonctions comme exec ou system peuvent être bloquées, eval en revanche non, car c'est une construction du langage et non une fonction. Le blocage complique la prochaine étape des attaquants, mais n'empêche pas tout code malveillant.

## Sources

- [Manuel PHP : assert()](https://www.php.net/manual/de/function.assert.php)
- [Manuel PHP : create_function()](https://www.php.net/manual/de/function.create-function.php)
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
