跳转到帖子

Linux 漏洞库:sudo Baron Samedit(CVE-2021-3156)本地提权排查与修复

精选回复

发布于

漏洞概况

CVE-2021-3156,又称 Baron Samedit,是 sudo/sudoedit 参数解析过程中的堆缓冲区溢出漏洞。攻击者只需具备本地普通用户权限,即可能利用以 setuid root 运行的 sudo 获取 root 权限。

  • 漏洞类型:本地权限提升、堆缓冲区溢出
  • 影响组件:sudo、sudoedit
  • CWE:CWE-122
  • CVSS 3.x:7.8
  • 上游影响范围:sudo 1.8.2 至 1.8.31p2、1.9.0 至 1.9.5p1
  • 上游修复版本:sudo 1.9.5p2
  • 利用前提:攻击者已获得本地普通用户执行权限
发行版通常会将补丁回移到旧版本,因此不能只根据 sudo 的上游版本号判断是否存在漏洞,应同时核对发行版安全公告和软件包 changelog。

权限边界与风险

该漏洞不要求用户出现在 sudoers 文件中,也不要求其拥有任何 sudo 命令授权。只要系统上的 sudo 二进制保留 setuid root 权限,本地低权限账户就处于潜在攻击面内。

在授权渗透或主机失陷排查中,以下入口需要重点关注:

  • Web 服务被写入 WebShell 后获得的 www-data、apache、nginx 等账户。
  • 容器逃逸后进入宿主机的低权限账户。
  • 运维跳板机、开发服务器上的普通 SSH 账户。
  • 定时任务、CI Runner 或中间件服务账户。
  • 允许本地交互登录但不在 sudo 组中的外包或临时账户。

如果攻击成功,攻击者可能读取密钥与配置、修改审计日志、植入持久化任务,或继续横向使用主机上的凭据。该漏洞应按完整 root 权限失陷风险处理。

技术分析

sudo 在以 sudoedit 方式运行并处理 shell 模式参数时,对反斜杠转义字符的解析存在不一致。参数长度计算与后续反转义复制使用了不同的边界条件,特定输入可导致数据写出目标堆缓冲区。

由于 sudo 通常带有 setuid 位,相关解析代码运行在 root 权限上下文中。攻击者可尝试控制相邻堆对象,使单纯的越界写进一步转化为代码执行。漏洞核心不在 sudoers 授权规则,因此配置“用户无 sudo 权限”不能阻断此问题。

资产与版本排查

首先确认 sudo 的真实路径、文件权限、安装来源和发行版修订版本。以下命令只读取系统信息,不触发漏洞利用:

# 二进制路径与 setuid 状态
command -v sudo
command -v sudoedit
ls -l "$(command -v sudo)" "$(command -v sudoedit)"
stat -c '%A %a %U:%G %n' "$(command -v sudo)"

# 上游版本及插件版本
sudo --version | head -n 12

# Debian / Ubuntu
dpkg-query -W -f='${Package} ${Version} ${Architecture}\n' sudo
apt-cache policy sudo
zgrep -i 'CVE-2021-3156' /usr/share/doc/sudo/changelog.Debian.gz 2>/dev/null

# RHEL / CentOS / Rocky / AlmaLinux / Fedora
rpm -q sudo --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n'
rpm -q --changelog sudo | grep -i -m 3 'CVE-2021-3156'

正常情况下,sudo 文件权限中会出现 s,例如 -rwsr-xr-x。若所在挂载点启用了 nosuid,内核不会赋予其 setuid 权限,但这只能视为当前利用条件受限,不能替代软件修复。

# 检查 sudo 所在文件系统及挂载参数
findmnt -T "$(command -v sudo)" -o TARGET,SOURCE,FSTYPE,OPTIONS

# 核对软件包文件是否被本地修改
# Debian / Ubuntu
dpkg -V sudo

# RPM 系发行版
rpm -V sudo

判断时应遵循以下顺序:

  • 优先查看发行版安全公告是否明确标注 CVE-2021-3156 已修复。
  • 检查已安装包的完整发行版版本号,包括 revision、release 和 security 后缀。
  • 通过包内 changelog 或厂商漏洞数据库确认是否包含回移补丁。
  • 不要因为版本号低于 1.9.5p2 就直接认定存在漏洞,也不要因为运行时未崩溃就认定安全。

授权验证建议

生产环境不建议直接运行公开利用脚本,也不建议使用可能触发堆损坏的探测参数。堆布局会受发行版、glibc、环境变量和本地配置影响,失败的验证可能只表现为进程崩溃,同时留下不完整证据。

授权测试中建议采用“软件包证据优先”的验证方式:

  • 记录操作系统版本、内核版本、sudo 包完整版本和仓库来源。
  • 确认 sudo 是否具有 setuid root 权限。
  • 确认本地低权限账户能否执行 sudo 二进制;无需验证其 sudoers 权限。
  • 对照对应发行版公告判断当前软件包是否包含补丁。
  • 需要动态复现时,应使用隔离快照、测试账户和与目标一致的软件包构建环境,不在业务主机执行利用载荷。
# 建议保存到授权测试证据中的基础信息
id
uname -a
cat /etc/os-release
sudo --version | head -n 12
stat -c '%A %a %U:%G %n' "$(command -v sudo)"
findmnt -T "$(command -v sudo)" -o TARGET,SOURCE,FSTYPE,OPTIONS

日志留痕与失陷排查

该漏洞利用发生在本地进程中,sudo 日志未必包含完整命令参数。成功利用后,攻击者也可能主动删除 auth.log 或 journal,因此“未发现 sudo 记录”不能证明未被利用。

可先检查 sudo、sudoedit 调用记录以及内核中的崩溃信息:

# systemd journal
journalctl --since '7 days ago' _COMM=sudo
journalctl --since '7 days ago' _COMM=sudoedit
journalctl -k --since '7 days ago' | grep -Ei 'sudo(edit)?.*(segfault|general protection|core dumped)'

# Debian / Ubuntu 传统日志
zgrep -hEi 'sudo|sudoedit|segfault|general protection' /var/log/auth.log* /var/log/kern.log* 2>/dev/null

# RHEL 系传统日志
zgrep -hEi 'sudo|sudoedit|segfault|general protection' /var/log/secure* /var/log/messages* 2>/dev/null

# auditd 已启用时
ausearch -x sudo -ts recent -i
ausearch -x sudoedit -ts recent -i
ausearch -m EXECVE -ts recent -i | grep -Ei 'sudo|sudoedit'

需要重点关联的异常包括:

  • 普通服务账户执行 sudo 或 sudoedit,但 sudoers 中没有对应业务需求。
  • sudo 进程出现 segfault、general protection fault 或异常 core dump。
  • sudo 调用后短时间内出现 uid=0 的 shell、解释器或网络工具。
  • /etc/sudoers.d、/etc/passwd、/etc/shadow、root 的 authorized_keys 被修改。
  • /etc/cron.d、systemd unit、LD_PRELOAD 配置或 setuid 文件出现新增和变更。
# 排查近期权限与持久化变更
find /etc/sudoers.d /etc/cron.d /etc/systemd/system /root/.ssh \
  -xdev -type f -mtime -14 -ls 2>/dev/null

# 查找异常 setuid 文件,结果应与基线比对
find / -xdev -type f -perm -4000 -ls 2>/dev/null

# 检查关键账户文件时间与属性
stat /etc/passwd /etc/shadow /etc/sudoers /root/.ssh/authorized_keys 2>/dev/null

# 查看近期 root 进程执行记录,前提是已部署 auditd
ausearch -ua 0 -ts recent -m EXECVE -i

补充审计规则

尚未完成批量升级时,可临时增加 sudo 执行审计,用于缩短暴露窗口内的调查盲区。auditd 规则只能提供留痕,不能阻止漏洞利用。

# 临时规则,重启后失效
auditctl -w /usr/bin/sudo -p x -k sudo_exec

# 某些系统中 sudoedit 是指向 sudo 的符号链接,先确认实际路径
readlink -f /usr/bin/sudoedit

# 持久化规则
cat > /etc/audit/rules.d/50-sudo-exec.rules <<'EOF'
-w /usr/bin/sudo -p x -k sudo_exec
EOF

augenrules --load
ausearch -k sudo_exec -i

审计规则上线前应评估日志量,尤其是多人运维机和自动化平台。sudoedit 通常通过 argv[0] 区分运行模式,调查 EXECVE 记录时不仅要看 exe 字段,也要检查 a0 参数是否为 sudoedit。

修复步骤

首选方案是从受信任的发行版仓库升级 sudo。升级前保持一个经过授权的 root 控制台会话,避免包管理或 sudo 配置异常造成远程失联。

# Debian / Ubuntu
apt-get update
apt-get install --only-upgrade sudo

# RHEL / Rocky / AlmaLinux / Fedora
dnf upgrade sudo

# 旧版 CentOS / RHEL
yum update sudo

# 升级后再次确认
sudo --version | head -n 12
dpkg-query -W sudo 2>/dev/null || rpm -q sudo

若暂时无法升级,可在具备控制台 root 通道的维护窗口中移除 sudo 的 setuid 位,作为短时应急措施:

# 执行前必须确认另有可用的 root 登录或控制台通道
chmod u-s /usr/bin/sudo
stat -c '%A %a %U:%G %n' /usr/bin/sudo

该措施会使正常 sudo 提权失效,可能影响自动化任务。完成软件包升级后,应通过重新安装或修复发行版软件包恢复正确权限,不建议脱离包管理器长期手工维护权限位。

修复验证

  • 确认当前安装包已被发行版标记为修复 CVE-2021-3156。
  • 确认软件包来源未指向未知第三方仓库。
  • 确认 sudo 二进制校验结果没有非预期修改。
  • 确认 sudoers 配置语法正常,业务授权未被扩大。
  • 回看升级前后的 sudo、audit 和内核日志,确认不存在异常提权痕迹。
# sudoers 配置检查
visudo -c

# 查看启用的仓库与软件包来源
apt-cache policy sudo 2>/dev/null
repoquery -i sudo 2>/dev/null

# 检查升级时间附近的日志
journalctl --since '2 hours ago' | grep -Ei 'sudo|sudoedit|package|dnf|yum|apt'

结论

CVE-2021-3156 的关键风险在于它绕过了 sudoers 权限边界:本地账户是否被授予 sudo 权限并不是安全判断条件。排查时应围绕软件包补丁状态、setuid 条件、本地账户入口和审计日志建立证据链。修复应以发行版安全更新为准,动态利用验证只应在授权、隔离且可回滚的复现环境中进行。若日志中已经出现异常 sudo 崩溃或低权限账户后的 root 活动,应按主机失陷流程处置,而不是仅完成补丁升级。

服务器与云环境安全示意图
服务器、云资产与权限边界梳理示意
漏洞验证与修复流程示意图
漏洞成因、验证条件与修复闭环示意

这个漏洞排查时不要只比较 sudo --version,很多发行版会在版本号基本不变的情况下回补补丁。上游受影响范围大致为 1.8.2~1.8.31p2、1.9.0~1.9.5p1,但最终应以发行版安全公告和软件包修订号为准。

可以先确认实际二进制、版本及包来源:

command -v sudo
sudo --version | head -n 1
ls -l "$(command -v sudo)"
readlink -f "$(command -v sudo)"

# Debian / Ubuntu
dpkg-query -W -f='${Package} ${Version} ${Status}\n' sudo
apt-cache policy sudo
zgrep -i 'CVE-2021-3156' /usr/share/doc/sudo/changelog.Debian.gz 2>/dev/null

# RHEL / CentOS / Rocky / Alma
rpm -q sudo
rpm -q --changelog sudo | grep -i -m1 'CVE-2021-3156'
dnf updateinfo info --cves CVE-2021-3156 2>/dev/null || \
yum updateinfo info --cves CVE-2021-3156

# SUSE
rpm -q sudo
zypper lp --cve CVE-2021-3156

# Arch
pacman -Qi sudo | grep -E '^(Name|Version)'

需要注意的是,攻击者只要已经取得本地普通账号即可利用,并不要求该账号存在于 sudoers。因此“用户没有 sudo 权限”不能作为未受影响的依据。

修复优先使用发行版仓库提供的安全更新,不建议直接手工覆盖 /usr/bin/sudo:

# Debian / Ubuntu
apt-get update
apt-get install --only-upgrade sudo

# RHEL 系
dnf upgrade sudo
# 老版本系统
yum update sudo

# SUSE
zypper update sudo

# Arch
pacman -Syu sudo

更新后重新查询包版本,并检查文件是否仍由包管理器维护:

# Debian / Ubuntu
dpkg -V sudo
dpkg-query -W -f='${Version}\n' sudo

# RPM 系
rpm -V sudo
rpm -q sudo

sudo 通常是短生命周期进程,升级后一般不需要重启系统;但应结束现有管理员会话并重新执行一次,确认调用的是已更新的文件。多台机器排查时,建议采集“发行版、系统版本、sudo 包完整版本、仓库来源”,而不是只收集上游版本号。

如果暂时无法升级,较直接的临时缓解方式是撤销 sudo 的 SUID 位:

chmod u-s /usr/bin/sudo

这会导致普通用户完全无法通过 sudo 提权,执行前必须确保有可用的 root 控制台、带外管理或其他恢复通道。完成升级后,应通过重新安装软件包恢复正确权限,而不是凭经验手工设置:

# Debian / Ubuntu
apt-get --reinstall install sudo

# RPM 系
dnf reinstall sudo

最后,单纯查看 sudo 日志不一定能判断是否被利用,因为该漏洞可能在正常策略校验前触发。若怀疑主机已失陷,应进一步核查补丁前后的异常本地登录、近期新增 SUID 文件、root 权限进程和持久化项:

find / -xdev -type f -perm -4000 -printf '%TY-%Tm-%Td %TH:%TM %u %p\n' 2>/dev/null | sort
awk -F: '$3 == 0 {print $1 ":" $6 ":" $7}' /etc/passwd
systemctl list-unit-files --state=enabled
find /etc/cron* /var/spool/cron -type f -mtime -30 -ls 2>/dev/null
journalctl --since '30 days ago' _UID=0 2>/dev/null

不建议在生产机上直接运行公开 PoC 做验证;以厂商包状态、软件包修订号和完整性检查作为判定依据更稳妥。

创建帐户或登录后发表意见

最近浏览 0

  • 没有会员查看此页面。