Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
freebsd-dirent-info-leak-bugs — CVE-2020-25578 和 CVE-2020-25579:我在2020年发现的一些FreeBSD信息泄露漏洞。 | Kitploit
工具/GitHubGitHub/farazsth98/freebsd-dirent-info-leak-bugs
内存取证漏洞分析漏洞利用信息收集二进制分析
GitHubfarazsth98/freebsd-dirent-info-leak-bugs

freebsd-dirent-info-leak-bugs

CVE-2020-25578 和 CVE-2020-25579:我在2020年发现的一些FreeBSD信息泄露漏洞。

查看仓库

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
7225年前尚未审核

我是如何发现这些漏洞的?

  1. 随机决定审计 FreeBSD 中的文件系统
  2. 做一些研究,发现默认使用的文件系统是 FFS 和 UFS 的组合
  3. 花一些时间审计 ufs_create,发现 0 个漏洞
  4. 前往此处查看 UFS 文件系统函数的提交历史
  5. 发现这个关于通过栈上分配的 struct dirent 对象中的填充字节泄露信息的提交
  6. 分析该补丁,发现对 msdosfs_readdir 的补丁不完整。他们修补了一个实例,但没有修补第二个。
  7. 编写 PoC 确认我可以泄露 3 个填充字节。然后开始寻找变种。
  8. 在 mqueuefs、autofs、smbfs 和 tmpfs 中找到变种,这些变种允许我泄露完整的 8 字节指针。编写 PoC 确认。

原始漏洞

如上所述,我最初发现的漏洞是在分析上述提交的补丁时,在 msdosfs_readdir 中发现的。

在 FreeBSD 上调用 readdir 的基本流程如下:

root@kitploit:~
#include <dirent.h>

int main(void) {
    struct dirent *dp;
    DIR *dirp;

    dirp = opendir("./somedir");
    dp = readdir(dirp);
}

根据 somedir 所在的具体文件系统,FreeBSD 内核中可能会调用许多 *_readdir 函数中的某一个。

上面的补丁添加了一个名为 dirent_terminate 的函数,旨在将 struct dirent 对象返回给用户空间(通常使用 uiomove 函数)之前调用它。该函数将清空结构体中 d_name 字段的填充字节以及剩余字节。此处是 struct dirent 的定义。

查看补丁,在第 1562 行,可以看到 dirent_terminate 被调用,参数为 dirbuf 变量。随后,uiomove 被调用来将 dirbuf 的内容复制回用户空间。然而,请注意这些代码行位于这个 if 语句的块内。此 if 语句上方的注释说明,只有在 MSDOS 文件系统的根目录上调用 readdir 时才会走这个分支,因此我们只需在文件系统的根目录之外的任何子目录中调用 readdir,即可跳过这个 if 语句。

继续往下看,我们在第 1691 行看到另一个对 uiomove 的调用。然而,仔细阅读代码会发现,在这种情况下并没有调用 dirent_terminate,这意味着填充字节将保持未初始化状态。不幸的是,d_name 字段在该函数开头已被清空(此处),所以我们无法获得更大的泄露。

PoC

首先,我没有 USB 驱动器,所以不得不想办法挂载一个 MSDOS 文件系统。以下操作可行:

root@kitploit:~
$ dd if=/dev/zero of=test.img bs=512 count=256000
$ sudo mdconfig -a -t vnode -f test.img
$ sudo newfs_msdos -s 131072000 /dev/md1 # 我的 mdconfig 返回了 md1
$ mkdir ./temp
$ sudo mount -t msdosfs /dev/md1 ./temp
$ mkdir ./temp/test_dir

PoC 可以在 original_poc.c 中找到。只需用 clang 编译,并在与上述命令相同的目录中运行,你将看到打印出的泄露字节。

变种

我开始寻找这个漏洞的变种。我大致是用 uiomove\(&.*, 进行 grep,返回了大约 15-20 个结果,然后我手动检查了所有结果。不幸的是,这些变种在 FreeBSD 中默认都不存在(这些文件系统需要手动启用/编译到内核中)。存在变种的函数如下:

  1. mqfs_readdir
  2. tmpfs_dir_getdotdent
  3. tmpfs_dir_getdotdotdent
  4. smbfs_readvdir
  5. autofs_readdir_one

所有这些函数中的漏洞完全相同,因此我只介绍 mqfs_readdir。

  1. 首先,在栈上分配了一个 struct dirent entry
  2. 接着,调用 dirent_terminate 清空结构体的填充字节和 d_name 字段
  3. 最后,调用 vfs_read_dirent。该函数会调用 uiomove 将结构体复制到用户空间

到目前为止一切看起来都正常,对吧?不一定。我们必须确保结构体的所有字段都已初始化。如果仔细看代码,你会发现 d_off 字段保持未初始化。该字段的类型是 off_t,本质上是一个 int64_t。当结构体被复制到用户空间时,我们会得到未初始化的数据。

PoC

同样的 PoC 适用于所有变种,你只需在不同的文件系统上运行它。对于 mqueuefs,执行以下操作(需要先启用/将 mqueuefs 编译到内核中):

root@kitploit:~
$ mkdir ./temp
$ sudo mount -t mqueuefs null ./temp

PoC 本身可以在 variants_poc.c 中找到。只需用 clang 编译,并在与上述命令相同的目录中运行。你将看到打印出的内核指针(大概一个栈指针和一个代码段/堆指针,我没有确认)。

下载工具