Contexte de la vulnérabilité

Le gestionnaire php_session_rfc1867_callback du module ext/session de PHP stocke deux pointeurs bruts de type zval * dans les tables de hachage post_bytes_processed et current_file_bytes_processed. Ces pointeurs référencent des buckets qui sont libérés lors du second appel de session.upload_progress dans le même cycle de requête. La configuration par défaut (session.upload_progress.enabled=1, fréquence 1 %) suffit à déclencher le problème.

Mécanisme d'exploitation

Lors d’un premier POST multipart rapide, les deux caches sont remplis. Un second appel update() relit le fichier de session, puis zend_hash_update détruit l’arbre décodé précédent via le destructeur zval_ptr_dtor. Le bucket libéré est ensuite réutilisé par l’allocation du heap, laissant un pointeur stale qui pointe vers une structure zend_fcall_info contrôlée par l’attaquant. Cette structure contient un zend_internal_function.handler situé à l’offset +88, qui, lorsqu’il est invoqué par zend_call_function, exécute system(). Les offsets précis (ex. zend_fcall_info 64 B, param_count à +48) ont été confirmés sur les sources php‑src 8.4.4 et 8.2.34.

Analyse des impacts et limites

La chaîne d’exploitation permet d’exécuter du code arbitraire avec les privilèges du processus PHP‑FPM ou du serveur web, ce qui constitue une compromission totale du service. La vulnérabilité dépend de la réutilisation du même bucket ; si le heap n’alloue pas immédiatement un objet compatible, l’exploitation échoue, ce qui introduit une variabilité liée à la charge du serveur et aux versions de compilation. Les builds de LiteSpeed lsphp82 montrent des offsets de désynchronisation différents selon la distribution (bookworm 0xc930, noble 0xcef0, jammy 0xd060), confirmant que le delta entre zval_ptr_dtor et zend_call_function varie à chaque build.

Mesures d'atténuation

1. Inventorier les versions PHP : php -v. Les versions 7.x et antérieures ne reçoivent pas de correctif, il faut donc migrer vers 8.5.11, 8.4.26, 8.3.35 ou 8.2.34 dès leur disponibilité.
2. Appliquer un stop‑gap en modifiant php.ini, .user.ini ou .htaccess pour désactiver ou restreindre session.upload_progress ; recharger PHP‑FPM après modification.
3. Limiter les uploads multipart au périmètre réseau : un WAF ou un reverse proxy doit filtrer ou limiter le débit des POST multipart vers les points d’entrée qui n’en ont pas besoin.
4. Mettre à jour dès la sortie du correctif officiel : les versions stables mentionnées corrigent le problème de libération du bucket.