漏洞信息#

CVE编号:CVE-2020-7247
登记时间:2020-01-20
漏洞类型:命令执行RCE
NVD漏洞评分:9.8 Critical
操作系统:OpenBSD 6.6
漏洞软件:OpenSMTPD 6.6
Shell权限:root

漏洞原理#

OpenSMTPD向本地用户方法邮件是使用构建命令行(mda_command)并且调用的方法。为了防止构建命令行过程被攻击者调用,采取了过滤机制。但过滤的代码逻辑含有漏洞,导致攻击者可以绕过过滤,从而执行任意代码。

在OpenSMTPD漏洞版本源代码的smtp_session.c文件中,smtp_mailaddr执行了判断地址合法性,并且在某些不合法情况执行补救措施。

在上述文件的1640和1641行,我们可以发现,当地址的@左部分(user部分)和@右部分(domain部分)任一无法通过valid_*part检测时,将会执行if代码块的代码。

而valid_localpart主要是过滤如下的危险字符,避免多条指令的执行。

但上述代码的1651逻辑,当domain部分为空,即不输入时,将会自动加上本地主机的地址,并且直接返回1,表示合法。这个漏洞逻辑就造成了user过滤的跳过,导致了下面的调用链可以被利用:

首先是sender在parse.y YACC脚本中,被用于构建MBOX的command。

然后在smtpd.c中将会执行这个构建的mda_command:

从而造成了任意代码执行。当收件人为root时,该命令由root账户执行,所以最后命令执行获取的是root权限。

由于发件人的长度被限制为64字节,如果想要执行更长的命令,可以利用邮件的Body。由于mda_command执行时,标准输入将会输入邮件经过添加头部信息后的内容,我们可以直接调用sh读取输入,从而执行任意长度的代码。

但生成的邮件将会被添加上头部信息,导致执行过程错误。

由于头部信息最多13行,所以我们可以用一个for循环执行13次read命令,跳过这13行内容。为了避免写入的shell内容被跳过,可以在邮件内容前设置13行仅含有注释开始符号#的padding(类似于PWN shellcode写入时的0x90)。

漏洞环境搭建#

使用官网下载的install66.iso安装OpenBSD 6.6。

由于OpenSMTPD默认禁止外域地址向本地账户发送邮件。为了实现远程调用,需先编辑smtpd.conf配置文件,加入允许外域向本地用户发送邮件的配置,从而实现远程代码注入,否则只能做到本地提权。

在smtpd.conf中加入 match from any for domain “openbsd66.my.domain” action “local”。其中openbsd66.my.domain是本地域名(openbsd66是hostname,my.domain是安装时配置的默认的域名),表示从任何地址发送给本地的邮件,应用local规则。local规则为调用mbox机制,使用别名文件aliases进行邮件投递。从而打通漏洞的调用链。

写好配置文件后,需要使用rcctl start smtpd启动smtpd服务。

漏洞复现过程#

我写了一个基于pwntools remote交互功能的攻击脚本。

首先建立与靶机25端口的连接,发送SMTP HELO命令。在MAIL FROM的user部分写入执行sh和header跳过的shell命令,并且不写user部分。RCPT TO写入root账户,以便获取root权限(如果换用其他账户将会获得_smtpd账户权限)。最后使用DATA命令,写入邮件内容(13行Padding+shell命令)。这里shell命令是反弹shell。

发送完payload后,在本地开启监听服务器,等待连接。连接后进入交互模式。

执行该脚本,即可获得root shell。