CVE-2019-15846 分析

通过比对补丁可以发现以下修复:

src\string.cstring_interpret_escape()函数加了一句if (ch == '\0') return **pp;

/*************************************************
* Interpret escape sequence *
*************************************************/

/* This function is called from several places where escape sequences are to be
interpreted in strings.

Arguments:
pp points a pointer to the initiating "\" in the string;
the pointer gets updated to point to the final character
If the backslash is the last character in the string, it
is not interpreted.
Returns: the value of the character escape
*/

int
string_interpret_escape(const uschar **pp)
{
#ifdef COMPILE_UTILITY
const uschar *hex_digits= CUS"0123456789abcdef";
#endif
int ch;
const uschar *p = *pp;
ch = *(++p);
if (ch == '\0') return **pp; // bug fix in cve 2019 15846
if (isdigit(ch) && ch != '8' && ch != '9')
{
ch -= '0';
if (isdigit(p[1]) && p[1] != '8' && p[1] != '9')
{
ch = ch * 8 + *(++p) - '0';
if (isdigit(p[1]) && p[1] != '8' && p[1] != '9')
ch = ch * 8 + *(++p) - '0';
}
}
else switch(ch)
{
case 'b': ch = '\b'; break;
case 'f': ch = '\f'; break;
case 'n': ch = '\n'; break;
case 'r': ch = '\r'; break;
case 't': ch = '\t'; break;
case 'v': ch = '\v'; break;
case 'x':
ch = 0;
if (isxdigit(p[1]))
{
ch = ch * 16 +
Ustrchr(hex_digits, tolower(*(++p))) - hex_digits;
if (isxdigit(p[1])) ch = ch * 16 +
Ustrchr(hex_digits, tolower(*(++p))) - hex_digits;
}
break;
}
*pp = p;
return ch;
}

利用过程:

有关此漏洞的一些详细说明:
-首先,我们使用tls连接到exim并发送一个以反斜杠null结尾的sni(由于string_printing2()中的反斜杠错误,此sni未经修改而写入spool)。
-其次,我们利用string_interpret_escape()中的反斜杠空错误(sni是从spool读取的,由string_unprinting()取消转义),并将此越界读取转换为越界写入(堆溢出)。
-接下来,我们使用这个堆溢出覆盖空闲malloc块的头,并增加其大小,使其与其他已分配的malloc块重叠。
-最后,我们分配这个扩展的malloc块,并用它覆盖堆的大部分(已经分配的malloc块)

接下来编译一份exim4来进行调试

参考文章: