谷歌开源文件访问漏洞审计工具 PathAuditor(详解)
审计由二进制执行的和文件系统相关的 libc 函数的每个调用。 检查该系统调用中使用的路径是否为用户可写入。如是,则可导致非权限用户通过符号链接替换目录或文件。 将所有的违规情况记录为潜在的漏洞问题。
该工具通过使用LD-PRELOAD 来 hook 所有和文件系统相关的系统调用并将任何遇到的违反情况记录到系统日志中。
检测示例
if (S_ISDIR (sb.st_mode)) {
char *dst;
if ((dst = malloc(strlen(ent->d_name) + 3)) == NULL)
message (LOG_FATAL, "malloc failed.\n");
strcpy(dst, ent->d_name);
strcat(dst, "/X");
rename(ent->d_name, dst);
if (errno == EXDEV) {
free(dst);
message (LOG_VERBOSE,
"File on different device skipped: `%s/%s'\n",
dirname, ent->d_name);
continue;
}
// [...]
简言之,该代码调用 rename("/tmp/foo", "/tmp/foo/x"),如果“/tmp/foo”为挂载点,则返回 EXEDV。如果“/tmp/foo”由除 root以外的任意用户所有,则 PathAuditor 将把该调用标记为一个潜在的漏洞。要理解其中的原因,我们必须思考一下当执行该重命名系统调用时内核中会发生什么(简化版):
1、内核为第一个参数遍历路径“/tmp/foo”。
2、内核为第二个参数遍历路径“/tmp/foo/x”。
3、如果源和目标位于不同的文件系统,则返回 EXDEV。
4、否则,将文件从第一个目录移至第二个目录。
由于“/tmp/foo”将被解析两次,因此存在竞争条件。如果它受用户控制,那么用户能够在任何时间点用其它文件进行替换。具体来讲,我们首先希望“/tmp/foo”成为通过tmpreaper 代码中通过 if(S_ISDIR) 检查的一个目录。之后我们在该代码进入syscall 之前将其替换为一个文件。当内核解析第一个参数时,它将会看到含有受用户控制内容的一个文件。现在我们将其再次替换,不过这次在相同的文件系统上包含对任意目录的一个符号链接。该内核将再次解析路径,跟随符号链接并将受控制文件迁移至所选目录中。
文件系统限制相同是因为在文件系统之间无法进行重命名。但在某些 Linux 发行版本中, /tmp 只是默认的 rootfs 上的一个文件夹,你可以使用此 bug 将文件迁移至 /etc/cron 中,进而以 root 身份执行。
如何运行
首先需要通过bazel 构建ibpath_auditor.so,之后使用 LD_PRELOAD 将其加载到二进制中。任何违反行为将被记录到 syslog 中,因此确保运行它:
bazel build //pathauditor/libc:libpath_auditor.so
LD_PRELOAD=/path/to/bazel-bin/pathauditor/libc/libpath_auditor.so cat /tmp/foo/bar
tail /var/log/syslog
也可以将其添加至 /etc/ld.so.preload 中,在系统上的所有进程中运行。不过需要注意的是只推荐在测试系统上使用,因为它可能导致稳定性问题。
可以尝试配置该项目的 docker 容器快速入门:
docker build -t pathauditor-example .
docker run -it pathauditor-example
# LD_PRELOAD=/pathauditor/bazel-bin/pathauditor/libc/libpath_auditor.so cat /tmp/foo/bar
# cat /var/log/syslog
今年,谷歌还开源了硅信任根项目、加密协议 Private Join and Compute、模糊测试平台ClusterFuzz 以及 Sandboxed API。
奇安信代码卫士 (codesafe)
国内首个专注于软件开发安全的产品线。