概述
我们通过分析之后,在OpenBSD的邮件服务器OpenSMTPD中发现了一个安全漏洞,这个漏洞是一个越界读取漏洞,在该漏洞的帮助下,攻击者将能够在目标设备上以非Root用户身份实现远程Shell命令执行。
由于该漏洞存在于OpenSMTPD的客户端(负责将邮件发送至远程SMTP服务器)代码中,因此我们必须考虑以下两种不同的场景:
1、客户端漏洞利用:这个漏洞是一个存在于OpenSMTPD默认配置中的远程可利用的漏洞。尽管OpenSMTPD只会监听本地的localhost端口,但默认配置下,它能够接收来自本地用户的电子邮件,并将其转发至远程服务器端。如果攻击者能够控制负责接收转发邮件的远程服务器(无论是恶意服务器或是被入侵的服务器,或通过执行中间人攻击、DNS或BGP攻击),那么攻击者将能够在安装了OpenSMTPD的服务器或其他设备上实现任意Shell命令执行。
2、服务器端漏洞利用:首先,攻击者必须与负责接收外部邮件的目标OpenSMTPD服务器建立连接,然后向该服务器发送一封能够反弹Shell的邮件。接下来,当OpenSMTPD跟它们的邮件服务器建立连接并发送反弹邮件时,攻击者就可以利用OpenSMTPD的客户端漏洞来执行攻击了。最后,为了让攻击者的恶意Shell命令能够在目标设备上成功执行,攻击者必须让OpenSMTPD发生崩溃,并等待其重新启动(可通过管理员权限手动重启,或通过系统更新以及reboot命令自动重启)。
为了更好地研究、分析和演示这个漏洞,我们专门开发了一个针对该漏洞的漏洞利用PoC,并且成功地在OpenBSD v6.6、OpenBSD v5.9、Debian 10、Debian 11和Fedora 31中进行了漏洞利用测试。根据OpenBSD的要求,为了给OpenSMTPD的用户提供一个修复自己系统漏洞的机会,我们约定在2020年2月26日之前不会发布漏洞利用的细节,目前时间已到,因此我们正式发布了这篇漏洞分析报告。
漏洞分析
SMTP客户端与SMTP服务器建立连接之后,可以向其发送类似EHLO、MAIL FROM和RCPT TO之类的命令。SMTP服务器将会以单行或多行的形式发送响应数据:
1、第一行数据将会以三个数字字符开头,然后接上一个“-”符号,结尾就是可选的文本信息了,例如:"250-ENHANCEDSTATUSCODES";
2、最后一行将以同样的三个数字开头,后面跟上一个可选的空格符,再加可选的文本信息。
在OpenSMTPD的客户端代码中,这些多行响应将通过mta_io()函数来进行解析和处理,相关代码段如下:
------------------------------------------------------------------------------
1098 static void
1099 mta_io(struct io *io, int evt, void *arg)
1100 {
....
1133 case IO_DATAIN:
1134 nextline:
1135 line = io_getline(s->io, &len);
....
1146 if ((error = parse_smtp_response(line, len, &msg, &cont))) {
------------------------------------------------------------------------------
当line[3] == '-'成立时,第一行响应数据会被追加至一个大小为2KB的响应缓冲区replybuf中:
------------------------------------------------------------------------------
1177 if (cont) {
1178 if (s->replybuf[0] == '\0')
1179 (void)strlcat(s->replybuf, line, sizeof s->replybuf);
1180 else {
1181 line = line + 4;
....
1187 (void)strlcat(s->replybuf, line, sizeof s->replybuf);
1188 }
1189 goto nextline;
1190 }
------------------------------------------------------------------------------
当line[3] != '-'成立时,最后一行响应数据同样会被追加至响应缓冲区replybuf中:
------------------------------------------------------------------------------
1195 if (s->replybuf[0] != '\0') {
1196 p = line + 4;
....
1201 if (strlcat(s->replybuf, p, sizeof s->replybuf) >= sizeof s->replybuf)
------------------------------------------------------------------------------
不幸的是,如果最后一行数据中的三个数字字符后面没有接可选空格以及文本数据的话,那么上述代码的第1196行中的p将指向'\0'终止符后的第一个字符,因此这个越界字符串将会被追加到响应缓冲区replybuf中(第1201行)。
漏洞修复
目前,OpenBSD的开发人员已经解决了该问题,并发布了相应的漏洞修复补丁。
* 参考来源:openwall,FB小编Alpha_h4ck编译,转载请注明来自FreeBuf.COM