WordPress第三方主题文件漏洞分析

  国外博客最近公布了关于wordpress主题的一个0day,这些主题都使用了timthumb.php这个文件,该文件用于处理图片的显示效果等,原文地址可以参见:http://sebug.net/vuldb/ssvid-20811 。这里具体分析下漏洞的成因,其实在国外这篇文章也有分析,只是不是很清晰

  appdir

  PHP

  WordPress

  漏洞成因

  大家可以首先打开这个链接,版本控制,可以看到:

  r143 ,stronger website domain checks (don’t allow http://wordpress.com.hacker.com/)

  作者在这里标明了已经修复了这个漏洞,那么我们就对比下r143和r142两个版本的区别。

  对比分析这两个版本,发现结果如下:

  1.foreach ($allowedSites as $site) {

  2.    if (strpos (strtolower ($url_info['host']), $site) !== false) {

  3.        $isAllowedSite = true;

  4.}

  5.

  6.foreach ($allowedSites as $site) {

  7.    if (strpos (strtolower ($url_info['host'] . ‘/’), $site) !== false) {

  8.        $isAllowedSite = true;

  9.}

  对了一个’/',在匹配的时候限制了白名单域名只能在地址的最后面,这样就限制了可以在任意的域名前面加上白名单的域名,举个例子来说,我们假如有域名xyz.com,那么我们可以随便添加二、三级域名。先看看timthumb限制了哪些域名。

  1.// external domains that are allowed to be displayed on your website

  2.$allowedSites = array (

  3.        ‘flickr.com’,

  4.        ‘picasa.com’,

  5.        ‘blogger.com’,

  6.        ‘wordpress.com’,

  7.        ‘img.youtube.com’,

  8.        ‘upload.wikimedia.org’,

  9.);

  这样的话我们就可以添加blogger.com.xyz.com,成功绕过白名单的检测。看到这里我不禁想到我上次分析的百度贴吧flash过滤机制研究,也存在一定的问题,因此在匹配或者是搜索的时候需要特别注意。

  利用

  如果大家看了原文的留言,别人给出了利用方法(不过我没域名测试),这里我们还是对源码进行一下分析。

  首先是引入url的地方:

  1.// sort out image source

  2.$src = get_request (‘src’, ”);

  3.if ($src == ” || strlen ($src) <= 3) {

  4.    display_error (‘no image specified’);

  5.}

  get_request函数:

  1./**

  2. *

  3. * @param [HTML_REMOVED] $property

  4. * @param [HTML_REMOVED] $default

  5. * @return [HTML_REMOVED]

  6. */

  7.function get_request ($property, $default = 0) {

  8.    if (isset ($_GET[$property])) {

  9.        return $_GET[$property];

  10.    } else {

  11.        return $default;

  12.    }

  13.}

  然后是文件检查:

  1.// clean params before use

  2.$src = clean_source ($src);

  3.// get mime type of src

  4.$mime_type = mime_type ($src);

  5.// used for external websites only

  6.$external_data_string = ”;

  7.// generic file handle for reading and writing to files

  8.$fh = ”;

  9.// check to see if this image is in the cache already

  10.// if already cached then display the image and die

  11.check_cache ($mime_type);

  其中cleansource函数中调用checkexternal函数实现了写文件操作。

  1.**

  2. *

  3. * @global array $allowedSites

  4. * @param string $src

  5. * @return string

  6. */

  7.function check_external ($src) {

  8.        global $allowedSites;

  9.        // work out file details

  10.        $fileDetails = pathinfo ($src);

  11.        $filename = ‘external_’ . md5 ($src);  //注意这个地方是文件生成后的文件名

  12.        $local_filepath = DIRECTORY_CACHE . ‘/’ . $filename . ‘.’ . strtolower ($fileDetails['extension']);

  13.        // only do this stuff the file doesn’t already exist

  14.        if (!file_exists ($local_filepath)) {

  15.                if (strpos (strtolower ($src), ‘http://’) !== false || strpos (strtolower ($src), ‘https://’) !== false) {

  16.                        if (!validate_url ($src)) {

  17.                                display_error (‘invalid url’);

  18.                        }

  19.                        $url_info = parse_url ($src);

  20.                        // convert youtube video urls

  21.                        // need to tidy up the code

  22.                        if ($url_info['host'] == ‘www.youtube.com’ || $url_info['host'] == ‘youtube.com’) {

  23.                                parse_str ($url_info['query']);

  24.                                if (isset ($v)) {

  25.                                        $src = ‘http://img.youtube.com/vi/’ . $v . ‘/0.jpg’;

  26.                                        $url_info['host'] = ‘img.youtube.com’;

  27.                                }

  28.                        }

  29.                        // check allowed sites (if required)

  30.                        if (ALLOW_EXTERNAL) {

  31.                                $isAllowedSite = true;

  32.                        } else {

  33.                                $isAllowedSite = false;  //注意这个地方是重点

  34.                                foreach ($allowedSites as $site) {

  35.                                        if (strpos (strtolower ($url_info['host']), $site) !== false) {

  36.                                                $isAllowedSite = true;

  37.                                        }

  38.                                }

  39.                        }

  40.                        // if allowed  //判断正确了就直接写文件了。

  41.                        if ($isAllowedSite) {

  42.                                if (function_exists (‘curl_init’)) {

  43.                                        global $fh;

  44.                                        $fh = fopen ($local_filepath, ‘w’);

  45.                                        $ch = curl_init ($src);

  46.                                        curl_setopt ($ch, CURLOPT_TIMEOUT, CURL_TIMEOUT);

  47.                                        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′);

  48.                                        curl_setopt ($ch, CURLOPT_URL, $src);

  49.                                        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, TRUE);

  50.                                        curl_setopt ($ch, CURLOPT_HEADER, 0);

  51.                                        curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

  52.                                        curl_setopt ($ch, CURLOPT_FILE, $fh);

  53.                                        curl_setopt ($ch, CURLOPT_WRITEFUNCTION, ‘curl_write’);

  54.                                        // error so die

  55.                                        if (curl_exec ($ch) === FALSE) {

  56.                                                unlink ($local_filepath);

  57.                                                touch ($local_filepath);

  58.                                                display_error (‘error reading file ‘ . $src . ‘ from remote host: ‘ . curl_error ($ch));

  59.                                        }

  60.                                        curl_close ($ch);

  61.                                        fclose ($fh);

  62.                } else {

  63.                                        if (!$img = file_get_contents ($src)) {

  64.                                                display_error (‘remote file for ‘ . $src . ‘ can not be accessed. It is likely that the file’);

  65.                                        }

  66.                                        if (file_put_contents ($local_filepath, $img) == FALSE) {

  67.                                                display_error (‘error writing temporary file’);

  68.                                        }

  69.                                }

  70.                                if (!file_exists ($local_filepath)) {

  71.                                        display_error (‘local file for ‘ . $src . ‘ can not be created’);

  72.                                }

  73.                                $src = $local_filepath;

  74.                        } else {

  75.                                display_error (‘remote host “‘ . $url_info['host'] . ‘” not allowed’);

  76.                        }

  77.                }

  78.    } else {

  79.                $src = $local_filepath;

  80.        }

  81.    return $src;

  82.}

 

发表评论

邮箱地址不会被公开。 必填项已用*标注