
lighttpd 1.4.85 - Élevé - À distance - Chemin - Win32 natif GET /..%20/ lit en dehors de la racine du document
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · lighttpd-win32-dotdot-space
Write-up : https://abraxaslabs.tech/research/lighttpd-win32-dotdot-space
Classe : Lecture de fichier Portée : Distante
lighttpd 1.4.85 (4852959) - lighttpd
Le staticfile natif _WIN32 concatène document-root à rel_path après buffer_path_simplify. La simplification ne replie ../ que lorsque le troisième octet est /. http_response_prepare_physical ne supprime les espaces et points de fin que sur le chemin entier. GET /..%20/windows/win.ini reste donc /.. /windows/win.ini. _wstati64 / _wopen sans préfixe \\?\ laissent alors Win32 supprimer l'espace par composant et traiter ce segment comme ...
Un GET/HEAD non authentifié sur un lighttpd natif Windows lit un fichier régulier hors de document-root que le compte worker peut ouvrir. Unix/Linux n'est pas concerné par ce reliquat. Lecture de fichier, pas RCE.
Le lab est un gadget de ces fonctions d'épinglage. Ce n'est pas un worker natif Win32 réel. La dernière ligne utilise how=gadget.
| ID | pas encore de CVE |
| Classe | Lecture de fichier (path traversal, ..%20/ natif Win32) |
| Portée | Distante (GET/HEAD non authentifié) |
| CWE | CWE-22 |
| CVSS | Élevé : 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N |
| Produit | lighttpd1.4 |
| Affecté | 1.4.85 (4852959e67ef51ea68084984400d3264b854c97d) natif _WIN32 |
| Auth | aucune. mod_staticfile par défaut |
| Licence | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 uniquement, how=gadget |
Nécessite un lighttpd natif Windows servant des fichiers statiques. Le compte worker doit pouvoir ouvrir le fichier régulier cible.
| Privilège | Méthode / sink | Prouvé en lab ou déduit |
|---|---|---|
Lire un fichier hors de document-root | GET /..%20/<name> non authentifié | Prouvé en lab (gadget). Le corps HTTP 200 est le secret du parent |
Même classe pour un autre espace/point ASCII de fin sur un composant .. non final | décodage url puis simplification conserve .. | Prouvé en lab pour %20. Déduit pour un autre espace/point de fin |
| HEAD sur le même chemin | staticfile HEAD | Déduit. Le lab a utilisé GET |
Négatif : vrai /../ | buffer_path_simplify replie ../ | Prouvé en lab. 404, /windows/win.ini simplifié, aucun témoin |
| Négatif : ouverture POSIX Unix de la chaîne physique non simplifiée | open("/srv/htdocs/.. /windows/win.ini") | Prouvé en lab. ENOENT |
Écarté sur ce reliquat : staticfile Unix/Linux ; Cygwin (même suppression, ouverture POSIX) ; %5C parseopt de 1.4.85 ; alias CVE-2018-19052 ; Host CVE-2014-2324. Pas de RCE. Pas d'écriture.
J'ai épinglé le tag lighttpd-1.4.85. Vingt chasses. Staticfile Unix/Linux par défaut, FastCGI, proxy, TLS, auth, HTTP/2, alias/rewrite : rien à ce niveau. La vague de parseurs 1.4.81-1.4.85 avait déjà fermé les trailers, les conflits d'en-têtes CGI et les Content-Length de backend invalides.
buffer_path_simplify ne replie ../ que lorsque walk[2] == '/'. La suppression WIN32 dans http_response_prepare_physical (src/response.c 334-360) est la queue du chemin entier. _wstati64 / _wopen (src/fs_win32.c 24-77) passent de l'UTF-16 sans \\?\, donc Win32 supprime les espaces de fin par composant et .. devient ... La concaténation physique est doc_root + rel_path sans vérification de basedir après stat.
Les mauvais virages déjà consignés : traiter ENOENT d'Unix comme « pas un bug » (c'est le contrôle négatif) ; qualifier Cygwin de Win32 natif ; affirmer que %5C de 1.4.85 est ce résidu ; gonfler la lecture de fichier en RCE. Théâtre : un reverse shell. L'oracle est un corps 200 provenant du parent de la racine du document.
python3 lighttpd-win32-dotdot-space-Abraxas-Labs.py
ou
cd lab
./run.sh
Le lab est une reproduction fidèle de buffer_urldecode_path, buffer_path_simplify (mappage Win32 '\\'), de la suppression de fin dans response.c et de _wstati64 sans \\?\. L'ouverture POSIX Unix sert de contrôle négatif. La résolution Win32 est implémentée comme la même suppression des espaces de fin par composant, puis . / .., puis une ouverture POSIX du chemin résolu. HTTP en boucle locale 127.0.0.1:19400.
/index.html -> 200 public-index, aucun témoin./../windows/win.ini -> 404, simplifié en /windows/win.ini./..%20/windows/win.ini -> décodé en /.. /windows/win.ini, la simplification a conservé l'espace, ENOENT sous Unix, résolu en /srv/windows/win.ini sous Win32, 200 témoin.SUCCESS lighttpd-win32-dotdot-space how=gadget win32-get=200 unix-open=enoent simplify-kept-dotdot-space=yes LIGHTTPD-WIN32-DOTDOT-SPACE-WITNESS
Supprimer les espaces et points de fin par composant de chemin avant la simplification, ou préfixer les ouvertures Win32 avec \\?\ et rejeter tout chemin physique qui ne reste pas sous document-root.
4852959e67ef51ea68084984400d3264b854c97d)src/buffer.c · src/response.c · src/fs_win32.c%5C parseopt · CVE-2018-19052 alias · CVE-2014-2324 HostGNU Affero GPL v3.0. Voir LICENSE. Laboratoire en boucle locale uniquement. Aucune garantie.