abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · lighttpd-win32-dotdot-space
类别: 文件读取 可达性: 远程
lighttpd 1.4.85 (4852959) - lighttpd
原生 _WIN32 staticfile 在 buffer_path_simplify 之后将 document-root 与 rel_path 拼接。Simplify 仅在第三个字节为 / 时折叠 ../。http_response_prepare_physical 仅从整个路径中去除末尾空格和点。因此 GET /..%20/windows/win.ini 保持为 /.. /windows/win.ini。随后不带 \\?\ 前缀的 _wstati64 / _wopen 让 Win32 按组件去除空格,并将该段视为 ..。
在原生 Windows lighttpd 上未经认证的 GET/HEAD 可读取 document-root 之外、worker 账户能够打开的常规文件。 Unix/Linux 不存在此遗留问题。属于文件读取,而非 RCE。
该实验环境是这些 pin 函数的 gadget。它不是真实的原生 Win32 worker。最后一行使用 how=gadget。
| ID | 暂无 CVE |
| 类别 | 文件读取(路径遍历,原生 Win32 ..%20/) |
| 可达性 | 远程(未经认证的 GET/HEAD) |
| CWE | CWE-22 |
| CVSS | 高危:7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N |
| 产品 | lighttpd1.4 |
| 受影响版本 | 1.4.85 (4852959e67ef51ea68084984400d3264b854c97d) 原生 _WIN32 |
| 认证 | 无。默认 mod_staticfile |
| 许可证 | GNU Affero GPL v3.0 |
| 实验环境 | 仅 127.0.0.1,how=gadget |
需要原生 Windows lighttpd 提供静态文件服务。Worker 账户必须能够打开目标常规文件。
| 权限 | 方法 / sink | 实验验证或推断 |
|---|---|---|
读取 document-root 之外的文件 | 未经认证的 GET /..%20/<name> | 实验验证(gadget)。HTTP 200 响应体为父目录中的机密文件 |
对非末尾 .. 组件上的其他末尾 ASCII 空格/点采用同类方法 | url 解码后 simplify 保留 .. | %20 已实验验证。其他末尾空格/点属推断 |
| 对同一路径发起 HEAD | staticfile HEAD | 推断。实验使用 GET |
反例:真实的 /../ | buffer_path_simplify 折叠 ../ | 实验验证。404,简化后为 /windows/win.ini,无 witness |
| 反例:对未简化的物理字符串进行 Unix POSIX open | open("/srv/htdocs/.. /windows/win.ini") | 实验验证。ENOENT |
此遗留问题已排除:Unix/Linux staticfile;Cygwin(相同的 strip,POSIX open);1.4.85 %5C parseopt;CVE-2018-19052 alias;CVE-2014-2324 Host。不是 RCE。不是写入。
我固定了标签 lighttpd-1.4.85。进行了二十次搜寻。默认 Unix/Linux staticfile、FastCGI、proxy、TLS、auth、HTTP/2、alias/rewrite:在此标准下均无发现。1.4.81-1.4.85 解析器浪潮已经修复了 trailers、CGI 头冲突和无效的后端 Content-Length。
buffer_path_simplify 仅在 walk[2] == '/' 时折叠 ../。http_response_prepare_physical(src/response.c 334-360)中的 WIN32 strip 作用于整个路径的尾部。_wstati64 / _wopen(src/fs_win32.c 24-77)传递 UTF-16 时不带 \\?\,因此 Win32 按组件去除末尾空格,.. 变为 ..。物理拼接为 doc_root + rel_path,没有基于 stat 之后的 basedir 检查。
已记录的弯路:将 Unix ENOENT 视为“不是漏洞”(它是对照组);将 Cygwin 称为原生 Win32;声称 1.4.85 %5C 就是此遗留问题;将文件读取夸大为 RCE。作秀:反弹 shell。判定依据是来自 document-root 父目录的 200 响应体。
python3 lighttpd-win32-dotdot-space-Abraxas-Labs.py
或
cd lab
./run.sh
该实验环境忠实复现了 buffer_urldecode_path、buffer_path_simplify(Win32 '\\' 映射)、response.c 尾部 strip,以及不带 \\?\ 的 _wstati64 的 gadget。Unix POSIX open 是对照组。Win32 解析实现为相同的按组件末尾空格 strip,然后处理 . / ..,最后对解析后的路径执行 POSIX open。回环 HTTP 127.0.0.1:19400。
/index.html -> 200 public-index,无 witness。/../windows/win.ini -> 404,简化后为 /windows/win.ini。/..%20/windows/win.ini -> 解码为 /.. /windows/win.ini,simplify 保留了空格,Unix ENOENT,Win32 解析为 /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
在 simplify 之前按路径组件去除末尾空格和点,或者为 Win32 打开操作添加 \\?\ 前缀,并拒绝任何未保持在 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。参见 LICENSE。仅限回环实验环境。无担保。