网站地图    收藏   

主页 > 后端 > 网站安全 >

WordPress中timthumb.php远程文件存储漏洞分析 - 网站

来源:自学PHP网    时间:2015-04-17 14:46 作者: 阅读:

[导读] 编外:请参考本文:http://www.2cto.com/Article/201108/98870.html来源:http://xuser.org/read.php?18作者:xuser@fsafe今天在微博上看见的关于wordpress出现了漏洞,随即赶紧打开相关页面分析具体原因,发现是...

编外:请参考本文:http://www.2cto.com/Article/201108/98870.html

来源:http://xuser.org/read.php?18
作者:xuser@fsafe
今天在微博上看见的关于wordpress出现了漏洞,随即赶紧打开相关页面分析具体原因,发现是timthumb.php远程存储文件时候的验证上不足而产生的漏洞。大概分析过程如下:
该文件对提交的src变量提交并验证后存储到服务器上
 

$src = get_request ('src', '');


利用parse_url ($src)将src进行url分割,然后进行验证
 

  global $allowedSites;

  // work out file details
  $filename = 'external_' . md5 ($src);
  $local_filepath = DIRECTORY_CACHE . '/' . $filename;
  
  // only do this stuff the file doesn't already exist
  if (!file_exists ($local_filepath)) {

    if (strpos (strtolower ($src), 'http://') !== false || strpos (strtolower ($src), 'https://') !== false) {

      if (!validate_url ($src)) {
        display_error ('invalid url');
      }

      $url_info = parse_url ($src);

      if (count (explode ('.', $url_info['path'])) > 2) {
        display_error ('source filename invalid');
      }      

      if (($url_info['host'] == 'www.youtube.com' || $url_info['host'] == 'youtube.com') && preg_match ('/v=([^&]+)/i', $url_info['query'], $matches)) {
        $v = $matches[1];
        $src = 'http://img.youtube.com/vi/' . $v . '/0.jpg';
        $url_info['host'] = 'img.youtube.com';        //如果来源是youtube,则修改之前存储的host
      }
      
      $isAllowedSite = false;

      // check allowed sites (if required)
      if (ALLOW_EXTERNAL) {                //ALLOW_EXTERNAL默认为false

        $isAllowedSite = true;

      } else {

        foreach ($allowedSites as $site) {
          if (strpos (strtolower ($url_info['host']), $site) !== false)  //在$url_info['host'])查找是否存在$site
            $isAllowedSite = true;  //当为true就继续下一步的存储
          }
        }

      }


其中$allowedSites数组在文件头定义如下
 

$allowedSites = array (
  'flickr.com',
  'picasa.com',
  'img.youtube.com',
);


进过一系列的验证如果$isAllowedSite如果为真就开始存储这个文件到服务器上
 

      if ($isAllowedSite) {

        if (function_exists ('curl_init')) {

          global $fh;

          $fh = fopen ($local_filepath, 'w');
          $ch = curl_init ($src);

          curl_setopt ($ch, CURLOPT_TIMEOUT, CURL_TIMEOUT);
          curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0');
          curl_setopt ($ch, CURLOPT_URL, $src);
          curl_setopt ($ch, CURLOPT_RETURNTRANSFER, TRUE);
          curl_setopt ($ch, CURLOPT_HEADER, 0);
          curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
          curl_setopt ($ch, CURLOPT_FILE, $fh);
          curl_setopt ($ch, CURLOPT_WRITEFUNCTION, 'curl_write');

          // error so die
          if (curl_exec ($ch) === FALSE) {
            unlink ($local_filepath);
            touch ($local_filepath);
            display_error ('error reading file ' . $src . ' from remote host: ' . curl_error ($ch));
          }

          curl_close ($ch);
          fclose ($fh);
          
          // check it's actually an image
          $file_infos = getimagesize ($local_filepath);

          // no mime type or invalid mime type
          if (empty ($file_infos['mime']) || !preg_match ("/jpg|jpeg|gif|png/i", $file_infos['mime'])) {
            unlink ($local_filepath);
            touch ($local_filepath);
            display_error ('remote file not a valid image');
          }          

                } else {

          if (!$img = file_get_contents ($src)) {
            display_error ('remote file for ' . $src . ' can not be accessed. It is likely that the file permissions are restricted');
          }

          if (file_put_contents ($local_filepath, $img) == FALSE) {
            display_error ('error writing temporary file');
          }

        }

        if (!file_exists ($local_filepath)) {
          display_error ('local file for ' . $src . ' can not be created');
        }

        $src = $local_filepath;

      } else {

        display_error ('remote host "' . $url_info['host'] . '" not allowed');

      }


使用了strpos验证是否匹配列表中的条件应该是考虑到其分域名问题,不过也形成了一些安全隐患,例如picasa.com.yourdomain.com也是符合这个匹配条件的。关于存储文件的位置信息在如下代码中
 

  $filename = 'external_' . md5 ($src);
  $local_filepath = DIRECTORY_CACHE . '/' . $filename;


不过通过修改这个匹配规则或直接删除$isAllowedSite所有数组元素都可以临时解决该问题。

备注:发现一些timthumb.php版本中$isAllowedSite数组元素和存储文件方式不太一致,不过漏洞产生原因与此关系不是很大

自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习

京ICP备14009008号-1@版权所有www.zixuephp.com

网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com

添加评论