前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >以UPX漏洞为例介绍整数溢出(基础篇)

以UPX漏洞为例介绍整数溢出(基础篇)

作者头像
FB客服
发布2018-07-30 15:56:09
9800
发布2018-07-30 15:56:09
举报
文章被收录于专栏:FreeBuf

*本文原创作者:tocttou,本文属FreeBuf原创奖励计划,未经许可禁止转载

我发现Freebuf上没有整数溢出漏洞的基础介绍,所以这篇文章通过分析我刚刚发现的UPX源代码中的整数溢出漏洞,介绍一下C/C++整数溢出漏洞的原理、触发和修复方法。这篇文章暂不涉及如何利用整数溢出达到远程代码执行,UPX的漏洞只是一个拒绝服务漏洞。

0x01 整数溢出原理

C/C++中的整数溢出基本原理非常简单,比如unsigned char number = 200 + 200;。最终number的值是400 mod 256=144。这是因为C++对于无符号整数(unsigned char, unsigned int等)溢出的处理是取模,导致的结果是两个整数相加,反而结果更小。C++中有符号整数溢出是未定义行为。下文中所有提到整数溢出,都指的是无符号整数溢出。整数溢出的利用一般都是用它来导致缓冲区溢出,进而利用缓冲区溢出技巧来代码执行、泄露内存或拒绝服务。

我认为对于文件解析一类的程序要特别注意整数溢出问题,因为有很多文件格式,它们的文件头中包含了长度、偏移信息。攻击者通过构造畸形文件可以直接控制这些信息,尝试触发整数溢出或其他缓冲区溢出漏洞。所以在写代码时我们需要关注的点有:第一,将整数运算的结果作为缓冲区长度分配内存;第二,将整数运算的结果作为偏移量读取内存。

对于第一点,比如这段代码:

如果len1是攻击者可控的值,那么这里就存在整数溢出问题。假设是32位程序,攻击者选取len1 = 0xFFFFFFC1,那么len1+40等于1,所以buffer的长度为1。第三行,作者错误地假设了下标0x10一定会在buffer分配的内存区间内,但实际上这里发生了越界写入。

对于第二点,看这段代码:

这里作者错误地假设了如果40 + offset这个index没有越界,则offset这个index也没有越界。但是如果我们取offset=255。则40 + offset = 39,那么我们就将buffer[255]这个越界地址写入了0。

0x02 分析UPX整数溢出漏洞

这个漏洞是我最近找出来的UPX开源项目的漏洞。因为最近研究UPX,随手在CVE数据库里搜索了一下有没有UPX的漏洞,结果还真有,CVE-2017-15056。漏洞报告在 https://github.com/upx/upx/issues/128 。这是一个畸形文件导致内存越界读取漏洞,我看了一下修复的commit。从commit来看,修复并不完美,而且正好可以拿来讲整数溢出。

我们重点看commit中PackLinuxElf32::PackLinuxElf32help1函数中添加在250-256行的校验:

file_size是用户输入的ELF文件的大小,e_phoff, e_phnum, e_shoff, e_shnum都是ELF文件头部的字段。这些值我们可以通过构造畸形ELF文件来控制。显然这里作者在避免缓冲区越界读取问题,检测e_shoff + e_shnum sizeof(Elf32_Shdr)这个偏移量是否依然在ELF文件大小之内。如果不在,就抛出异常,因为我们的缓冲区只有file_size这么大。作者想到了检查整数溢出,但是他的方法是把e_phoff和e_shoff从unsigned int转换成unsigned long。值得注意的是unsigned long的大小是:MSVC下永远是32位整数,gcc和clang下32位ELF就是32位整数,64位ELF就是64位整数。所以如果我们用32位UPX的话,(unsigned long)e_shoff + e_shnumsizeof(Elf32_Shdr)是可以溢出的,只要e_shoff足够大,让它们的和大于或等于2^32,它的值就可以小于file_size。

往下:

268至272行针对e_type不是ET_DYN (shared object file)情形,268行的len就是之前258行校验的值,按上文说的len是溢出之后的值,它小于file_size,但是e_phoff很大。所以到272行phdri=e_phoff + file_image又发生整数溢出,phdri会小于file_image。所以如果接下来phdri被用于读取Elf32_Phdr结构体的值,那么读到的实际上是缓冲区file_image以外的值。但是随后发现phdri使用之前会检查e_phoff是否为0x40。所以这个缓冲区越界读取是触发不了的。

接下来274行以下针对e_type是ET_DYN情形,类似地,因为我们取e_shoff为一个接近2^32的值,如0xFFFFE000,这样shdri= (Elf32_Shdr *)(e_shoff + file_image);指向的就是file_image内存之前的位置。然后进入elf_find_section_type(Elf32_Shdr::SHT_DYNSYM)函数:

for循环内shdri指针被用来读取shdri->sh_type的值。这时因为shdri不是一个有效的地址,这里就会触发崩溃。

所以我的PoC就直接把CVE-2017-15056的PoC拿来,把e_type改成3 (ET_DYN)、e_shoff改成0xFFFFE000、e_shnum改成0x00FF。这样e_shoff + e_shnum * sizeof(Elf32_Shdr)的值是0x07D8,小于file_size。shdri等于file_image - 0x2000。用32位UPX压缩PoC,就能看到崩溃:

当然这个整数溢出漏洞只能到拒绝服务为止了,应该是没法远程利用的(比如把内存写到输出文件里)。我也对UPX、ELF文件了解不多,所以就没深入研究其他位置有没有溢出问题。

0x03 修复

我提交了一个Pull request修复这个UPX漏洞,但是他们没用我的PR,他们自己写了一个commit。对于加法避免整数溢出的方法两种:加法运算的和如果小于任何一个加数,则有溢出:

另一种是转换成64位无符号整数:

乘法:转换成64位或者:

0x04 参考

https://github.com/upx/upx/issues/128 https://github.com/upx/upx/commit/ef336dbcc6dc8344482f8cf6c909ae96c3286317 https://github.com/upx/upx/pull/190 https://github.com/upx/upx/commit/90a1322929259b3049f11564d25cc1bc99ee54fa

*本文原创作者:tocttou,本文属FreeBuf原创奖励计划,未经许可禁止转载

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-04-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FreeBuf 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x01 整数溢出原理
  • 0x02 分析UPX整数溢出漏洞
  • 0x03 修复
  • 0x04 参考
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档