vsftpd 3.0.5 - 高危 - 远程 - 权限残留 - 大括号 deny_file 遗漏 .private/secret
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · vsftpd-deny-file-brace-child
类别: 权限残留 可达性: 远程
vsftpd 3.0.5 - Chris Evans
手册页(vsftpd.conf.5)中的示例是 deny_file={*.mp3,*.mov,.private}。匹配的名称“不应以任何方式被访问”,包括“下载、进入目录、影响目录内的内容”。vsf_access_check_file(access.c:16-43)对客户端提供的路径调用 vsf_filename_passes_filter,然后对整个花括号可调项执行 str_locate_str。过滤器匹配最后一段 / 前缀;残留的 /secret 不匹配;{*.mp3,*.mov,.private} 的子串查找未命中。
CWD .private 被拒绝(basename 命中)。RETR .private/secret 和 RETR dir/.private 成功。这个残留所破坏的正是“目录内”这一点。
CVE-2015-1419 是发行版公开的 realpath/basename 补丁。官方 3.0.5 从未采纳它。Debian 的花括号分支仍然匹配完整路径,因此这个子路径遍历在已打补丁的发行版包上依然存在。请勿重复提交 2015-1419。
这个残留是一个受配置门控的拒绝列表遗漏。它不是未认证 RCE,不是 chroot 逃逸,也不是读取主机 /etc。
| ID | 暂无 CVE |
| 类别 | 权限残留 |
| 可达性 | 远程(已认证 FTP) |
| CWE | CWE-863, CWE-22 |
| CVSS | 高危:7.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N |
| 产品 | vsftpd(Chris Evans) |
| 受影响 | vsftpd 3.0.5 官方 tarball SHA-256 26b602ae454b0ba6d99ef44a09b6b9e0dfa7f67228106736df1f278c70bc91d3 |
| 认证 | 已认证 FTP USER/PASS(实验环境中为匿名)。deny_file 设置为花括号列表(默认未设置) |
| 许可证 | GNU Affero GPL v3.0 |
| 实验环境 | 仅 127.0.0.1。匿名只读。见证文件。 |
谁:已认证的 FTP 用户(实验环境中为匿名 ftp)。会话 UID 在 vsftpd 常规降权之后。deny_file 本应是额外策略,用来从该 UID 手中收回权限。手册页提到的虚拟用户方案共享 guest_username,因此 Unix DAC 无法区分它们。tunable_deny_file 为 NULL 的原版 3.0.5 不属于此残留。
| 方法 + 汇聚点 | 权限 |
|---|---|
RETR .private/secret,配合文档中的花括号 deny_file={*.mp3,*.mov,.private} | handle_retr 以会话 uid 对目录名在拒绝列表上的文件执行 str_open。实验:150/226,37 字节,正文 VSFTPD-DENY-FILE-BRACE-CHILD-WITNESS |
RETR dir/.private | 同一汇聚点。另一个目录下名为 .private 的文件(must_match_at_current_pos 拒绝索引 > 0 的匹配)。实验:150/226,正文 DIRDOT-VSFTPD-DENY-FILE-BRACE-CHILD-WITNESS |
vsf_access_check_file 门控推断;实验为只读)| 方法 + 汇聚点 | 权限 |
|---|---|
当 write_enable=YES 时对同一路径执行 STOR / APPE | handle_upload_common 以会话 uid 创建 / 覆盖 |
对同一路径执行 DELE / RNTO | str_unlink / 重命名一个拒绝列表本应阻止的名称 |
| 方法 + 汇聚点 | 权限 |
|---|---|
LIST .private/x(或在被拒绝的树内执行 LIST) | handle_dir_common 对完整参数做访问检查(未命中),然后在斜杠分割后对 .private 前缀执行 str_opendir。仅名称。Unix DAC 仍然适用 |
| 方法 + 汇聚点 | 结果 |
|---|---|
CWD .private | 550 Permission denied。basename .private 命中花括号 |
RETR song.mp3 | 550。*.mp3 是最后一段模式,确实匹配 |
CWD .private 本身(basename 命中)hide_file 对目录项的 LIST 隐藏(basename 来自 readdir;对隐藏名称的 RETR 是文档中说明的预期行为)/etchttp_enable 默认关闭;FTP 模式 GET 会终止会话)deny_file=.private 由子串回退所挽救(在 .private/secret 中 str_locate_str 查找 .private)我锁定的是官方 vsftpd 3.0.5(SHA-256 26b602ae...c91d3),而不是 GitHub 镜像或 Debian/Fedora 源码树。进行了十九次源码搜寻。默认编译的守护进程没有未公开的严重/高危残留。这一个需要操作者复制手册页中的花括号示例。
vsf_filename_passes_filter(ls.c)匹配 * / ? / 非嵌套的 {,},并且只对最后一段模式做有效工作。对于名称 .private/secret 与 {*.mp3,*.mov,.private} 的匹配:
*.mp3、*.mov、.private 在 .private/secret 的开头进行匹配。残留的 /secret 不匹配,除非该 token 是 *。{*.mp3,*.mov,.private},未命中。已经公开的错误方向:CVE-2015-1419 仅是发行版的 realpath。官方 Changelog 没有此类修复。即便是 Debian 的花括号分支也复制完整规范化路径,因此子路径仍然可以遍历。
cd lab
./run.sh
回环控制 127.0.0.1:18710,PASV 18711-18718。Compose 项目 vsftpd-deny-file-brace-child。官方 3.0.5 tarball,匿名只读,deny_file={*.mp3,*.mov,.private}。见证 VSFTPD-DENY-FILE-BRACE-CHILD-WITNESS。最后一行:
SUCCESS vsftpd-deny-file-brace-child cwd-dotprivate=550 retr-child=yes retr-dir-dotprivate=yes mp3=550 VSFTPD-DENY-FILE-BRACE-CHILD-WITNESS
对每个路径组件匹配花括号备选项,或在过滤器之前执行 realpath / basename(注意常见的符号链接注意事项)。文档中的示例应真正拒绝子路径。
厂商接收邮箱为 [email protected](vsftpd)。请勿在任何 vsftpd 镜像上公开提交 GitHub issue。
Abraxas Labs - abraxaslabs.tech - github.com/abraxas - @abraxas_null - [email protected]