Exim Off-by-one RCE:利用完全缓解绕过的CVE-2018-6789

概观

我们在2018年2月5日报告了Exim的base64解码函数中的溢出漏洞,标识为CVE-2018-6789。自从exim第一次提交以来就存在这个错误,因此所有版本都受到影响。根据我们的研究,可以利用它来获得预授权远程代码执行,并且至少有400,000台服务器处于风险之中。补丁版本4.90.1已经发布,我们建议立即升级exim。

受影响

  • 所有Exim版本低于4.90.1

base64解码中有一个字节溢出

脆弱性分析

这是b64decode函数中解码缓冲区长度的计算错误:
base64.c:153 b64decode

b64decode(const uschar *code, uschar **ptr)
{
int x, y;
uschar *result = store_get(3*(Ustrlen(code)/4) + 1);

*ptr = result;
// perform decoding
}

如上所示,exim分配一个3*(len/4)+1字节缓冲区来存储解码后的base64数据。但是,如果输入不是有效的base64字符串且长度为4n+3exim,则会在解码时分配3n+1但占用3n+2字节。这会导致一个字节堆溢出(aka逐个)。
通常,这个错误是无害的,因为内存覆盖通常是未使用的。但是,当字符串适合某些特定长度时,该字节会覆盖一些关键数据。另外,这个字节是可控的,这使得开发更加可行。
Base64解码是这样一个基本功能,因此这个错误可以很容易地触发,导致远程代码执行。

开发

为了评估这个错误的严重程度,我们开发了一个针对exim的SMTP守护进程的攻击。以下段落描述了用于实现pre-auth远程代码执行的开发机制。为了利用这一个字节溢出,有必要诱骗内存管理机制。在阅读本节之前,强烈建议您具有堆开发的基本知识[ref]

我们开发了这个漏洞:

  • Debian(stretch)Ubuntu(zesty)
  • 使用apt-get安装Exim4软件包的SMTP守护进程(4.89 / 4.88)
  • 启用配置(在默认配置中未注释)CRAM-MD5身份验证器(使用base64的任何其他身份验证程序也可以运行)
  • 基本的SMTP命令(EHLO,MAIL FROM / RCPT TO)和AUTH

内存分配

首先,我们回顾一下源代码并搜索有用的内存分配。正如我们在前一篇文章中提到的,exim使用自定义函数进行动态分配:

extern BOOL    store_extend_3(void *, int, int, const char *, int);  /* The */
extern void    store_free_3(void *, const char *, int);     /* value of the */
extern void   *store_get_3(int, const char *, int);         /* 2nd arg is   */
extern void   *store_get_perm_3(int, const char *, int);    /* __FILE__ in  */
extern void   *store_malloc_3(int, const char *, int);      /* every call,  */
extern void    store_release_3(void *, const char *, int);  /* so give its  */
extern void    store_reset_3(void *, const char *, int);    /* correct type */

函数store_free()store_malloc()调用malloc()free()直接glibc。
Glibc需要一个稍大的(0x10字节)并将其元数据存储0x10在每个分配的第一个字节(x86-64)中,然后返回其位置data。下面的插图描述了块的结构:
Exim Off-by-one RCE:利用完全缓解绕过的CVE-2018-6789

元数据包括前一个块的大小(正好在内存中的那个),当前块的大小和一些标志。前三位size用于存储标志。在这个例子中,0x81隐含当前块的大小是0x80字节,并且前一个块正在使用中。
在exim中使用的大部分已发布的块被放入一个双向链表中,称为未排序的bin。Glibc根据标志维护它,并将相邻的已发布块合并到一个更大的块中以避免碎片化。对于每个分配请求,glibc都会以FIFO(先进先出)顺序检查这些块,并重新使用这些块。

对于一些性能问题,进出口维护自己的链表结构store_get()store_release()store_extend()store_reset()

Exim Off-by-one RCE:利用完全缓解绕过的CVE-2018-6789

storeblocks的主要特点是每个块至少有0x2000字节,这成为我们利用的限制。请注意,storeblock也是data一个块。因此,如果我们查看记忆,就像:

Exim Off-by-one RCE:利用完全缓解绕过的CVE-2018-6789

这里我们列出用来排列堆数据的函数:

  • EHLO主机名
    对于每个EHLO(或HELO)命令,exim存储主机名的指针sender_host_name

    • store_free() 老名字
    • store_malloc() 为新的名字

    smtp_in.c:1833 check_helo

  1839 /* Discard any previous helo name */
  1840
  1841 if (sender_helo_name != NULL)
  1842   {
  1843   store_free(sender_helo_name);
  1844   sender_helo_name = NULL;
  1845   }
  ...
  1884 if (yield) sender_helo_name = string_copy_malloc(start);
  1885 return yield;

无法识别的命令
对于每个具有不可打印字符的无法识别的命令,exim分配一个缓冲区以将其转换为可打印
  • store_get() 存储错误消息

smtp_in.c:5725 smtp_setup_msg

  5725   done = synprot_error(L_smtp_syntax_error, 500, NULL,
  5726     US"unrecognized command");

  • AUTH
    在大多数身份验证过程中,exim使用base64编码与客户端进行通信。编码和解码字符串存储在一个缓冲区中store_get()

    • store_get() 为字符串
    • 可以包含不可打印的字符,NULL字节
    • 不一定是null终止
  • 在EHLO / HELO,MAIL,RCPT中复位
    当命令正确完成时,smtp_reset()被调用。此函数调用store_reset()将块链重置为重置点,这意味着所有由store_get()last命令分配的storeblocks 被释放。

    • store_reset() 重置点(设置在功能的开始处)
    • 释放块一次添加

    smtp_in.c:3771 smtp_setup_msg

 3771 int
  3772 smtp_setup_msg(void)
  3773 {
  3774 int done = 0;
  3775 BOOL toomany = FALSE;
  3776 BOOL discarded = FALSE;
  3777 BOOL last_was_rej_mail = FALSE;
  3778 BOOL last_was_rcpt = FALSE;
  3779 void *reset_point = store_get(0);
  3780
  3781 DEBUG(D_receive) debug_printf("smtp_setup_msg entered\n");
  3782
  3783 /* Reset for start of new message. We allow one RSET not to be counted as a
  3784 nonmail command, for those MTAs that insist on sending it between every
  3785 message. Ditto for EHLO/HELO and for STARTTLS, to allow for going in and out of
  3786 TLS between messages (an Exim client may do this if it has messages queued up
  3787 for the host). Note: we do NOT reset AUTH at this point. */
  3788
  3789 smtp_reset(reset_point);

利用步骤

为了充分利用这一点,解码后的base64数据下的块应该易于释放和控制。经过多次尝试,我们发现这sender_host_name是一个更好的选择。我们安排堆布局,sender_host_name为base64数据留下一块空闲的块。

Exim Off-by-one RCE:利用完全缓解绕过的CVE-2018-6789

  1. 把一大块成无序斌
    首先,我们发送一个EHLO消息,巨大的主机名,使其分配和释放,留下一个0x6060长(3个storeblocks长)块在未分类垃圾桶。
  2. 剪下第一个storeblock
    然后我们发送一个无法识别的字符串来触发store_get()并在释放的chunk中分配storeblock。
  3. 剪下第二个存储区并释放第一个存储区
    我们再次发送EHLO消息以获得第二个存储区。由于smtp_resetEHLO完成后被调用,第一个块被顺序释放。

    堆布局准备好后,我们可以使用off-by-one覆盖原始块大小。我们修改0x20210x20f1,它稍微扩展了块。

    Exim Off-by-one RCE:利用完全缓解绕过的CVE-2018-6789

  4. 发送base64数据并逐个
    触发要逐个触发,我们启动一个AUTH命令来发送base64数据。溢出字节正好覆盖下一个块的第一个字节并扩展下一个块。
  5. 伪造一个合理的块大小
    由于块被扩展,所以下一块块的开始被改变到原始块的内部。因此,我们需要让它看起来像一个正常的块来通过glibc的理智检查。我们在这里发送另一个base64字符串,因为它需要NULL字节和不可打印字符来伪造块大小。
  6. 释放扩展块
    为了控制扩展块的内容,我们需要首先释放块,因为我们不能直接编辑它。也就是说,我们应该发送一个新的EHLO消息来释放旧的主机名。但是,正常EHLO消息调用smtp_reset成功后可能会导致程序中止或崩溃。为了避免这种情况,我们发送一个无效的主机名称,如a+
  7. 覆盖next重叠的存储区块的指针

Exim Off-by-one RCE:利用完全缓解绕过的CVE-2018-6789

块发布后,我们可以使用AUTH检索它并覆盖部分重叠的存储块。这里我们使用一种称为部分写入的技巧。有了这个,我们可以在不破坏ASLR(地址空间布局随机化)的情况下修改指针。我们部分地将next指针更改为包含ACL(访问控制列表)字符串的存储区块。ACL字符串由一组全局指针指向,例如:

 uschar *acl_smtp_auth;
 uschar *acl_smtp_data;
 uschar *acl_smtp_etrn;
 uschar *acl_smtp_expn;
 uschar *acl_smtp_helo;
 uschar *acl_smtp_mail;
 uschar *acl_smtp_quit;
 uschar *acl_smtp_rcpt;


8.这些指针在exim进程开始时初始化,根据配置进行设置。例如,如果acl_smtp_mail = acl_check_mail配置中有一行,指针acl_smtp_mail指向字符串acl_check_mail。无论何时使用MAIL FROM,exim都会执行ACL检查,该检查将acl_check_mail首先进行扩展。在扩展时,exim尝试在遇到命令时执行命令${run{cmd}},因此只要我们控制ACL字符串,就可以实现代码执行。另外,我们不需要直接劫持程序控制流程,因此我们可以轻松地绕过诸如PIE(位置独立可执行文件),NX等缓解措施。

9.重置存储区块并检索ACL存储区块
现在ACL存储区块位于链接列表链中。它一旦smtp_reset()被触发就会被释放,然后我们可以通过分配多个块来再次检索它。

10.覆盖ACL字符串并触发ACL检查
最后,我们覆盖包含ACL字符串的整个块。现在我们发送诸如EHLO,MAIL,RCPT等命令来触发ACL检查。一旦我们触及配置中定义的acl,我们就可以实现远程代码执行。

固定

升级到4.90.1或以上

时间线

  • 2018年2月5日09:10报告给Exim
  • 2011年2月6日23:23 CVE收到
  • 2018年2月10日18:00发布补丁

积分

DEVHORE研究团队Meh发现的漏洞。
meh [at] devco [dot] re

参考

https://exim.org/static/doc/security/CVE-2018-6789.txt
https://git.exim.org/exim.git/commit/cf3cd306062a08969c41a1cdd32c6855f1abecf1
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-6789
http://www.openwall.com/lists/oss-security/2018/02/07/2

本文来自DEVCPRE,经授权后发布,本文观点不代表MottoIN立场,转载请联系原作者。

发表评论

登录后才能评论

联系我们

021-62666911

在线咨询:点击这里给我发消息

邮件:root@mottoin.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code