项目标题
CVE-2021-3156 sudo 漏洞利用生成器
安装
- 安装依赖 ./install.sh
- 运行漏洞利用生成器:./run.sh
- 如果系统上的sudo版本存在漏洞,则会为已安装的版本生成漏洞利用代码
- 漏洞利用代码生成在 exploit.c 和二进制文件 ./exploit 中
前提条件
- gdb gcc make python3 python3-distro
- 带 tcache 的 glibc
- 当前支持 Ubuntu、Debian 操作系统
已测试环境
- Ubuntu 20.04.1
- Ubuntu 20.04.2
- Ubuntu 20.10
- Ubuntu 18.04.5
- Debian 10.7.0
作者
漏洞描述
- sudo 在 main 函数的 parse_args 中会对元字符进行转义
- 随后,在 set_cmnd 中,会删除那些后面没有空格的转义字符
- sudo 假设 parse_args 是 set_cmnd 的前置条件
- 问题在于每个解析器的条件不同。第一个解析器在模式为 (MODE_RUN && MODE_SHELL) 时执行。第二个解析器在模式为 (MODE_RUN | MODE_EDIT | MODE_CHECK) 且 (MODE_SHELL|MODE_LOGIN_SHELL) 时执行
- 存在一种方式不执行第一个解析器而执行第二个:sudoedit -s
- set_cmnd 计算参数长度并在堆上创建一个 chunk 用于拼接参数。然后逐个复制每个参数,直到遇到空字节,再继续处理下一个参数。如果输入参数以 '\' 结尾,set_cmnd 会跳过转义字符,复制空字节,但会继续将下一个参数视为同一参数进行复制。这会导致堆缓冲区溢出
- 因此,如果最后一个参数以 '\' 结尾,set_cmnd 会使用第一个环境变量的内容溢出缓冲区。如果该环境变量也以 '\' 结尾,则会继续复制下一个环境变量
漏洞利用生成器
- 使用 (https://packetstormsecurity.com/files/161160/Sudo-Heap-Based-Buffer-Overflow.html) 中描述的方法2
- 溢出后,sudo 使用 glibc nsswitch 读取 group 数据库
- nsswitch 在堆上创建一个 service_table 数据结构,包含所有数据库和 nsswitch.conf 中的服务
- group 的服务具有 struct service_user 类型
- 该结构体有一个 name 字段,用于存储服务名称
- nsswitch 根据 /etc/nsswitch.conf 中 group 数据库每个服务的配置,动态加载 libnss_[服务名称]_.so.2 库
- 必须将 library 指针覆盖为 NULL 以避免崩溃。此外,这会导致库重新加载到内存中,此次会加载一个包含 shellcode 的本地库
- 使用堆风水(heap grooming)技术。创建不同大小的"本地"环境变量,以在堆上生成特定的布局,使 set_cmnd 复制参数的 chunk 能够接近目标——即 group 的 service_user 结构体
- 在 set_cmnd 执行 malloc 之前,检查堆的 tcache,查看即将被回收的前几个 chunk 及其大小
- 对构成 nsswitch 数据库和服务的 chunk 进行排序。按顺序遍历它们。存储目标 chunk 和前一个 chunk 的内存地址
- 在 tcache bin 中搜索该范围内的 chunk
- 一旦知道 chunk 的位置和大小,即可生成漏洞利用代码
- 使用一个以 '\' 和空字节结尾的参数,其大小恰好使该 chunk 被回收
- 创建精确的"本地"环境变量,以生成合适的堆布局
- 在这些"本地"变量之前,创建一个大小足以到达目标结构体的环境变量
- 使用包含转义字符 '\' 的字符串数组将目标结构体覆盖为空字节,这会在 set_cmnd 中写入一个空字节
- 将 service_user 的 name 覆盖为 'x/x',以便后续加载库 'libnss_x/x.so.2'
- 在该库中创建一个构造函数,用于执行 shellcode
- 由于 sudo 以 suid 位运行,其 shell 属于 root
许可证
本项目采用 GNU GPL 许可证