
lighttpd 1.4.85 - High - Remote - Path - native Win32 GET /..%20/ reads outside document-root
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · lighttpd-win32-dotdot-space
Class: File read Reach: Remote
lighttpd 1.4.85 (4852959) - lighttpd
Native _WIN32 staticfile joins document-root to rel_path after buffer_path_simplify. Simplify only folds ../ when the third byte is /. http_response_prepare_physical strips trailing spaces and dots from the whole path only. GET /..%20/windows/win.ini therefore stays /.. /windows/win.ini. _wstati64 / _wopen without a \\?\ prefix then let Win32 strip the space per component and treat that segment as ...
Unauthenticated GET/HEAD on native Windows lighttpd reads a regular file outside document-root that the worker account can open. Unix/Linux is not this leftover. File read, not RCE.
The lab is a gadget of those pin functions. It is not a live native Win32 worker. Last line uses how=gadget.
| ID | no CVE yet |
| Class | File read (path traversal, native Win32 ..%20/) |
| Reach | Remote (unauthenticated GET/HEAD) |
| CWE | CWE-22 |
| CVSS | High: 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N |
| Product | lighttpd1.4 |
| Affected | 1.4.85 (4852959e67ef51ea68084984400d3264b854c97d) native _WIN32 |
| Auth | none. Default mod_staticfile |
| License | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 only, how=gadget |
Needs native Windows lighttpd serving static files. Worker account must be able to open the target regular file.
| Privilege | Method / sink | Lab-proven or inferred |
|---|---|---|
Read a file outside document-root | Unauth GET /..%20/<name> | Lab-proven (gadget). HTTP 200 body is the parent secret |
Same class for other trailing ASCII space/dot on a non-final .. component | url-decode then simplify keeps .. | Lab-proven for %20. Inferred for other trailing space/dot |
| HEAD the same path | staticfile HEAD | Inferred. Lab used GET |
Negative: real /../ | buffer_path_simplify folds ../ | Lab-proven. 404, simplified /windows/win.ini, no witness |
| Negative: Unix POSIX open of the unsimplified physical string | open("/srv/htdocs/.. /windows/win.ini") | Lab-proven. ENOENT |
Closed on this leftover: Unix/Linux staticfile; Cygwin (same strip, POSIX open); 1.4.85 %5C parseopt; CVE-2018-19052 alias; CVE-2014-2324 Host. Not RCE. Not a write.
I pinned tag lighttpd-1.4.85. Twenty hunts. Default Unix/Linux staticfile, FastCGI, proxy, TLS, auth, HTTP/2, alias/rewrite: none at this bar. The 1.4.81-1.4.85 parser wave already closed trailers, CGI header conflicts, and invalid backend Content-Length.
buffer_path_simplify only folds ../ when walk[2] == '/'. WIN32 strip in http_response_prepare_physical (src/response.c 334-360) is the whole-path tail. _wstati64 / _wopen (src/fs_win32.c 24-77) pass UTF-16 without \\?\, so Win32 strips trailing spaces per component and .. becomes ... Physical join is doc_root + rel_path with no post-stat basedir check.
Wrong turns already recorded: treating Unix ENOENT as "not a bug" (it is the negative control); calling Cygwin native Win32; claiming 1.4.85 %5C is this leftover; inflating file read to RCE. Theatre: a reverse shell. The oracle is a 200 body from the parent of document-root.
python3 lighttpd-win32-dotdot-space-Abraxas-Labs.py
or
cd lab
./run.sh
The lab is a faithful gadget of buffer_urldecode_path, buffer_path_simplify (Win32 '\\' map), the response.c tail strip, and _wstati64 without \\?\. Unix POSIX open is the negative control. Win32 resolve is implemented as the same per-component trailing-space strip, then . / .., then a POSIX open of the resolved path. Loopback HTTP 127.0.0.1:19400.
/index.html -> 200 public-index, no witness./../windows/win.ini -> 404, simplified /windows/win.ini./..%20/windows/win.ini -> decoded /.. /windows/win.ini, simplify kept the space, Unix ENOENT, Win32 resolved /srv/windows/win.ini, 200 witness.SUCCESS lighttpd-win32-dotdot-space how=gadget win32-get=200 unix-open=enoent simplify-kept-dotdot-space=yes LIGHTTPD-WIN32-DOTDOT-SPACE-WITNESS
Strip trailing spaces and dots per path component before simplify, or prefix Win32 opens with \\?\ and reject a physical path that does not stay under 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. See LICENSE. Loopback lab only. No warranty.