Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2018-6789 — Exploit for CVE-2018-6789, a heap buffer overflow in Exim's base64 decoding, achieving remote code execution via chunk overlap and ACL string manipulation. | Kitploit
Tools/GitHubGitHub/beraphin/cve-2018-6789
Vulnerability AnalysisExploitationCTFLearning & EducationBinary ExploitationLabs & Practice
GitHubberaphin/cve-2018-6789

CVE-2018-6789

Exploit for CVE-2018-6789, a heap buffer overflow in Exim's base64 decoding, achieving remote code execution via chunk overlap and ACL string manipulation.

View Repository
3156 years agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2018-6789

Environment Setup

Install dependencies

apt-get install gcc net-tools vim gdb python wget git make procps libpcre3-dev libdb-dev libxt-dev libxaw7-dev

Download an old version of exim

wget ftp://mirror.easyname.at/exim-ftp/exim/exim4/old/exim-4.89.tar.gz
tar -xvzf ./exim-4.89.tar.gz
cd ./exim-4.89
cp src/EDITME Local/Makefile
cp exim_monitor/EDITME Local/eximon.conf

Then modify Local/Makefile For convenience, point all directories to the current directory

BIN_DIRECTORY=/home/zzx/EVA/cve-2018-6789/exim-4.89/bin
CONFIGURE_FILE=/home/zzx/EVA/cve-2018-6789/exim-4.89/configure
SPOOL_DIRECTORY=/home/zzx/EVA/cve-2018-6789/exim-4.89/exim
EXIM_USER=zzx
AUTH_PLAINTEXT=yes
AUTH_CRAM_MD5=yes
AUTH_TLS=yes

This is convenient for debugging Then compile and install

make install

Modify ./configure, overwrite with the content below

acl_smtp_mail=acl_check_mail
acl_smtp_data=acl_check_data
begin acl
acl_check_mail:
  .ifdef CHECK_MAIL_HELO_ISSUED
  deny
    message = no HELO given before MAIL command
    condition = ${if def:sender_helo_name {no}{yes}}
  .endif

  accept

acl_check_data:
  accept

begin authenticators
fixed_cram:
  driver = cram_md5
  public_name = CRAM-MD5
  server_secret = ${if eq{$auth1}{ph10}{secret}fail}
  server_set_id = $auth1

Running

./bin/exim -bd -d-receive

Vulnerability Analysis

First, analyze the patch in base64.c: 1 Here, result is the buffer where the base64 decoding result is stored, allocated by the store_get function.

It can be seen that the size calculation before the patch is problematic. When the size is in the range of 4n to 4n+3, the calculated size lengths are equal, but when b64decode decodes parameters that are not multiples of 4, it decodes one or two extra bytes.

For example, sending directly:

auth_md5('Hf'*42)

size=0x40 Memory layout:

pwndbg> hexdump 0x711d60 0x50
+0000 0x711d60  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  1d f1 df 1d  │....│....│....│....│
+0010 0x711d70  f1 df 1d f1  df 1d f1 df  1d f1 df 1d  f1 df 1d f1  │....│....│....│....│
+0020 0x711d80  df 1d f1 df  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  │....│....│....│....│
+0030 0x711d90  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  1d f1 df 00  │....│....│....│....│
+0040 0x711da0  20 61 61 61  61 61 61 61  61 61 61 61  61 61 61 61  │.aaa│aaaa│aaaa│aaaa│

Try again:

auth_md5('Hf'*42+'HfH')

size=0x40

pwndbg> hexdump 0x711d60 0x50
+0000 0x711d60  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  1d f1 df 1d  │....│....│....│....│
+0010 0x711d70  f1 df 1d f1  df 1d f1 df  1d f1 df 1d  f1 df 1d f1  │....│....│....│....│
+0020 0x711d80  df 1d f1 df  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  │....│....│....│....│
+0030 0x711d90  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  1d f1 df 1d  │....│....│....│....│
+0040 0x711da0  f1 61 61 61  61 61 61 61  61 61 61 61  61 61 61 61  │.aaa│aaaa│aaaa│aaaa│

Two bytes overflowed.

Exim Memory Management Mechanism

To improve performance, exim implements its own memory management mechanism on top of the original heap management. It acts as an intermediate buffer between the code and glibc, aiming to reduce the number of malloc and free calls. 2 For exim, a separate heap chunk is called a storeblock. Each time, a buffer of appropriate size is split from within it for use. If a storeblock is used up, another storeblock is allocated via malloc. For each storeblock, its structure is a simple singly linked list:

/* Structure describing the beginning of each big block. */
typedef struct storeblock {
  struct storeblock *next;
  size_t length;
} storeblock;

The main APIs used by the program for heap are in store.c:

store_get
store_release
store_extend
store_reset

store_get is used to obtain a buffer, key code as follows:

128 void *
129 store_get_3(int size, const char *filename, int linenumber)
....
145   int length = (size <= STORE_BLOCK_SIZE)? STORE_BLOCK_SIZE : size;
...
161   /* If there was no free block, get a new one */
162 
163   if (!newblock)
164     {
165     pool_malloc += mlength;           /* Used in pools */
166     nonpool_malloc -= mlength;        /* Exclude from overall total */
167     newblock = store_malloc(mlength);
...

It can be seen that the minimum length of a store_block applied each time is STORE_BLOCK_SIZE, i.e., 8192.

Therefore, a 8192-byte store_block, plus its structure header and heap header, has a total size of 0x2020. 3

Each time exim executes a command sent by the client, if the command execution is successful, it calls store_reset to release unnecessary caches and excess store_blocks. "Successful execution" here means the command format is correct, the email does not contain illegal characters, etc., otherwise store_reset is not called.

Exploit Strategy

This vulnerability is a classic off-by-one (though actually two bytes can overflow), but because the overflowed bytes are few, it is not possible to directly overwrite sensitive structures on the heap. Therefore, it is necessary to leverage some ptmalloc features to amplify the impact of this vulnerability and turn it into a larger overflow, or overlap. For off-by-one vulnerabilities, there is a classic exploitation method: chunk enlarge -> chunk overlap. By enlarging the size of a heap chunk and then forging a heap header to bypass glibc sanity checks, chunk overlap is achieved, allowing a larger range of overwrite.

The main process here is: chunk enlarge -> chunk overlap -> corrupt next pointer in storeblock, then trigger store_reset to cause an arbitrary heap chunk free. When this heap chunk is allocated again, its content can be modified (type confusion). Meh's article recommends modifying the heap chunk where the ACL string resides, because there is a command execution function in the processing of ACL strings. There are many ACL strings, but most are NULL (possibly related to the configuration file). Here, I chose the acl_smtp_mail string, whose command execution syntax is:

${run{command}}

The approximate heap layout is as follows: 4

The first heap chunk is the one obtained from base64 decoding, used for off-by-one. Therefore, it should be at the end of a storeblock. For convenience, allocate a heap chunk larger than 0x2020 to store the base64 decoding result. The second heap chunk is sender_helo_name, used to overwrite the next heap chunk. sender_helo_name is not stored in a storeblock but directly malloced:

1832 static BOOL
1833 check_helo(uschar *s)
1834 {
...
1884 if (yield) sender_helo_name = string_copy_malloc(start);

So its size is arbitrary. The third heap chunk is the one obtained from base64 decoding, mainly used to forge the header and be overwritten. Therefore, it should be at the beginning of a storeblock. For convenience, directly allocate 0x2020 bytes.

Exploit

My exploit was also obtained step by step following online analysis. The general idea is the same, but the heap layout is a bit different from others, so some small parameters are different.

Download Tool