{"id":2828,"date":"2011-08-02T09:30:02","date_gmt":"2011-08-02T13:30:02","guid":{"rendered":"http:\/\/teamtutorials.com\/?p=2828"},"modified":"2011-08-02T21:12:35","modified_gmt":"2011-08-03T01:12:35","slug":"fix-the-timthumb-php-wordpress-exploit","status":"publish","type":"post","link":"https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit","title":{"rendered":"Fix the timthumb.php WordPress exploit"},"content":{"rendered":"

There was a recent exploit found in a common file used to generate thumbnails. I found out about the exploit from Mark Maunder’s site<\/a>. If you have a server running several wordpress blogs, like us, here is a way to fix all the exploits.<\/p>\n

If you don’t want to copy and paste skip to the bottom of the post to download the fix.<\/strong><\/p>\n

First, upload a fixed version of the tim thumb file names timthumb-fix.php<\/p>\n

\r\n<?php\r\n\/**\r\n * TimThumb script created by Ben Gillbanks, originally created by Tim McDaniels and Darren Hoyt\r\n * http:\/\/code.google.com\/p\/timthumb\/\r\n * \r\n * GNU General Public License, version 2\r\n * http:\/\/www.gnu.org\/licenses\/old-licenses\/gpl-2.0.html\r\n *\r\n * Examples and documentation available on the project homepage\r\n * http:\/\/www.binarymoon.co.uk\/projects\/timthumb\/\r\n *\/\r\n\r\ndefine ('CACHE_SIZE', 1000);\t\t\t\t\/\/ number of files to store before clearing cache\r\ndefine ('CACHE_CLEAR', 20);\t\t\t\t\t\/\/ maximum number of files to delete on each cache clear\r\ndefine ('CACHE_USE', TRUE);\t\t\t\t\t\/\/ use the cache files? (mostly for testing)\r\ndefine ('CACHE_MAX_AGE', 864000);\t\t\t\/\/ time to cache in the browser\r\ndefine ('VERSION', '1.28');\t\t\t\t\t\/\/ version number (to force a cache refresh)\r\ndefine ('DIRECTORY_CACHE', '.\/cache');\t\t\/\/ cache directory\r\ndefine ('MAX_WIDTH', 1500);\t\t\t\t\t\/\/ maximum image width\r\ndefine ('MAX_HEIGHT', 1500);\t\t\t\t\/\/ maximum image height\r\ndefine ('ALLOW_EXTERNAL', FALSE);\t\t\t\/\/ allow external website (override security precaution - not advised!)\r\ndefine ('MEMORY_LIMIT', '30M');\t\t\t\t\/\/ set PHP memory limit\r\ndefine ('MAX_FILE_SIZE', 1500000);\t\t\t\/\/ file size limit to prevent possible DOS attacks (roughly 1.5 megabytes)\r\ndefine ('CURL_TIMEOUT', 10);\t\t\t\t\/\/ timeout duration. Tweak as you require (lower = better)\r\n\r\n\/\/ external domains that are allowed to be displayed on your website\r\n$allowedSites = array ();\r\n\r\n\/\/ STOP MODIFYING HERE!\r\n\/\/ --------------------\r\n\r\n\/\/ sort out image source\r\n$src = get_request ('src', '');\r\nif ($src == '' || strlen ($src) <= 3) {\r\n    display_error ('no image specified');\r\n}\r\n\r\n\/\/ clean params before use\r\n$src = clean_source ($src);\r\n\r\n\/\/ get mime type of src\r\n$mime_type = mime_type ($src);\r\n\r\n\/\/ used for external websites only\r\n$external_data_string = '';\r\n\r\n\/\/ generic file handle for reading and writing to files\r\n$fh = '';\r\n\r\n\/\/ check to see if this image is in the cache already\r\n\/\/ if already cached then display the image and die\r\ncheck_cache ($mime_type);\r\n\r\n\/\/ cache doesn't exist and then process everything\r\n\/\/ check to see if GD function exist\r\nif (!function_exists ('imagecreatetruecolor')) {\r\n    display_error ('GD Library Error: imagecreatetruecolor does not exist - please contact your webhost and ask them to install the GD library');\r\n}\r\n\r\nif (function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {\r\n\t$imageFilters = array (\r\n\t\t1 => array (IMG_FILTER_NEGATE, 0),\r\n\t\t2 => array (IMG_FILTER_GRAYSCALE, 0),\r\n\t\t3 => array (IMG_FILTER_BRIGHTNESS, 1),\r\n\t\t4 => array (IMG_FILTER_CONTRAST, 1),\r\n\t\t5 => array (IMG_FILTER_COLORIZE, 4),\r\n\t\t6 => array (IMG_FILTER_EDGEDETECT, 0),\r\n\t\t7 => array (IMG_FILTER_EMBOSS, 0),\r\n\t\t8 => array (IMG_FILTER_GAUSSIAN_BLUR, 0),\r\n\t\t9 => array (IMG_FILTER_SELECTIVE_BLUR, 0),\r\n\t\t10 => array (IMG_FILTER_MEAN_REMOVAL, 0),\r\n\t\t11 => array (IMG_FILTER_SMOOTH, 0),\r\n\t);\r\n}\r\n\r\n\/\/ get standard input properties\r\n$new_width =  (int) abs (get_request ('w', 0));\r\n$new_height = (int) abs (get_request ('h', 0));\r\n$zoom_crop = (int) get_request ('zc', 1);\r\n$quality = (int) abs (get_request ('q', 90));\r\n$align = get_request ('a', 'c');\r\n$filters = get_request ('f', '');\r\n$sharpen = (bool) get_request ('s', 0);\r\n\r\n\/\/ set default width and height if neither are set already\r\nif ($new_width == 0 && $new_height == 0) {\r\n    $new_width = 100;\r\n    $new_height = 100;\r\n}\r\n\r\n\/\/ ensure size limits can not be abused\r\n$new_width = min ($new_width, MAX_WIDTH);\r\n$new_height = min ($new_height, MAX_HEIGHT);\r\n\r\n\/\/ set memory limit to be able to have enough space to resize larger images\r\nini_set ('memory_limit', MEMORY_LIMIT);\r\n\r\nif (file_exists ($src)) {\r\n\r\n    \/\/ open the existing image\r\n    $image = open_image ($mime_type, $src);\r\n    if ($image === false) {\r\n        display_error ('Unable to open image : ' . $src);\r\n    }\r\n\r\n    \/\/ Get original width and height\r\n    $width = imagesx ($image);\r\n    $height = imagesy ($image);\r\n\t$origin_x = 0;\r\n\t$origin_y = 0;\r\n\r\n    \/\/ generate new w\/h if not provided\r\n    if ($new_width && !$new_height) {\r\n        $new_height = floor ($height * ($new_width \/ $width));\r\n    } else if ($new_height && !$new_width) {\r\n        $new_width = floor ($width * ($new_height \/ $height));\r\n    }\r\n\r\n\t\/\/ scale down and add borders\r\n\tif ($zoom_crop == 3) {\r\n\r\n\t\t$final_height = $height * ($new_width \/ $width);\r\n\r\n\t\tif ($final_height > $new_height) {\r\n\t\t\t$new_width = $width * ($new_height \/ $height);\r\n\t\t} else {\r\n\t\t\t$new_height = $final_height;\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t\/\/ create a new true color image\r\n\t$canvas = imagecreatetruecolor ($new_width, $new_height);\r\n\timagealphablending ($canvas, false);\r\n\r\n\t\/\/ Create a new transparent color for image\r\n\t$color = imagecolorallocatealpha ($canvas, 0, 0, 0, 127);\r\n\r\n\t\/\/ Completely fill the background of the new image with allocated color.\r\n\timagefill ($canvas, 0, 0, $color);\r\n\r\n\t\/\/ scale down and add borders\r\n\tif ($zoom_crop == 2) {\r\n\r\n\t\t$final_height = $height * ($new_width \/ $width);\r\n\t\t\r\n\t\tif ($final_height > $new_height) {\r\n\t\t\t\r\n\t\t\t$origin_x = $new_width \/ 2;\r\n\t\t\t$new_width = $width * ($new_height \/ $height);\r\n\t\t\t$origin_x = round ($origin_x - ($new_width \/ 2));\r\n\r\n\t\t} else {\r\n\r\n\t\t\t$origin_y = $new_height \/ 2;\r\n\t\t\t$new_height = $final_height;\r\n\t\t\t$origin_y = round ($origin_y - ($new_height \/ 2));\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t\/\/ Restore transparency blending\r\n\timagesavealpha ($canvas, true);\r\n\r\n\tif ($zoom_crop > 0) {\r\n\r\n\t\t$src_x = $src_y = 0;\r\n\t\t$src_w = $width;\r\n\t\t$src_h = $height;\r\n\r\n\t\t$cmp_x = $width \/ $new_width;\r\n\t\t$cmp_y = $height \/ $new_height;\r\n\r\n\t\t\/\/ calculate x or y coordinate and width or height of source\r\n\t\tif ($cmp_x > $cmp_y) {\r\n\r\n\t\t\t$src_w = round ($width \/ $cmp_x * $cmp_y);\r\n\t\t\t$src_x = round (($width - ($width \/ $cmp_x * $cmp_y)) \/ 2);\r\n\r\n\t\t} else if ($cmp_y > $cmp_x) {\r\n\r\n\t\t\t$src_h = round ($height \/ $cmp_y * $cmp_x);\r\n\t\t\t$src_y = round (($height - ($height \/ $cmp_y * $cmp_x)) \/ 2);\r\n\r\n\t\t}\r\n\r\n\t\t\/\/ positional cropping!\r\n\t\tif ($align) {\r\n\t\t\tif (strpos ($align, 't') !== false) {\r\n\t\t\t\t$src_y = 0;\r\n\t\t\t}\r\n\t\t\tif (strpos ($align, 'b') !== false) {\r\n\t\t\t\t$src_y = $height - $src_h;\r\n\t\t\t}\r\n\t\t\tif (strpos ($align, 'l') !== false) {\r\n\t\t\t\t$src_x = 0;\r\n\t\t\t}\r\n\t\t\tif (strpos ($align, 'r') !== false) {\r\n\t\t\t\t$src_x = $width - $src_w;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\timagecopyresampled ($canvas, $image, $origin_x, $origin_y, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h);\r\n\r\n    } else {\r\n\r\n        \/\/ copy and resize part of an image with resampling\r\n        imagecopyresampled ($canvas, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);\r\n\r\n    }\r\n\r\n    if ($filters != '' && function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {\r\n        \/\/ apply filters to image\r\n        $filterList = explode ('|', $filters);\r\n        foreach ($filterList as $fl) {\r\n\r\n            $filterSettings = explode (',', $fl);\r\n            if (isset ($imageFilters[$filterSettings[0]])) {\r\n\r\n                for ($i = 0; $i < 4; $i ++) {\r\n                    if (!isset ($filterSettings[$i])) {\r\n\t\t\t\t\t\t$filterSettings[$i] = null;\r\n                    } else {\r\n\t\t\t\t\t\t$filterSettings[$i] = (int) $filterSettings[$i];\r\n\t\t\t\t\t}\r\n                }\r\n\r\n                switch ($imageFilters[$filterSettings[0]][1]) {\r\n\r\n                    case 1:\r\n\r\n                        imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1]);\r\n                        break;\r\n\r\n                    case 2:\r\n\r\n                        imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2]);\r\n                        break;\r\n\r\n                    case 3:\r\n\r\n                        imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3]);\r\n                        break;\r\n\r\n                    case 4:\r\n\r\n                        imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3], $filterSettings[4]);\r\n                        break;\r\n\r\n                    default:\r\n\r\n                        imagefilter ($canvas, $imageFilters[$filterSettings[0]][0]);\r\n                        break;\r\n\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n\t\/\/ sharpen image\r\n\tif ($sharpen && function_exists ('imageconvolution')) {\r\n\r\n\t\t$sharpenMatrix = array (\r\n\t\t\tarray (-1,-1,-1),\r\n\t\t\tarray (-1,16,-1),\r\n\t\t\tarray (-1,-1,-1),\r\n\t\t);\r\n\r\n\t\t$divisor = 8;\r\n\t\t$offset = 0;\r\n\r\n\t\timageconvolution ($canvas, $sharpenMatrix, $divisor, $offset);\r\n\r\n\t}\r\n\r\n    \/\/ output image to browser based on mime type\r\n    show_image ($mime_type, $canvas);\r\n\r\n    \/\/ remove image from memory\r\n    imagedestroy ($canvas);\r\n\r\n\t\/\/ if not in cache then clear some space and generate a new file\r\n\tclean_cache ();\r\n\r\n\tdie ();\r\n\r\n} else {\r\n\r\n    if (strlen ($src)) {\r\n        display_error ('image ' . $src . ' not found');\r\n    } else {\r\n        display_error ('no source specified');\r\n    }\r\n\r\n}\r\n\r\n\r\n\/**\r\n *\r\n * @global <type> $quality\r\n * @param <type> $mime_type\r\n * @param <type> $image_resized \r\n *\/\r\nfunction show_image ($mime_type, $image_resized) {\r\n\r\n    global $quality;\r\n\r\n    $cache_file = get_cache_file ($mime_type);\r\n\r\n\tswitch ($mime_type) {\r\n\t\tcase 'jpg':\r\n\t\t\timagejpeg ($image_resized, $cache_file, $quality);\r\n\t\t\tbreak;\r\n\r\n\t\tdefault:\r\n\t\tcase 'png':\r\n\t\t\timagepng ($image_resized, $cache_file, floor ($quality * 0.09));\r\n\t\t\tbreak;\r\n\r\n\t}\r\n\r\n\tshow_cache_file ($mime_type);\r\n\r\n}\r\n\r\n\r\n\/**\r\n *\r\n * @param <type> $property\r\n * @param <type> $default\r\n * @return <type> \r\n *\/\r\nfunction get_request ($property, $default = 0) {\r\n\r\n    if (isset ($_GET[$property])) {\r\n        return $_GET[$property];\r\n    } else {\r\n        return $default;\r\n    }\r\n\r\n}\r\n\r\n\r\n\/**\r\n *\r\n * @param <type> $mime_type\r\n * @param <type> $src\r\n * @return <type>\r\n *\/\r\nfunction open_image ($mime_type, $src) {\r\n\r\n\tswitch ($mime_type) {\r\n\t\tcase 'jpg':\r\n\t\t\t$image = imagecreatefromjpeg ($src);\r\n\t\t\tbreak;\r\n\r\n\t\tcase 'png':\r\n\t\t\t$image = imagecreatefrompng ($src);\r\n\t\t\tbreak;\r\n\r\n\t\tcase 'gif':\r\n\t\t\t$image = imagecreatefromgif ($src);\r\n\t\t\tbreak;\r\n\t}\r\n\r\n    return $image;\r\n\r\n}\r\n\r\n\/**\r\n * clean out old files from the cache\r\n * you can change the number of files to store and to delete per loop in the defines at the top of the code\r\n *\r\n * @return <type>\r\n *\/\r\nfunction clean_cache () {\r\n\r\n\t\/\/ add an escape\r\n\t\/\/ Reduces the amount of cache clearing to save some processor speed\r\n\tif (rand (1, 50) > 10) {\r\n\t\treturn true;\r\n\t}\r\n\r\n\tflush ();\r\n\r\n    $files = glob (DIRECTORY_CACHE . '\/*', GLOB_BRACE);\r\n\r\n\tif (count ($files) > CACHE_SIZE) {\r\n\t\t\r\n        $yesterday = time () - (24 * 60 * 60);\r\n\r\n        usort ($files, 'filemtime_compare');\r\n        $i = 0;\r\n\r\n\t\tforeach ($files as $file) {\r\n\r\n\t\t\t$i ++;\r\n\r\n\t\t\tif ($i >= CACHE_CLEAR) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (@filemtime ($file) > $yesterday) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (file_exists ($file)) {\r\n\t\t\t\tunlink ($file);\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n    }\r\n\r\n}\r\n\r\n\r\n\/**\r\n * compare the file time of two files\r\n *\r\n * @param <type> $a\r\n * @param <type> $b\r\n * @return <type>\r\n *\/\r\nfunction filemtime_compare ($a, $b) {\r\n\r\n\t$break = explode ('\/', $_SERVER['SCRIPT_FILENAME']);\r\n\t$filename = $break[count ($break) - 1];\r\n\t$filepath = str_replace ($filename, '', $_SERVER['SCRIPT_FILENAME']);\r\n\r\n\t$file_a = realpath ($filepath . $a);\r\n\t$file_b = realpath ($filepath . $b);\r\n\r\n    return filemtime ($file_a) - filemtime ($file_b);\r\n\r\n}\r\n\r\n\r\n\/**\r\n * determine the file mime type\r\n *\r\n * @param <type> $file\r\n * @return <type>\r\n *\/\r\nfunction mime_type ($file) {\r\n\r\n\t$file_infos = getimagesize ($file);\r\n\t$mime_type = $file_infos['mime'];\r\n\r\n\t\/\/ no mime type\r\n\tif (empty ($mime_type)) {\r\n\t\tdisplay_error ('no mime type specified');\r\n\t}\r\n\r\n    \/\/ use mime_type to determine mime type\r\n    if (!preg_match ("\/jpg|jpeg|gif|png\/i", $mime_type)) {\r\n\t\tdisplay_error ('Invalid src mime type: ' . $mime_type);\r\n    }\r\n\r\n\t$mime_type = strtolower ($mime_type);\r\n\t$mime_type = str_replace ('image\/', '', $mime_type);\r\n\r\n\tif ($mime_type == 'jpeg') {\r\n\t\t$mime_type = 'jpg';\r\n\t}\r\n\r\n    return $mime_type;\r\n\r\n}\r\n\r\n\r\n\/**\r\n *\r\n * @param <type> $mime_type\r\n *\/\r\nfunction check_cache ($mime_type) {\r\n\r\n\tif (CACHE_USE) {\r\n\r\n\t\tif (!show_cache_file ($mime_type)) {\r\n\t\t\t\/\/ make sure cache dir exists\r\n\t\t\tif (!file_exists (DIRECTORY_CACHE)) {\r\n\t\t\t\t\/\/ give 777 permissions so that developer can overwrite\r\n\t\t\t\t\/\/ files created by web server user\r\n\t\t\t\tmkdir (DIRECTORY_CACHE);\r\n\t\t\t\tchmod (DIRECTORY_CACHE, 0777);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t}\r\n\r\n}\r\n\r\n\r\n\/**\r\n *\r\n * @param <type> $mime_type\r\n * @return <type> \r\n *\/\r\nfunction show_cache_file ($mime_type) {\r\n\r\n\t\/\/ use browser cache if available to speed up page load\r\n\tif (!empty ($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {\r\n\t\tif (strtotime ($_SERVER['HTTP_IF_MODIFIED_SINCE']) < strtotime ('now')) {\r\n\t\t\theader ('HTTP\/1.1 304 Not Modified');\r\n\t\t\tdie ();\r\n\t\t}\r\n\t}\r\n\r\n\t$cache_file = get_cache_file ($mime_type);\r\n\r\n\tif (file_exists ($cache_file)) {\r\n\r\n\t\t\/\/ change the modified headers\r\n\t\t$gmdate_expires = gmdate ('D, d M Y H:i:s', strtotime ('now +10 days')) . ' GMT';\r\n\t\t$gmdate_modified = gmdate ('D, d M Y H:i:s') . ' GMT';\r\n\r\n\t\t\/\/ send content headers then display image\r\n\t\theader ('Content-Type: ' . $mime_type);\r\n\t\theader ('Accept-Ranges: bytes');\r\n\t\theader ('Last-Modified: ' . $gmdate_modified);\r\n\t\theader ('Content-Length: ' . filesize ($cache_file));\r\n\t\theader ('Cache-Control: max-age=' . CACHE_MAX_AGE . ', must-revalidate');\r\n\t\theader ('Expires: ' . $gmdate_expires);\r\n\r\n\t\tif (!@readfile ($cache_file)) {\r\n\t\t\t$content = file_get_contents ($cache_file);\r\n\t\t\tif ($content != FALSE) {\r\n\t\t\t\techo $content;\r\n\t\t\t} else {\r\n\t\t\t\tdisplay_error ('cache file could not be loaded');\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tdie ();\r\n\r\n    }\r\n\r\n\treturn FALSE;\r\n\r\n}\r\n\r\n\r\n\/**\r\n *\r\n * @staticvar string $cache_file\r\n * @param <type> $mime_type\r\n * @return string\r\n *\/\r\nfunction get_cache_file ($mime_type) {\r\n\r\n    static $cache_file;\r\n\tglobal $src;\r\n\r\n\t$file_type = '.png';\r\n\r\n\tif ($mime_type == 'jpg') {\r\n\t\t$file_type = '.jpg';\r\n    }\r\n\r\n    if (!$cache_file) {\r\n\t\t\/\/ filemtime is used to make sure updated files get recached\r\n        $cache_file = DIRECTORY_CACHE . '\/' . md5 ($_SERVER ['QUERY_STRING'] . VERSION . filemtime ($src)) . $file_type;\r\n    }\r\n\r\n    return $cache_file;\r\n\r\n}\r\n\r\n\r\n\/**\r\n *\r\n * @param <type> $url\r\n * @return <type> \r\n *\/\r\nfunction validate_url ($url) {\r\n\t$pattern = "\/\\b(?:(?:https?):\\\/\\\/|www\\.)[-a-z0-9+&@#\\\/%?=~_|!:,.;]*[-a-z0-9+&@#\\\/%=~_|]\/i";\r\n\treturn preg_match ($pattern, $url);\r\n}\r\n\r\n\r\n\/**\r\n *\r\n * @global array $allowedSites\r\n * @param string $src\r\n * @return string\r\n *\/\r\nfunction check_external ($src) {\r\n\r\n\tglobal $allowedSites;\r\n\r\n\t\/\/ work out file details\r\n\t$fileDetails = pathinfo ($src);\r\n\t$filename = 'external_' . md5 ($src);\r\n\t$local_filepath = DIRECTORY_CACHE . '\/' . $filename . '.' . strtolower ($fileDetails['extension']);\r\n\r\n\t\/\/ only do this stuff the file doesn't already exist\r\n\tif (!file_exists ($local_filepath)) {\r\n\r\n\t\tif (strpos (strtolower ($src), 'http:\/\/') !== false || strpos (strtolower ($src), 'https:\/\/') !== false) {\r\n\r\n\t\t\tif (!validate_url ($src)) {\r\n\t\t\t\tdisplay_error ('invalid url');\r\n\t\t\t}\r\n\r\n\t\t\t$url_info = parse_url ($src);\r\n\r\n\t\t\t\/\/ convert youtube video urls\r\n\t\t\t\/\/ need to tidy up the code\r\n\r\n\t\t\tif ($url_info['host'] == 'www.youtube.com' || $url_info['host'] == 'youtube.com') {\r\n\t\t\t\tparse_str ($url_info['query']);\r\n\r\n\t\t\t\tif (isset ($v)) {\r\n\t\t\t\t\t$src = 'http:\/\/img.youtube.com\/vi\/' . $v . '\/0.jpg';\r\n\t\t\t\t\t$url_info['host'] = 'img.youtube.com';\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t\/\/ check allowed sites (if required)\r\n\t\t\tif (ALLOW_EXTERNAL) {\r\n\r\n\t\t\t\t$isAllowedSite = true;\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t$isAllowedSite = false;\r\n\t\t\t\tforeach ($allowedSites as $site) {\r\n\t\t\t\t\tif (strpos (strtolower ($url_info['host']), $site) !== false) {\r\n\t\t\t\t\t\t$isAllowedSite = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\t\/\/ if allowed\r\n\t\t\tif ($isAllowedSite) {\r\n\r\n\t\t\t\tif (function_exists ('curl_init')) {\r\n\r\n\t\t\t\t\tglobal $fh;\r\n\r\n\t\t\t\t\t$fh = fopen ($local_filepath, 'w');\r\n\t\t\t\t\t$ch = curl_init ($src);\r\n\r\n\t\t\t\t\tcurl_setopt ($ch, CURLOPT_TIMEOUT, CURL_TIMEOUT);\r\n\t\t\t\t\tcurl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla\/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko\/20041107 Firefox\/1.0');\r\n\t\t\t\t\tcurl_setopt ($ch, CURLOPT_URL, $src);\r\n\t\t\t\t\tcurl_setopt ($ch, CURLOPT_RETURNTRANSFER, TRUE);\r\n\t\t\t\t\tcurl_setopt ($ch, CURLOPT_HEADER, 0);\r\n\t\t\t\t\tcurl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, FALSE);\r\n\t\t\t\t\tcurl_setopt ($ch, CURLOPT_FILE, $fh);\r\n\t\t\t\t\tcurl_setopt ($ch, CURLOPT_WRITEFUNCTION, 'curl_write');\r\n\r\n\t\t\t\t\t\/\/ error so die\r\n\t\t\t\t\tif (curl_exec ($ch) === FALSE) {\r\n\t\t\t\t\t\tunlink ($local_filepath);\r\n\t\t\t\t\t\ttouch ($local_filepath);\r\n\t\t\t\t\t\tdisplay_error ('error reading file ' . $src . ' from remote host: ' . curl_error ($ch));\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tcurl_close ($ch);\r\n\t\t\t\t\tfclose ($fh);\r\n\r\n                } else {\r\n\r\n\t\t\t\t\tif (!$img = file_get_contents ($src)) {\r\n\t\t\t\t\t\tdisplay_error ('remote file for ' . $src . ' can not be accessed. It is likely that the file permissions are restricted');\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (file_put_contents ($local_filepath, $img) == FALSE) {\r\n\t\t\t\t\t\tdisplay_error ('error writing temporary file');\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (!file_exists ($local_filepath)) {\r\n\t\t\t\t\tdisplay_error ('local file for ' . $src . ' can not be created');\r\n\t\t\t\t}\r\n\r\n\t\t\t\t$src = $local_filepath;\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tdisplay_error ('remote host "' . $url_info['host'] . '" not allowed');\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n    } else {\r\n\r\n\t\t$src = $local_filepath;\r\n\r\n\t}\r\n\r\n    return $src;\r\n\r\n}\r\n\r\n\r\n\/**\r\n * callback for curl command to receive external images\r\n * limit the amount of data downloaded from external servers\r\n * \r\n * @global <type> $data_string\r\n * @param <type> $handle\r\n * @param <type> $data\r\n * @return <type>\r\n *\/\r\nfunction curl_write ($handle, $data) {\r\n\r\n\tglobal $external_data_string, $fh;\r\n\r\n\tfwrite ($fh, $data);\r\n\t$external_data_string .= $data;\r\n\r\n\tif (strlen ($external_data_string) > MAX_FILE_SIZE) {\r\n\t\treturn 0;\r\n\t} else {\r\n\t\treturn strlen ($data);\r\n\t}\r\n\r\n}\r\n\r\n\r\n\/**\r\n * tidy up the image source url\r\n *\r\n * @param <type> $src\r\n * @return string\r\n *\/\r\nfunction clean_source ($src) {\r\n\r\n\t$host = str_replace ('www.', '', $_SERVER['HTTP_HOST']);\r\n\t$regex = "\/^(http(s|):\\\/\\\/)(www\\.|)" . $host . "\\\/\/i";\r\n\r\n\t$src = preg_replace ($regex, '', $src);\r\n\t$src = strip_tags ($src);\r\n    $src = check_external ($src);\r\n\r\n    \/\/ remove slash from start of string\r\n    if (strpos ($src, '\/') === 0) {\r\n        $src = substr ($src, -(strlen ($src) - 1));\r\n    }\r\n\r\n    \/\/ don't allow users the ability to use '..\/'\r\n    \/\/ in order to gain access to files below document root\r\n    $src = preg_replace ("\/\\.\\.+\\\/\/", "", $src);\r\n\r\n    \/\/ get path to image on file system\r\n    $src = get_document_root ($src) . '\/' . $src;\r\n\r\n\tif (!is_file ($src)) {\r\n\t\tdisplay_error ('source is not a valid file');\r\n\t}\r\n\r\n\tif (filesize ($src) > MAX_FILE_SIZE) {\r\n\t\tdisplay_error ('source file is too big (filesize > MAX_FILE_SIZE)');\r\n\t}\r\n\r\n\tif (filesize ($src) <= 0) {\r\n\t\tdisplay_error ('source file <= 0 bytes. Possible external file download error (file is too large)');\r\n\t}\r\n\t\r\n    return realpath ($src);\r\n\r\n}\r\n\r\n\r\n\/**\r\n *\r\n * @param <type> $src\r\n * @return string\r\n *\/\r\nfunction get_document_root ($src) {\r\n\r\n    \/\/ check for unix servers\r\n    if (file_exists ($_SERVER['DOCUMENT_ROOT'] . '\/' . $src)) {\r\n        return $_SERVER['DOCUMENT_ROOT'];\r\n    }\r\n\r\n    \/\/ check from script filename (to get all directories to timthumb location)\r\n    $parts = array_diff (explode ('\/', $_SERVER['SCRIPT_FILENAME']), explode ('\/', $_SERVER['DOCUMENT_ROOT']));\r\n\r\n\t$path = '.\/';\r\n\t\r\n\tforeach ($parts as $part) {\r\n\t\tif (file_exists ($path . '\/' . $src)) {\r\n\t\t\treturn realpath ($path);\r\n\t\t}\r\n\t\t$path .= '..\/';\r\n\t}\r\n\r\n    \/\/ special check for microsoft servers\r\n    if (!isset ($_SERVER['DOCUMENT_ROOT'])) {\r\n        $path = str_replace ("\/", "\\\\", $_SERVER['ORIG_PATH_INFO']);\r\n        $path = str_replace ($path, '', $_SERVER['SCRIPT_FILENAME']);\r\n\r\n        if (file_exists ($path . '\/' . $src)) {\r\n            return realpath ($path);\r\n        }\r\n    }\r\n\r\n    display_error ('file not found');\r\n\r\n}\r\n\r\n\r\n\/**\r\n * generic error message\r\n *\r\n * @param <type> $errorString\r\n *\/\r\nfunction display_error ($errorString = '') {\r\n\r\n    header ('HTTP\/1.1 400 Bad Request');\r\n\techo '<pre>' . htmlentities ($errorString);\r\n\techo '<br \/>Query String : ' . htmlentities ($_SERVER['QUERY_STRING']);\r\n\techo '<br \/>TimThumb version : ' . VERSION . '<\/pre>';\r\n    die ();\r\n\r\n}\r\n<\/pre>\n

Then upload our shell script as fix_timthumb.sh:<\/p>\n

\r\n#!\/bin\/bash\r\nfind \/home\/ -name 'timthumb.php' -type f -printf '%h\\n' | while read line\r\ndo\r\n#Remove the old thumb\r\nrm -rf $line\/timthumb.php\r\n\r\n#Copy fixed thumb\r\ncp timthumb-fix.php $line\/timthumb.php\r\n\r\necho $line " done";\r\ndone\r\n<\/pre>\n

The all you have to do is execute this command:<\/p>\n

\r\nsh -x fix_timthumb.sh\r\n<\/pre>\n

The script will find any timthumb.php file and replace it with your fixed file. You will probably need root access to do this.<\/p>\n

[tweet2download file=”timthum_fix.zip” tweet=”Replace all timthumb.php files on your server http:\/\/su.pr\/1Libna” follow=”@teamtutorials” \/]<\/p>\n","protected":false},"excerpt":{"rendered":"

There was a recent exploit found in a common file used to generate thumbnails. I found out about the exploit from Mark Maunder’s site. If you have a server running several wordpress blogs, like us, here is a way to fix all the exploits. If you don’t want to copy and paste skip to the … Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":2836,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[17,23],"tags":[136,139,140,138,137,108],"yoast_head":"\nFix the timthumb.php WordPress exploit<\/title>\n<meta name=\"description\" content=\"There was a recent exploit found in a common file used to generate thumbnails. I found out about the exploit from Mark Maunder's site. If you have a\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Johnathan Ward\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"https:\/\/teamtutorials.com\/#website\",\"url\":\"https:\/\/teamtutorials.com\/\",\"name\":\"Team Tutorials\",\"description\":\"Learn something new today\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/teamtutorials.com\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit#primaryimage\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/teamtutorials.com\/wp-content\/uploads\/2011\/08\/timthumb.jpg\",\"contentUrl\":\"https:\/\/teamtutorials.com\/wp-content\/uploads\/2011\/08\/timthumb.jpg\",\"width\":\"480\",\"height\":\"480\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit#webpage\",\"url\":\"https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit\",\"name\":\"Fix the timthumb.php WordPress exploit\",\"isPartOf\":{\"@id\":\"https:\/\/teamtutorials.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit#primaryimage\"},\"datePublished\":\"2011-08-02T13:30:02+00:00\",\"dateModified\":\"2011-08-03T01:12:35+00:00\",\"author\":{\"@id\":\"https:\/\/teamtutorials.com\/#\/schema\/person\/3abea1fc71644afe035403357450b9d9\"},\"description\":\"There was a recent exploit found in a common file used to generate thumbnails. I found out about the exploit from Mark Maunder's site. If you have a\",\"breadcrumb\":{\"@id\":\"https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/teamtutorials.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Fix the timthumb.php WordPress exploit\"}]},{\"@type\":\"Person\",\"@id\":\"https:\/\/teamtutorials.com\/#\/schema\/person\/3abea1fc71644afe035403357450b9d9\",\"name\":\"Johnathan Ward\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/teamtutorials.com\/#personlogo\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/93d667fe5dc6df5c722e0df5eac14d40?s=96&d=mm&r=r\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/93d667fe5dc6df5c722e0df5eac14d40?s=96&d=mm&r=r\",\"caption\":\"Johnathan Ward\"},\"description\":\"Johnathan Ward is an experienced developer and consultant that writes tutorials to help other developers. In his day job, he is an IBM Watson Consultant with several years of experience deploying and customizing Watson Explorer solutions.\",\"sameAs\":[\"http:\/\/johnathanward.com\",\"https:\/\/twitter.com\/spyderman4g63\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Fix the timthumb.php WordPress exploit","description":"There was a recent exploit found in a common file used to generate thumbnails. I found out about the exploit from Mark Maunder's site. If you have a","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit","twitter_misc":{"Written by":"Johnathan Ward","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebSite","@id":"https:\/\/teamtutorials.com\/#website","url":"https:\/\/teamtutorials.com\/","name":"Team Tutorials","description":"Learn something new today","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/teamtutorials.com\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"ImageObject","@id":"https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit#primaryimage","inLanguage":"en-US","url":"https:\/\/teamtutorials.com\/wp-content\/uploads\/2011\/08\/timthumb.jpg","contentUrl":"https:\/\/teamtutorials.com\/wp-content\/uploads\/2011\/08\/timthumb.jpg","width":"480","height":"480"},{"@type":"WebPage","@id":"https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit#webpage","url":"https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit","name":"Fix the timthumb.php WordPress exploit","isPartOf":{"@id":"https:\/\/teamtutorials.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit#primaryimage"},"datePublished":"2011-08-02T13:30:02+00:00","dateModified":"2011-08-03T01:12:35+00:00","author":{"@id":"https:\/\/teamtutorials.com\/#\/schema\/person\/3abea1fc71644afe035403357450b9d9"},"description":"There was a recent exploit found in a common file used to generate thumbnails. I found out about the exploit from Mark Maunder's site. If you have a","breadcrumb":{"@id":"https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/teamtutorials.com\/web-development-tutorials\/fix-the-timthumb-php-wordpress-exploit#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/teamtutorials.com\/"},{"@type":"ListItem","position":2,"name":"Fix the timthumb.php WordPress exploit"}]},{"@type":"Person","@id":"https:\/\/teamtutorials.com\/#\/schema\/person\/3abea1fc71644afe035403357450b9d9","name":"Johnathan Ward","image":{"@type":"ImageObject","@id":"https:\/\/teamtutorials.com\/#personlogo","inLanguage":"en-US","url":"https:\/\/secure.gravatar.com\/avatar\/93d667fe5dc6df5c722e0df5eac14d40?s=96&d=mm&r=r","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/93d667fe5dc6df5c722e0df5eac14d40?s=96&d=mm&r=r","caption":"Johnathan Ward"},"description":"Johnathan Ward is an experienced developer and consultant that writes tutorials to help other developers. In his day job, he is an IBM Watson Consultant with several years of experience deploying and customizing Watson Explorer solutions.","sameAs":["http:\/\/johnathanward.com","https:\/\/twitter.com\/spyderman4g63"]}]}},"_links":{"self":[{"href":"https:\/\/teamtutorials.com\/wp-json\/wp\/v2\/posts\/2828"}],"collection":[{"href":"https:\/\/teamtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/teamtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/teamtutorials.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/teamtutorials.com\/wp-json\/wp\/v2\/comments?post=2828"}],"version-history":[{"count":0,"href":"https:\/\/teamtutorials.com\/wp-json\/wp\/v2\/posts\/2828\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/teamtutorials.com\/wp-json\/wp\/v2\/media\/2836"}],"wp:attachment":[{"href":"https:\/\/teamtutorials.com\/wp-json\/wp\/v2\/media?parent=2828"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/teamtutorials.com\/wp-json\/wp\/v2\/categories?post=2828"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/teamtutorials.com\/wp-json\/wp\/v2\/tags?post=2828"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}