CVE-2021-3156(别名 Sudo Baron Samedit)提权漏洞复现

原理

背景知识:sudoedit 和命令参数解析

  • sudo 是 Linux 上的权限提升工具,普通用户可以用它执行需要 root 权限的命令。

  • sudoeditsudo 的一个子命令,用来以 root 权限编辑文件

  • 当我们在命令里加 -s-i 选项时,sudo 会尝试进入 shell 模式

  • 在解析命令行参数时,sudo 需要对特殊字符(如空格、引号、反斜杠 \)做转义处理

漏洞出在: sudo 在处理参数转义时,有一处内存复制(heap buffer copy)写入越界,导致堆缓冲区溢出。


 漏洞触发点

当以如下方式调用 sudoedit:

sudoedit -s '\' `perl -e 'print "A"x65536'`
  • -s 选项要求 sudo 启动 shell。

  • 参数中第一个反斜杠 '\' 被当作转义字符处理。

  • sudo 在处理时错误地以为还需要再加一个字符,于是多分配了一个字节。

  • 后面跟着巨长的 A(65536 个),于是触发堆缓冲区溢出

背景:sudoedit -s 与参数处理

  • sudoedit -s 表示让 sudo 启动一个 shell

  • sudoedit 会对传入的参数进行 shell escape / 转义处理,比如把 \ 当作转义符处理。

  • 在处理参数字符串时,sudo 会计算 最终字符串长度,然后分配缓冲区。


反斜杠 \ 的处理

  • 你传入的参数是:

'\' `perl -e 'print "A"x65536'`

  • 第一个字符是 \

  • 在 C 或 sudo 内部,\转义字符,意思是“下一个字符被转义”。

  • sudo 的逻辑:

if (c == '\\') {

// 预期后面跟一个字符需要转义

length += 2;

// 或者多分配一个字节?

}

  • 问题出在 sudo 的长度计算

    • 它遇到 \,认为后面还需要一个字符进行转义。

    • 但是这里 \ 后面什么都没有(或者是被单引号包住),sudo 依然多分配了 1 个额外字节,以“容纳被转义的字符”。

  • 也就是说,sudo 的算法是:

分配长度 = strlen(原始参数) + 1(额外字节,用于转义处理)

  • 这个“额外字节”在普通情况不会出问题,但遇到非常长的参数(65536 个 A)时,就可能触发 堆缓冲区溢出


结合巨长参数

  • 你用 perl -e 'print "A"x65536' 生成了 65536 个字符。【sudo 内部缓冲区大小sudo 对参数做拷贝时,会在堆上分配一个缓冲区。这个缓冲区在代码里可能定义为 16 位整数来存长度,最大值就是 2^16 = 65536。】

  • sudo 在计算缓冲区时:

需要分配的长度 = 65536 + 1(多分配的字节) = 65537

  • 某些系统 malloc/堆管理器在这种边界长度上处理不当,可能导致 堆溢出


为什么“多分配一个字节”会导致溢出?

  • sudo 内部有一个 固定长度缓冲区,比如 65536(2^16)字节。

  • 多分配一个字节(65537)就超出了原有缓冲区的容量。

  • 当 sudo 把参数复制进去时,最后多出来的 1 字节写入堆中 紧邻的内存,就触发了 堆缓冲区溢出


具体成因

  • sudoers_policy.cparse_args.c 中,sudo 有一个函数用来解析参数并处理转义:

    while (*src) { 
            if (*src == '\\') { 
                    *dst++ = *src++; 
            } 
            *dst++ = *src++; 
    } 
  • 正常情况下,\ 用来保护后面的字符,不被当作特殊字符。

  • sudoedit -s 的逻辑在处理参数列表时,没有正确计算需要拷贝到堆缓冲区的空间大小。

  • 攻击者可以精心构造参数(含转义符+超长字符串),使得拷贝到堆中的内容超过预分配的内存块 → 覆盖堆上的相邻结构体数据(如函数指针)

这就相当于:

  • 你准备了一个小杯子(缓冲区),

  • 结果被人往里灌了一桶水(超长参数),

  • 水溢出来覆盖了桌上的其他物品(堆上相邻的数据)。


利用方式

  • 因为 sudo 是 setuid root 程序(以 root 权限运行),

  • 攻击者只要能控制溢出的数据,就有机会覆盖堆上的控制结构,例如:

    • service_user 结构体的指针

    • 函数返回地址

  • 这样当 sudo 继续运行时,就会跳转到攻击者提供的 payload,

  • 直接获得 root shell,无需知道任何密码。

环境准备

建议在虚拟机中测试,避免影响日常使用系统。
受影响的环境包括:

  • Ubuntu 20.04 / 19.04

  • Debian 10

  • CentOS 8

  • sudo 版本在:

    • 1.8.2 – 1.8.31p2

    • 1.9.0 – 1.9.5p1

 查看 sudo 版本:

sudo --version 

如果显示类似:

Sudo version 1.8.31

说明处于漏洞范围内。


漏洞验证命令

执行下面的命令(会触发 sudo 参数解析):

sudoedit -s '\' `perl -e 'print "A"x65536'`

命令解释

  • sudoedit -s
    进入 sudoedit 模式,并尝试调用 shell。

  • '\''
    构造转义字符,触发参数解析错误。

  • `perl -e 'print "A"x65536'`
    使用 Perl 打印 65536 个 A,构造超长参数,触发堆溢出。


结果观察

  • 易受攻击系统
    会出现 Segmentation fault(进程崩溃),类似:

    Segmentation fault (core dumped)

  • 已修复系统
    会报参数错误:

    sudoedit: invalid option -- '\'


后续操作

  • 如果验证出系统存在漏洞,可以进一步尝试利用公开的 Exploit 获取 root


修复方式

更新 sudo 到安全版本:

# Debian / Ubuntu sudo apt-get update && sudo apt-get install sudo
# CentOS / RHEL sudo yum update sudo

确认修复后,重新执行漏洞验证命令,应该不会再触发崩溃。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值