Symptômes · 9 min · publié le 17 juillet 2024

Fichiers .php.jpg dans les uploads : pourquoi c'est grave

Un `facture.php.jpg` dans les médias n'est pas une image mal nommée. Selon la config, le serveur exécute le PHP malgré l'extension image. Interdire l'exécution dans les dossiers d'upload est le correctif le moins coûteux une fois l'incident constaté — et souvent le plus oublié.

Réponse directe

Le serveur exécute parfois le PHP malgré l'extension image. Interdire l'exécution dans les dossiers médias est le correctif le moins coûteux après incident.

php.jpg upload double extension malware upload php wordpress

Pourquoi `.php.jpg` passe encore

Apache, selon les `AddHandler` et l'ordre des extensions, peut traiter `fichier.php.jpg` comme du PHP. Certains hôtes historiques le font encore. Nginx est plus strict par défaut, pas toujours : un `location ~ \.php` trop large rattrape. Le détail est chez l'hébergeur ; le risque, chez vous, dès qu'un upload écrit un PHP.

WordPress interdit en théorie les uploads PHP. Un plugin file manager, un champ « non filtré », un bug de validation, un admin fantôme : le fichier est là. La médiathèque peut même afficher une icône image si le `guid` finit en `.jpg`.

Ce n'est pas un cas d'école. C'est le vecteur d'entrée le plus banal après le mot de passe faible : on upload une « image », on l'appelle en URL, on a un shell.

Lister autrement que par la médiathèque

La médiathèque filtre les images et pagin. Passez par SFTP sur `wp-content/uploads/` (ou `img/`, `media/` Presta). Recherche `*.php*` dans l'arbre. Les `.phtml`, `.php5`, `.phar` aussi.

Exportez la liste nom / chemin / date. Les fichiers du jour de l'incident d'abord. Un `2024/01/` plein de PHP alors que vous n'uploadez plus depuis 2023 : quelqu'un écrit encore.

Les pièces jointes WordPress (`attachment` dans `wp_posts`) : un `guid` vers un `.php.jpg`. La SQL complète la recherche disque. Voir aussi articles inconnus pour les attachments déguisés.

  • Recherche `*.php*` sous uploads.
  • `.phtml`, `.php5`, `.phar`, `.inc`.
  • `guid` en base.
  • Même passe sur les dossiers « import » et « backup ».

Noms fréquents et doubles extensions

`.php.jpg`, `.php.png`, `.php.gif`, `.php.webp`, `.jpg.php`, `.png.php`. L'ordre change selon le handler. Cherchez les deux. Un `.phtml.jpg` apparaît sur les hôtes qui exécutent phtml.

Des noms `image4.php.jpg`, `favicon.php.ico`, `doc.php.pdf`. Le PDF n'est pas exécuté comme PHP en général ; le `.php.pdf` peut l'être si le handler est naïf. En doute, sortez le fichier du webroot.

Un vrai JPG qui contient un payload dans les métadonnées n'est pas une double extension. C'est un autre dossier (inclusion de fichier). Ici, on parle du nom.

Tester sans exécuter

Ne cliquez pas l'URL du suspect depuis un navigateur de prod « pour voir le shell ». Téléchargez en SFTP, ouvrez en texte. `<?php` en tête ou après une signature JPEG : classé.

Si vous devez tester l'exécution, faites-le sur une copie isolée, pas en laissant le fichier en 200 public. Le temps du test, l'URL est une porte ouverte au monde.

Les logs d'accès : des `GET` vers ce fichier avec des query strings longs (`?cmd=`, `?e=`) confirment l'usage. Gardez l'extrait. Heure d'entrée vs premier hit.

Interdire PHP dans uploads (Apache, Nginx)

Apache : un `.htaccess` dans `uploads` qui refuse l'engine PHP (`php_flag engine off` selon le mode, ou `Require all denied` sur `\.php`). Le bon snippet dépend de PHP-FPM vs mod_php. L'hébergeur a souvent un modèle « sécuriser uploads ». Demandez-le ; un snippet de forum casse les images.

Nginx : `location` sur le path médias qui n'inclut pas FastCGI vers PHP. C'est au vhost, pas à un `.htaccess` ignoré.

Après la règle : un `<?php echo 1;` de test que vous posez et retirez, appelé en HTTP, doit afficher le source ou 403, pas `1`. Si vous voyez `1`, la règle est morte. Voir interdire PHP pour le détail durable.

Cette règle ne remplace pas le retrait des fichiers. Elle empêche la prochaine exécution. Les deux gestes.

Le handler dans `.htaccess` qui annule tout

L'attaquant pose souvent, dans le même dossier, un `.htaccess` `AddHandler php .jpg`. Votre règle « engine off » à la racine perd. Lisez tous les `.htaccess` sous uploads. Voir htaccess modifié.

Un `.user.ini` `auto_prepend` dans uploads : même étage. Lisez-le.

LiteSpeed : des règles spécifiques. Testez réellement l'URL de test PHP, ne croyez pas le fichier.

Avatars, builders, et marketplaces

BBPress, un LMS, un marketplace : chaque vendeur uploade. Le dossier n'est pas `uploads/2024` classique, c'est `uploads/ultimatemember/` ou équivalent. La même recherche `*.php*` là.

Elementor et les kits importent des JSON + des médias. Un kit « gratuit » est un vecteur. Scannez après chaque import.

Les comptes clients en masse qui posent un avatar : croisez les dates d'inscription et les fichiers.

Nettoyer les fichiers, pas seulement la règle

Copie hors serveur, retrait du webroot, 404 sur l'URL. Les attachments en base : mettez à jour ou supprimez la pièce pour ne pas servir un lien cassé dans un article. Un `guid` mort vaut mieux qu'un shell.

Un cron peut reposer le fichier. Panel + cron. Un admin avec File Manager aussi.

Si l'URL du shell était dans Safe Browsing, réexamen après 404 réelle. 24 à 72 h. Inspection : 404, pas 200 avec une image vide.

Prévention qui tient après J+7

Règle d'exécution off, File Manager désinstallé, moins d'admins, types MIME stricts. Une revue `*.php*` sous uploads à J+7. C'est trois minutes.

Les plugins « permettre tous les uploads » n'ont plus leur place. Un besoin PDF/SVG se traite à part (SVG = XSS, autre sujet).

Vous pouvez déclarer le site. Une liste des `*.php*` sous uploads est déjà un plan de travail.

  • Liste `*.php*` + copies.
  • Règle anti-exécution testée.
  • `.htaccess` locaux relus.
  • File Manager hors jeu.

Questions fréquentes

Mon hébergeur dit que PHP ne s'exécute pas dans uploads. Je dois quand même chercher ?

+
Oui. Les configs changent, un `.htaccess` local annule, et le fichier reste une preuve d'écriture. Cherchez, même si l'URL « ne devrait pas » s'exécuter.

Un `.jpg` qui commence par `<?php`, sans double extension ?

+
Si le serveur ne l'exécute pas, le risque est une inclusion (`include` du thème). Retirez-le quand même. Le contenu, pas seulement le nom, compte.

Wordfence a mis le fichier en quarantaine. La règle est-elle posée ?

+
Pas forcément. La quarantaine retire un fichier. La règle anti-exécution est un autre geste, à vous ou à l'hébergeur.

Puis-je vider tout uploads pour être sûr ?

+
Vous perdez les images de la boutique et du blog. Filtrez `*.php*` et les dates suspectes. Une purge totale est un second incident commercial.

PrestaShop `img/` c'est la même chose ?

+
Oui : cherchez du PHP, interdisez l'exécution, lisez les `.htaccess` du dossier. Le nom du dossier change, pas le principe.
À lire ensuite
Interdire PHP dans les uploads Dossier aléatoire dans uploads .htaccess modifié Plugin File Manager Déclarer mon site