// 安全研究 · 2026-04-13

Linux 内核保护机制 fs.protected_symlinks 探究

在 Linux 系统安全中,符号链接(Symbolic Link)是一把双刃剑。它提供了路径跳转的便利,但也为符号链接劫持(Symlink Hijacking)和权限提升留下了后门。为了堵住这些漏洞,Linux 内核引入了 fs.protected_symlinks 参数。


protected_symlinks 是 Linux 内核的一项安全功能(自 3.6 版本引入),主要用于限制在特定条件下跟随符号链接的行为。其核心目的是防止低权限用户诱骗高权限进程(如 root 运行的 cron 任务或 Web 服务)去读写不该访问的文件。

如何查看与设置

  • 查看状态:cat /proc/sys/fs/protected_symlinks(1 为开启,0 为关闭)。
  • 临时修改:sysctl -w fs.protected_symlinks=0。
  • 永久修改:在 /etc/sysctl.conf 中添加 fs.protected_symlinks = 1。

2. 触发拦截的“三位一体”条件

内核不会无缘无故拦截链接。只有当以下 三个条件同时满足 时,open() 系统调用才会返回 EACCES(权限被拒绝):

  1. 全局开关开启:fs.protected_symlinks = 1。
  2. 处于危险目录:符号链接所在的父目录必须具有 粘滞位(Sticky Bit, +t) 且对 所有人可写(World-writable)。典型的例子是 /tmp 和 /var/tmp。
  3. 所有权不匹配:
    • 链接的创建者 与 尝试读取链接的进程运行者 不一致。
    • 且 链接的创建者 与 目标文件的所有者 不一致。

逻辑推论:如果你在自己的家目录(没有粘滞位)创建一个指向 root 文件的链接,该机制不会触发。内核认为私有目录是安全的,只有公共“垃圾场”才需要特别巡逻。


3. 实战案例:为什么 Web 服务器会报 404?

假设你在做一个 CTF 题目或渗透测试,场景如下:

  • 环境:Python http.server 以用户 hyh 身份在 /var/tmp 运行。
  • 目标:读取 /srv/ftp/pub/pass.txt(属主也是 hyh,其他人不可读)。
  • 尝试:你作为 www-data,在 /var/tmp 创建了一个文件链接 ln -s /srv/ftp/pub/pass.txt my_link。

结果分析

当你请求 http://localhost:8080/my_link 时:

  1. 内核拦截:因为满足了上述三个条件(/var/tmp 有粘滞位、你是 www-data、进程是 hyh),内核拒绝 open() 操作。
  2. 代码伪装:在 Python 的 server.py 源码中,所有 OSError(包括权限拒绝)都会被 try...except 捕获并重定向为 404 Not Found。

    这是一种安全策略:不告诉你“没权限”,而是告诉你“没这个文件”,防止泄露敏感路径的存在。


4. 绕过技巧:目录链接的“逻辑间隙”

这是 protected_symlinks 最有趣的地方:它对文件链接和目录链接的解析逻辑存在差异。

  • 文件链接(直接打开):你直接访问链接,内核会检查“谁建立了这个链接”,检查失败,拦截。
  • 目录链接(路径平移):如果你建立一个指向父目录的链接 ln -s /srv/ftp/pub pwn_dir,然后访问 /pwn_dir/pass.txt:
    1. 内核在解析路径组件时,将 pwn_dir 视为一个位置跳板。
    2. 一旦跳转完成,后续的操作变成了“在 /srv/ftp/pub 目录下打开 pass.txt”。
    3. 此时,由于进程所有者(hyh)和文件所有者(hyh)一致,内核认为这是合法的内部访问,不再触发针对链接所有者的校验。

总结

fs.protected_symlinks 是 Linux 为了修补共享目录漏洞而设计的“补丁”。它虽然能有效防止简单的符号链接劫持,但在面对目录级链接跳转和进程 UID 权限重合时,仍可能被巧妙绕过。理解它的底层触发逻辑,是进行安全加固或漏洞利用的基础。

原文 https://blog.csdn.net/2301_79518550/article/details/159887444