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), that configuration will by default not enforce encrypted connections to the smarthost. There is documentation in README.Debian.gz on how to enable encryption, but the steps laid out there have no effect, and Exim can still fall back to using unencrypted connection when connecting to the smarthost. And even if an encrypted connection is used, the certificate of the server is not verified. Workaround ---------- Set hosts_require_tls = * tls_verify_hosts = * on the remote_smtp_smarthost transport. Any encrypted connection for which certificate verification fails will be closed, and delivery will be deferred. The client Exim will never use unencrypted connections to the smarthost. Alternatively, the same effect can be achieved by setting REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS = * REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOSTS = * in /etc/exim4/conf.d/main/000_localmacros, although the latter one is only available since Debian 11 (bullseye). Details ======= When configuring Exim to use a smarthost by name (e.g. `smarthost.example.com`, but not `smarthost.example.com/MX`) and to encrypt the connection to the smarthost, I expect Exim to - require encryption (no fallback to an unencrypted connection), - verify the certificate (e.g. validity period, purpose, etc), - verify that the certificate is (recursily) signed by a trusted CA, - require the configured hostname to match the certificate, - and to refrain from using the connection if any of the above steps fail. This is what I'll call _fully verified SSL_. Connections that use encryption but don't ensure that all of those verification steps succeed I'll call _unverified SSL_. I'm excluding smarthosts looked up via MX records here, because I'm currently not in that situation, and also I have no clue how that is supposed to be matched to certificates. So I have no expectations there. To avoid the mail content being intercepted between client and smarthost, I'd like to require fully verified SSL on that connection. `/usr/share/doc/exim4/README.Debian.gz`, section 2.2.1. "Exim 4 as TLS/SSL client" explains that > Exim will use TLS via STARTTLS automatically as client if the server Exim > connects to offers it. This is opportunistic SSL/TLS, which makes sense in the context of independent mailservers talking with each other. As a client talking to a smarthost, I should know whether the server supports TLS or not, and in the case considered here it does support it. In this situation, doing SSL/TLS opportunistically will lower security. The documentation then goes on to talk about client certificates. Sandwiched between two paragraphs dealing with those is a paragraph > The certificate presented by the remote host is not checked unless you > specify a tls_verify_certificate option on the transport. So to enable verification of certificates I need to set an option. Nowhere does it say how to switch from opportunistic encryption to required and fully verified SSL. But verifying the certificate does not really make sense in an opportunistic setting, where the client is prepared to fall back to an unencrypted connection. So from that documentation I'd consider it is reasonable to assume that by turning on that option I will implicitly make fully verified SSL mandatory. What should the option be set to? `README.Debian.gz` does not say. Exim's `spec.info` does not know that option either, strictly speaking, but there is a setting on the smtp transport named `tls_verify_certificates` (note the `s` at the end), so let's go with that. `spec.info` says in "Private options for smtp": ``` ‘tls_verify_certificates’Use: _smtp_ Type: Default: _string_*__ _system_ The value of this option must be either the word "system" or the absolute path to a file or directory containing permitted certificates for servers, for use when setting up an encrypted connection. The "system" value for the option will use a location compiled into the SSL library. [...] [...] For back-compatibility, if neither tls_verify_hosts nor tls_try_verify_hosts are set (a single-colon empty list counts as being set) and certificate verification fails the TLS connection is closed. ``` So, this option actually has a default value `system`, which seems to imply reasonable behaviour. The last paragraph also sounds reasonable: if no host is explicitly configured to be checked, then check every host. Closing the TLS connection on verification failure sounds reasonable as well (what else would you do?). So from this I'd expect that after setting that option to `system` I'll definitely require fully verified SSL. It's a bit odd that `README.Debian.gz` instructs me to set an option that already has a reasonable default, but maybe that is cleared in Debian's configuration somewhere? So let's try it out. How to Reproduce ================ I checked that indeed encryption and successfull certificate verification is not enforced 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. 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 removing the CA that signed the smarthost's certificate from the certificate store on the client again, so the client should *not* trust the smarthost's Exim. I appended `tls_verify_certificates=system` to `/etc/exim4/conf.d/transport/30_exim4-config_remote_smtp_smarthost` on the client. I then sent a mail from the client to r...@target.com: ``` client> exim4 -i r...@target.com <<EOF testmarker EOF ``` The mail appeared on the target host: ``` target> grep testmarker /var/mail/mail testmarker ``` I started combing through `/etc/exim4/conf.d` for macros and looking deeper at Exim's `spec.info`. I tried these settings, all of them on the smarthost transport: - `tls_verify_certificates = system`, - `tls_verify_hosts = *`, and - `hosts_require_tls = *` (by way of setting `REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS = *` in `/etc/exim4/conf.d/main/000_localmacros`) None of these were effective in isolation, they either did not enforce encryption, or did not enforce successful certificate verification, or both. I did not try every combination, but the combination of `REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS = *` and `tls_verify_hosts = *` was effective in preventing mail to be delivered and passwords being leaked when the ssl-sniffer was active. From `/var/log/exim4/mainlog` on the client: ``` 2020-09-02 07:17:05 1kDQlF-0000et-Ln <= r...@client.example.com U=root P=local S=321 2020-09-02 07:17:05 1kDQlF-0000et-Ln == r...@target.com R=smarthost T=remote_smtp_smarthost defer (-37) H=smarthost.example.com [10.0.3.1]: TLS session: (certificate verification failed): certificate invalid ``` When reenabling the smarthosts CA on the client: ``` 2020-09-02 07:14:44 1kDQiy-0000eq-NN <= r...@client.example.com U=root P=local S=321 2020-09-02 07:14:44 1kDQiy-0000eq-NN => r...@target.com R=smarthost T=remote_smtp_smarthost H=smarthost.example.com [10.0.3.1] X=TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256 CV=yes DN="C=US,CN=smarthost.example.com" A=cram_md5 K C="250- 330 byte chunk, total 330\\n250 OK id=1kDQiy-0000RC-Sx" 2020-09-02 07:14:44 1kDQiy-0000eq-NN Completed ``` 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' ``` This was initially reported 2020-09-04 to secur...@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 --
signature.asc
Description: PGP signature