7.1.7 CVE-2018-6323 GNU binutils elf_object_p 整型溢出漏洞

下载文件

漏洞描述

二进制文件描述符(BFD)库(也称为libbfd)中头文件 elfcode.h 中的 elf_object_p() 函数(binutils-2.29.1 之前)具有无符号整数溢出,溢出的原因是没有使用 bfd_size_type 乘法。精心制作的 ELF 文件可能导致拒绝服务攻击。

漏洞复现

推荐使用的环境
备注

操作系统

Ubuntu 16.04

体系结构:32 位

调试器

gdb-peda

版本号:7.11.1

漏洞软件

binutils

版本号:2.29.1

系统自带的版本是 2.26.1,我们这里编译安装有漏洞的最后一个版本 2.29.1:

$ wget https://ftp.gnu.org/gnu/binutils/binutils-2.29.1.tar.gz
$ tar zxvf binutils-2.29.1.tar.gz
$ cd binutils-2.29.1/
$ ./configure --enable-64-bit-bfd
$ make && sudo make install
$ file /usr/local/bin/objdump
/usr/local/bin/objdump: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=c2e0c7f5040cd6798b708cb29cfaeb8c28d8262b, not stripped

使用 PoC 如下:

需要注意的是如果在 configure 的时候没有使用参数 --enable-64-bit-bfd,将会出现下面的结果:

漏洞分析

首先要知道什么是 BFD。BFD 是 Binary File Descriptor 的简称,使用它可以在你不了解程序文件格式的情况下,读写 ELF header, program header table, section header table 还有各个 section 等。当然也可以是其他的 BFD 支持的对象文件(比如COFF,a.out等)。对每一个文件格式来说,BFD 都分两个部分:前端和后端。前端给用户提供接口,它管理内存和规范数据结构,也决定了哪个后端被使用和什么时候后端的例程被调用。为了使用 BFD,需要包括 bfd.h 并且连接的时候需要和静态库 libbfd.a 或者动态库 libbfd.so 一起连接。

看一下这个引起崩溃的二进制文件,它作为一个可重定位文件,本来不应该有 program headers,但这里的 Number of program headers 这一项被修改为一个很大的值,已经超过了程序在内存中的范围:

objdump 用于显示一个或多个目标文件的各种信息,通常用作反汇编器,但也能显示文件头,符号表,重定向等信息。objdump 的执行流程是这样的:

  1. 首先检查命令行参数,通过 switch 语句选择要被显示的信息。

  2. 剩下的参数被默认为目标文件,它们通过 display_bfd() 函数进行排序。

  3. 目标文件的文件类型和体系结构通过 bfd_check_format() 函数来确定。如果被成功识别,则 dump_bfd() 函数被调用。

  4. dump_bfd() 依次调用单独的函数来显示相应的信息。

回溯栈调用情况:

一步一步追踪函数调用:

最关键的部分,读取 program headers 的逻辑如下:

因为伪造的数值 0xffff 大于 0,进入读取 program headers 的代码。然后在溢出点乘法运算前,eax 为伪造的数值 0x20000000

做乘法运算,0x20000000 * 0x38 = 0x700000000,产生溢出。截断后高位的 0x7 被丢弃, eax 为 0x00000000,且 OVERFLOW 的标志位被设置:

于是,在随后的 bfd_alloc() 调用时,第二个参数即大小为 0,分配不成功:

在后续的过程中,从 bfd_close_all_done()objalloc_free(),用于清理释放内存,其中就对 bfd_alloc() 分配的内存区域进行了 free() 操作,而这又是一个不存在的地址,于是抛出了异常。

补丁

该漏洞在 binutils-2.30 中被修复,补丁将 i_ehdrp->e_shnum 转换成 unsigned long 类型的 bfd_size_type,从而避免整型溢出。BFD 开发文件包含在软件包 binutils-dev 中:

由于存在回绕,一个无符号整数表达式永远无法求出小于零的值,也就不会产生溢出。

所谓回绕,可以看下面这个例子:

补丁如下:

打上补丁之后的 objdump 没有再崩溃:

参考资料

Last updated

Was this helpful?