Timthumb Vulnerability Scanner - Version 1.5

Version Description

  • Added a daily automatic scan
  • Added alerts across the admin section when vulnerable or outdated files are found
  • Fixed issue with updating timthumb src file
Download this release

Release Info

Developer peterebutler
Plugin Icon wp plugin Timthumb Vulnerability Scanner
Version 1.5
Comparing to
See all releases

Code changes from version 1.43 to 1.5

cg-tvs-admin-panel-display.php CHANGED
@@ -1,7 +1,38 @@
1
  <div class="wrap">
2
  <h2>Timthumb Scanner</h2>
3
- <div style="width:65%;min-width:500px;float:left">
4
- <div class="postbox metabox-holder" >
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  <h3 class="hndle">1. Scan</h3>
6
  <form action="" method="post">
7
  <input type="hidden" name="cg-tvs-action" value="scan">
@@ -79,6 +110,11 @@
79
  <?php endif; ?>
80
 
81
  </div>
 
 
 
 
 
82
  <div style="float:right;width:33%;">
83
  <div class="postbox metabox-holder" style="padding-top:0px">
84
  <h3 class="hndle" style="text-align:center"><a href="http://codegarage.com/"><img src="<?php echo WP_PLUGIN_URL; ?>/<?php echo basename( dirname( __FILE__ ) ); ?>/locker_logo.png"></a></h3>
@@ -101,8 +137,6 @@
101
  font-size:14px;
102
  width:90%;
103
  margin-bottom:10px; }
104
- /* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
105
- We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
106
  </style>
107
  <div id="mc_embed_signup">
108
  <form action="http://codegarage.us1.list-manage1.com/subscribe/post?u=18eaf7659266bae84144eef88&amp;id=0029c09237" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank">
1
  <div class="wrap">
2
  <h2>Timthumb Scanner</h2>
3
+ <ul class="subsubsub">
4
+ <li><a href="tools.php?page=cg-timthumb-scanner" <?php if($_GET['tab'] != 'options'): ?>class="current"<?php endif; ?>>Scan for Issues</a> | </li>
5
+ <li><a href="tools.php?page=cg-timthumb-scanner&tab=options" <?php if($_GET['tab'] == 'options'): ?>class="current"<?php endif; ?>>Options</a></li>
6
+ </ul>
7
+ <?php
8
+ switch($_GET['tab']){
9
+ case 'options':
10
+ ?>
11
+ <div style="width:65%;min-width:500px;float:left;clear:both;">
12
+ <div class="postbox metabox-holder">
13
+ <h3>Options</h3>
14
+ <form action="" method="post">
15
+ <input type="hidden" name="cg-tvs-action" value="update-options">
16
+ <?php wp_nonce_field( 'update_tvs_options'); ?>
17
+ <table class="form-table">
18
+ <tr>
19
+ <th><label for="scan-daily">Automatically run this scan daily</label></th>
20
+ <td><input id="scan-daily" name="scan-daily" type="checkbox" <?php if($this->scan_daily):?> checked="checked"<?php endif; ?>></td>
21
+ </tr>
22
+ <tr>
23
+ <th><input type="submit" class="button-primary"></th>
24
+ </tr>
25
+ </table>
26
+ </form>
27
+ </div>
28
+ </div>
29
+ <?php
30
+ break;
31
+ case 'scan':
32
+ default:
33
+ ?>
34
+ <div style="width:65%;min-width:500px;float:left;clear:both;">
35
+ <div class="postbox metabox-holder">
36
  <h3 class="hndle">1. Scan</h3>
37
  <form action="" method="post">
38
  <input type="hidden" name="cg-tvs-action" value="scan">
110
  <?php endif; ?>
111
 
112
  </div>
113
+ <?php
114
+ break;
115
+ } ?>
116
+
117
+
118
  <div style="float:right;width:33%;">
119
  <div class="postbox metabox-holder" style="padding-top:0px">
120
  <h3 class="hndle" style="text-align:center"><a href="http://codegarage.com/"><img src="<?php echo WP_PLUGIN_URL; ?>/<?php echo basename( dirname( __FILE__ ) ); ?>/locker_logo.png"></a></h3>
137
  font-size:14px;
138
  width:90%;
139
  margin-bottom:10px; }
 
 
140
  </style>
141
  <div id="mc_embed_signup">
142
  <form action="http://codegarage.us1.list-manage1.com/subscribe/post?u=18eaf7659266bae84144eef88&amp;id=0029c09237" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank">
cg-tvs-timthumb-latest.txt CHANGED
@@ -9,45 +9,54 @@
9
  *
10
  * Examples and documentation available on the project homepage
11
  * http://www.binarymoon.co.uk/projects/timthumb/
 
 
12
  */
13
 
14
  /*
15
- -----TimThumb CONFIGURATION-----
16
- You can either edit the configuration variables manually here, or you can
17
- create a file called timthumb-config.php and define variables you want
18
- to customize in there. It will automatically be loaded by timthumb.
19
- This will save you having to re-edit these variables everytime you download
20
- a new version of timthumb.
21
-
22
  */
23
- define ('VERSION', '2.8.2'); // Version of this script
24
  //Load a config file if it exists. Otherwise, use the values below
25
  if( file_exists(dirname(__FILE__) . '/timthumb-config.php')) require_once('timthumb-config.php');
26
- if(! defined('DEBUG_ON') ) define ('DEBUG_ON', false); // Enable debug logging to web server error log (STDERR)
27
- if(! defined('DEBUG_LEVEL') ) define ('DEBUG_LEVEL', 1); // Debug level 1 is less noisy and 3 is the most noisy
28
- if(! defined('MEMORY_LIMIT') ) define ('MEMORY_LIMIT', '30M'); // Set PHP memory limit
29
- if(! defined('BLOCK_EXTERNAL_LEECHERS') ) define ('BLOCK_EXTERNAL_LEECHERS', false); // If the image or webshot is being loaded on an external site, display a red "No Hotlinking" gif.
30
 
31
  //Image fetching and caching
32
- if(! defined('ALLOW_EXTERNAL') ) define ('ALLOW_EXTERNAL', TRUE); // Allow image fetching from external websites. Will check against ALLOWED_SITES if ALLOW_ALL_EXTERNAL_SITES is false
33
- if(! defined('ALLOW_ALL_EXTERNAL_SITES') ) define ('ALLOW_ALL_EXTERNAL_SITES', false); // Less secure.
34
- if(! defined('FILE_CACHE_ENABLED') ) define ('FILE_CACHE_ENABLED', TRUE); // Should we store resized/modified images on disk to speed things up?
35
  if(! defined('FILE_CACHE_TIME_BETWEEN_CLEANS')) define ('FILE_CACHE_TIME_BETWEEN_CLEANS', 86400); // How often the cache is cleaned
36
- if(! defined('FILE_CACHE_MAX_FILE_AGE') ) define ('FILE_CACHE_MAX_FILE_AGE', 86400); // How old does a file have to be to be deleted from the cache
37
- if(! defined('FILE_CACHE_SUFFIX') ) define ('FILE_CACHE_SUFFIX', '.timthumb.txt'); // What to put at the end of all files in the cache directory so we can identify them
38
- if(! defined('FILE_CACHE_DIRECTORY') ) define ('FILE_CACHE_DIRECTORY', './cache'); // Directory where images are cached. Left blank it will use the system temporary directory (which is better for security)
39
- if(! defined('MAX_FILE_SIZE') ) define ('MAX_FILE_SIZE', 10485760); // 10 Megs is 10485760. This is the max internal or external file size that we'll process.
40
- if(! defined('CURL_TIMEOUT') ) define ('CURL_TIMEOUT', 20); // Timeout duration for Curl. This only applies if you have Curl installed and aren't using PHP's default URL fetching mechanism.
41
- if(! defined('WAIT_BETWEEN_FETCH_ERRORS') ) define ('WAIT_BETWEEN_FETCH_ERRORS', 3600); //Time to wait between errors fetching remote file
 
 
 
42
  //Browser caching
43
- if(! defined('BROWSER_CACHE_MAX_AGE') ) define ('BROWSER_CACHE_MAX_AGE', 864000); // Time to cache in the browser
44
- if(! defined('BROWSER_CACHE_DISABLE') ) define ('BROWSER_CACHE_DISABLE', false); // Use for testing if you want to disable all browser caching
45
 
46
  //Image size and defaults
47
- if(! defined('MAX_WIDTH') ) define ('MAX_WIDTH', 1500); // Maximum image width
48
- if(! defined('MAX_HEIGHT') ) define ('MAX_HEIGHT', 1500); // Maximum image height
49
- if(! defined('NOT_FOUND_IMAGE') ) define ('NOT_FOUND_IMAGE', ''); //Image to serve if any 404 occurs
50
- if(! defined('ERROR_IMAGE') ) define ('ERROR_IMAGE', ''); //Image to serve if an error occurs instead of showing error message
 
 
 
 
 
 
51
 
52
  //Image compression is enabled if either of these point to valid paths
53
 
@@ -115,6 +124,7 @@ if(! defined('WEBSHOT_XVFB_RUNNING') ) define ('WEBSHOT_XVFB_RUNNING', false);
115
  if(! isset($ALLOWED_SITES)){
116
  $ALLOWED_SITES = array (
117
  'flickr.com',
 
118
  'picasa.com',
119
  'img.youtube.com',
120
  'upload.wikimedia.org',
@@ -187,7 +197,7 @@ class timthumb {
187
  }
188
  $this->cacheDirectory = FILE_CACHE_DIRECTORY;
189
  if (!touch($this->cacheDirectory . '/index.html')) {
190
- $this->error("Could note create the index.html file.");
191
  }
192
  } else {
193
  $this->cacheDirectory = sys_get_temp_dir();
@@ -246,9 +256,11 @@ class timthumb {
246
  }
247
  }
248
 
249
- $cachePrefix = ($this->isURL ? 'timthumb_ext_' : 'timthumb_int_');
250
  if($this->isURL){
251
- $this->cachefile = $this->cacheDirectory . '/' . $cachePrefix . md5($this->salt . $_SERVER ['QUERY_STRING'] . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
 
 
252
  } else {
253
  $this->localImage = $this->getLocalImagePath($this->src);
254
  if(! $this->localImage){
@@ -260,7 +272,7 @@ class timthumb {
260
  $this->debug(1, "Local image path is {$this->localImage}");
261
  $this->localImageMTime = @filemtime($this->localImage);
262
  //We include the mtime of the local file in case in changes on disk.
263
- $this->cachefile = $this->cacheDirectory . '/' . $cachePrefix . md5($this->salt . $this->localImageMTime . $_SERVER ['QUERY_STRING'] . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
264
  }
265
  $this->debug(2, "Cache file is: " . $this->cachefile);
266
 
@@ -438,6 +450,9 @@ class timthumb {
438
  }
439
  }
440
  protected function cleanCache(){
 
 
 
441
  $this->debug(3, "cleanCache() called");
442
  $lastCleanFile = $this->cacheDirectory . '/timthumb_cacheLastCleanTime.touch';
443
 
@@ -499,15 +514,15 @@ class timthumb {
499
  );
500
  }
501
 
502
- // get standard input properties
503
  $new_width = (int) abs ($this->param('w', 0));
504
  $new_height = (int) abs ($this->param('h', 0));
505
- $zoom_crop = (int) $this->param('zc', 1);
506
- $quality = (int) abs ($this->param('q', 90));
507
  $align = $this->cropTop ? 't' : $this->param('a', 'c');
508
- $filters = $this->param('f', '');
509
- $sharpen = (bool) $this->param('s', 0);
510
- $canvas_color = $this->param('cc', 'ffffff');
511
 
512
  // set default width and height if neither are set already
513
  if ($new_width == 0 && $new_height == 0) {
@@ -797,6 +812,9 @@ class timthumb {
797
  }
798
  protected function calcDocRoot(){
799
  $docRoot = @$_SERVER['DOCUMENT_ROOT'];
 
 
 
800
  if(!isset($docRoot)){
801
  $this->debug(3, "DOCUMENT_ROOT is not set. This is probably windows. Starting search 1.");
802
  if(isset($_SERVER['SCRIPT_FILENAME'])){
@@ -818,7 +836,6 @@ class timthumb {
818
  }
819
  protected function getLocalImagePath($src){
820
  $src = preg_replace('/^\//', '', $src); //strip off the leading '/'
821
- $realDocRoot = realpath($this->docRoot);
822
  if(! $this->docRoot){
823
  $this->debug(3, "We have no document root set, so as a last resort, lets check if the image is in the current dir and serve that.");
824
  //We don't support serving images outside the current dir if we don't have a doc root for security reasons.
@@ -833,7 +850,7 @@ class timthumb {
833
  if(file_exists ($this->docRoot . '/' . $src)) {
834
  $this->debug(3, "Found file as " . $this->docRoot . '/' . $src);
835
  $real = realpath($this->docRoot . '/' . $src);
836
- if(stripos($real, $realDocRoot) === 0){
837
  return $real;
838
  } else {
839
  $this->debug(1, "Security block: The file specified occurs outside the document root.");
@@ -845,7 +862,7 @@ class timthumb {
845
  if($absolute && file_exists($absolute)){ //realpath does file_exists check, so can probably skip the exists check here
846
  $this->debug(3, "Found absolute path: $absolute");
847
  if(! $this->docRoot){ $this->sanityFail("docRoot not set when checking absolute path."); }
848
- if(stripos($absolute, $realDocRoot) === 0){
849
  return $absolute;
850
  } else {
851
  $this->debug(1, "Security block: The file specified occurs outside the document root.");
@@ -868,7 +885,7 @@ class timthumb {
868
  if(file_exists($base . $src)){
869
  $this->debug(3, "Found file as: " . $base . $src);
870
  $real = realpath($base . $src);
871
- if(stripos($real, $realDocRoot) === 0){
872
  return $real;
873
  } else {
874
  $this->debug(1, "Security block: The file specified occurs outside the document root.");
@@ -1043,7 +1060,6 @@ class timthumb {
1043
  }
1044
  protected function openImage($mimeType, $src){
1045
  switch ($mimeType) {
1046
- case 'image/jpg': //This isn't a valid mime type so we should probably remove it
1047
  case 'image/jpeg':
1048
  $image = imagecreatefromjpeg ($src);
1049
  break;
@@ -1055,6 +1071,9 @@ class timthumb {
1055
  case 'image/gif':
1056
  $image = imagecreatefromgif ($src);
1057
  break;
 
 
 
1058
  }
1059
 
1060
  return $image;
@@ -1201,4 +1220,4 @@ class timthumb {
1201
  protected function is404(){
1202
  return $this->is404;
1203
  }
1204
- }
9
  *
10
  * Examples and documentation available on the project homepage
11
  * http://www.binarymoon.co.uk/projects/timthumb/
12
+ *
13
+ * $Rev$
14
  */
15
 
16
  /*
17
+ * --- TimThumb CONFIGURATION ---
18
+ * To edit the configs it is best to create a file called timthumb-config.php
19
+ * and define variables you want to customize in there. It will automatically be
20
+ * loaded by timthumb. This will save you having to re-edit these variables
21
+ * everytime you download a new version
 
 
22
  */
23
+ define ('VERSION', '2.8.5'); // Version of this script
24
  //Load a config file if it exists. Otherwise, use the values below
25
  if( file_exists(dirname(__FILE__) . '/timthumb-config.php')) require_once('timthumb-config.php');
26
+ if(! defined('DEBUG_ON') ) define ('DEBUG_ON', false); // Enable debug logging to web server error log (STDERR)
27
+ if(! defined('DEBUG_LEVEL') ) define ('DEBUG_LEVEL', 1); // Debug level 1 is less noisy and 3 is the most noisy
28
+ if(! defined('MEMORY_LIMIT') ) define ('MEMORY_LIMIT', '30M'); // Set PHP memory limit
29
+ if(! defined('BLOCK_EXTERNAL_LEECHERS') ) define ('BLOCK_EXTERNAL_LEECHERS', false); // If the image or webshot is being loaded on an external site, display a red "No Hotlinking" gif.
30
 
31
  //Image fetching and caching
32
+ if(! defined('ALLOW_EXTERNAL') ) define ('ALLOW_EXTERNAL', TRUE); // Allow image fetching from external websites. Will check against ALLOWED_SITES if ALLOW_ALL_EXTERNAL_SITES is false
33
+ if(! defined('ALLOW_ALL_EXTERNAL_SITES') ) define ('ALLOW_ALL_EXTERNAL_SITES', false); // Less secure.
34
+ if(! defined('FILE_CACHE_ENABLED') ) define ('FILE_CACHE_ENABLED', TRUE); // Should we store resized/modified images on disk to speed things up?
35
  if(! defined('FILE_CACHE_TIME_BETWEEN_CLEANS')) define ('FILE_CACHE_TIME_BETWEEN_CLEANS', 86400); // How often the cache is cleaned
36
+
37
+ if(! defined('FILE_CACHE_MAX_FILE_AGE') ) define ('FILE_CACHE_MAX_FILE_AGE', 86400); // How old does a file have to be to be deleted from the cache
38
+ if(! defined('FILE_CACHE_SUFFIX') ) define ('FILE_CACHE_SUFFIX', '.timthumb.txt'); // What to put at the end of all files in the cache directory so we can identify them
39
+ if(! defined('FILE_CACHE_PREFIX') ) define ('FILE_CACHE_PREFIX', 'timthumb'); // What to put at the end of all files in the cache directory so we can identify them
40
+ if(! defined('FILE_CACHE_DIRECTORY') ) define ('FILE_CACHE_DIRECTORY', './cache'); // Directory where images are cached. Left blank it will use the system temporary directory (which is better for security)
41
+ if(! defined('MAX_FILE_SIZE') ) define ('MAX_FILE_SIZE', 10485760); // 10 Megs is 10485760. This is the max internal or external file size that we'll process.
42
+ if(! defined('CURL_TIMEOUT') ) define ('CURL_TIMEOUT', 20); // Timeout duration for Curl. This only applies if you have Curl installed and aren't using PHP's default URL fetching mechanism.
43
+ if(! defined('WAIT_BETWEEN_FETCH_ERRORS') ) define ('WAIT_BETWEEN_FETCH_ERRORS', 3600); //Time to wait between errors fetching remote file
44
+
45
  //Browser caching
46
+ if(! defined('BROWSER_CACHE_MAX_AGE') ) define ('BROWSER_CACHE_MAX_AGE', 864000); // Time to cache in the browser
47
+ if(! defined('BROWSER_CACHE_DISABLE') ) define ('BROWSER_CACHE_DISABLE', false); // Use for testing if you want to disable all browser caching
48
 
49
  //Image size and defaults
50
+ if(! defined('MAX_WIDTH') ) define ('MAX_WIDTH', 1500); // Maximum image width
51
+ if(! defined('MAX_HEIGHT') ) define ('MAX_HEIGHT', 1500); // Maximum image height
52
+ if(! defined('NOT_FOUND_IMAGE') ) define ('NOT_FOUND_IMAGE', ''); // Image to serve if any 404 occurs
53
+ if(! defined('ERROR_IMAGE') ) define ('ERROR_IMAGE', ''); // Image to serve if an error occurs instead of showing error message
54
+ if(! defined('DEFAULT_Q') ) define ('DEFAULT_Q', 90); // Default image quality. Allows overrid in timthumb-config.php
55
+ if(! defined('DEFAULT_ZC') ) define ('DEFAULT_ZC', 1); // Default zoom/crop setting. Allows overrid in timthumb-config.php
56
+ if(! defined('DEFAULT_F') ) define ('DEFAULT_F', ''); // Default image filters. Allows overrid in timthumb-config.php
57
+ if(! defined('DEFAULT_S') ) define ('DEFAULT_S', 0); // Default sharpen value. Allows overrid in timthumb-config.php
58
+ if(! defined('DEFAULT_CC') ) define ('DEFAULT_CC', 'ffffff'); // Default canvas colour. Allows overrid in timthumb-config.php
59
+
60
 
61
  //Image compression is enabled if either of these point to valid paths
62
 
124
  if(! isset($ALLOWED_SITES)){
125
  $ALLOWED_SITES = array (
126
  'flickr.com',
127
+ 'staticflickr.com',
128
  'picasa.com',
129
  'img.youtube.com',
130
  'upload.wikimedia.org',
197
  }
198
  $this->cacheDirectory = FILE_CACHE_DIRECTORY;
199
  if (!touch($this->cacheDirectory . '/index.html')) {
200
+ $this->error("Could note create the index.html file - to fix this create an empty file named index.html file in the cache directory.");
201
  }
202
  } else {
203
  $this->cacheDirectory = sys_get_temp_dir();
256
  }
257
  }
258
 
259
+ $cachePrefix = ($this->isURL ? '_ext_' : '_int_');
260
  if($this->isURL){
261
+ $arr = explode('&', $_SERVER ['QUERY_STRING']);
262
+ asort($arr);
263
+ $this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . implode('', $arr) . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
264
  } else {
265
  $this->localImage = $this->getLocalImagePath($this->src);
266
  if(! $this->localImage){
272
  $this->debug(1, "Local image path is {$this->localImage}");
273
  $this->localImageMTime = @filemtime($this->localImage);
274
  //We include the mtime of the local file in case in changes on disk.
275
+ $this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . $this->localImageMTime . $_SERVER ['QUERY_STRING'] . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
276
  }
277
  $this->debug(2, "Cache file is: " . $this->cachefile);
278
 
450
  }
451
  }
452
  protected function cleanCache(){
453
+ if (FILE_CACHE_TIME_BETWEEN_CLEANS < 0) {
454
+ return;
455
+ }
456
  $this->debug(3, "cleanCache() called");
457
  $lastCleanFile = $this->cacheDirectory . '/timthumb_cacheLastCleanTime.touch';
458
 
514
  );
515
  }
516
 
517
+ // get standard input properties
518
  $new_width = (int) abs ($this->param('w', 0));
519
  $new_height = (int) abs ($this->param('h', 0));
520
+ $zoom_crop = (int) $this->param('zc', DEFAULT_ZC);
521
+ $quality = (int) abs ($this->param('q', DEFAULT_Q));
522
  $align = $this->cropTop ? 't' : $this->param('a', 'c');
523
+ $filters = $this->param('f', DEFAULT_F);
524
+ $sharpen = (bool) $this->param('s', DEFAULT_S);
525
+ $canvas_color = $this->param('cc', DEFAULT_CC);
526
 
527
  // set default width and height if neither are set already
528
  if ($new_width == 0 && $new_height == 0) {
812
  }
813
  protected function calcDocRoot(){
814
  $docRoot = @$_SERVER['DOCUMENT_ROOT'];
815
+ if (defined('LOCAL_FILE_BASE_DIRECTORY')) {
816
+ $docRoot = LOCAL_FILE_BASE_DIRECTORY;
817
+ }
818
  if(!isset($docRoot)){
819
  $this->debug(3, "DOCUMENT_ROOT is not set. This is probably windows. Starting search 1.");
820
  if(isset($_SERVER['SCRIPT_FILENAME'])){
836
  }
837
  protected function getLocalImagePath($src){
838
  $src = preg_replace('/^\//', '', $src); //strip off the leading '/'
 
839
  if(! $this->docRoot){
840
  $this->debug(3, "We have no document root set, so as a last resort, lets check if the image is in the current dir and serve that.");
841
  //We don't support serving images outside the current dir if we don't have a doc root for security reasons.
850
  if(file_exists ($this->docRoot . '/' . $src)) {
851
  $this->debug(3, "Found file as " . $this->docRoot . '/' . $src);
852
  $real = realpath($this->docRoot . '/' . $src);
853
+ if(stripos($real, $this->docRoot) == 0){
854
  return $real;
855
  } else {
856
  $this->debug(1, "Security block: The file specified occurs outside the document root.");
862
  if($absolute && file_exists($absolute)){ //realpath does file_exists check, so can probably skip the exists check here
863
  $this->debug(3, "Found absolute path: $absolute");
864
  if(! $this->docRoot){ $this->sanityFail("docRoot not set when checking absolute path."); }
865
+ if(stripos($absolute, $this->docRoot) == 0){
866
  return $absolute;
867
  } else {
868
  $this->debug(1, "Security block: The file specified occurs outside the document root.");
885
  if(file_exists($base . $src)){
886
  $this->debug(3, "Found file as: " . $base . $src);
887
  $real = realpath($base . $src);
888
+ if(stripos($real, $this->docRoot) == 0){
889
  return $real;
890
  } else {
891
  $this->debug(1, "Security block: The file specified occurs outside the document root.");
1060
  }
1061
  protected function openImage($mimeType, $src){
1062
  switch ($mimeType) {
 
1063
  case 'image/jpeg':
1064
  $image = imagecreatefromjpeg ($src);
1065
  break;
1071
  case 'image/gif':
1072
  $image = imagecreatefromgif ($src);
1073
  break;
1074
+
1075
+ default:
1076
+ $this->error("Unrecognised mimeType");
1077
  }
1078
 
1079
  return $image;
1220
  protected function is404(){
1221
  return $this->is404;
1222
  }
1223
+ }
class-cg-tvs-plugin.php CHANGED
@@ -5,6 +5,7 @@ class CG_TVS_Plugin{
5
  var $script_latest_version;
6
  var $script_safe_version;
7
  var $last_version_check;
 
8
 
9
  var $last_scan;
10
  var $script_instances;
@@ -13,8 +14,13 @@ class CG_TVS_Plugin{
13
  var $plugin_base;
14
 
15
  var $current_timthumb_src_version;
 
16
 
17
  function init(){
 
 
 
 
18
  $storage_array = get_option( 'cg_tvs_data' );
19
  if(is_array($storage_array)){
20
  $this->script_latest_version = $storage_array['script_latest_version'];
@@ -24,9 +30,12 @@ class CG_TVS_Plugin{
24
  $this->script_instances = $storage_array['script_instances'];
25
  $this->suspicious_files = $storage_array['suspicious_files'];
26
  $this->last_scan = $storage_array['last_scan'];
 
 
 
27
 
28
  }else{
29
- $this->script_latest_version = '2.8.2';
30
  $this->script_safe_version = '2.8.2';
31
 
32
  $this->last_version_check = 0;
@@ -34,6 +43,11 @@ class CG_TVS_Plugin{
34
  $this->script_instances = array();
35
  $this->suspicious_files = array();
36
  $this->last_scan = 0;
 
 
 
 
 
37
  $this->save();
38
  }
39
  if($this->last_version_check < time()-86400){
@@ -41,8 +55,12 @@ class CG_TVS_Plugin{
41
  $this->save();
42
  }
43
  $this->plugin_base_dir = trailingslashit(dirname(__FILE__));
44
- if(!is_writeable($this->plugin_base_dir)){
45
- $this->show_message('The plugin directory (at '.$this->plugin_base_dir.') is not writeable. Because of this, we can\'t download an updated copy of timthumb to use. Try changing permissions on this directory to 755 (or in certain cases, 777)', 'error');
 
 
 
 
46
  }
47
  }
48
 
@@ -53,12 +71,14 @@ class CG_TVS_Plugin{
53
 
54
  function activate(){
55
  $this->init();
 
56
  delete_option( 'cg_tvs_last_checked' );
57
  delete_option( 'cg_tvs_vulnerable_files' );
58
  delete_option( 'cg_tvs_safe_files' );
59
  }
60
 
61
  function deactivate(){
 
62
  delete_option( 'cg_tvs_data' );
63
  }
64
 
@@ -89,6 +109,12 @@ class CG_TVS_Plugin{
89
  $this->last_scan = time();
90
  $this->script_instances = $scanner->instances;
91
  $this->suspicious_files = $scanner->suspicious_files;
 
 
 
 
 
 
92
  $this->show_message('Scan completed.');
93
  $this->save();
94
  }
@@ -202,13 +228,18 @@ class CG_TVS_Plugin{
202
  $storage_array['script_instances'] = $this->script_instances;
203
  $storage_array['suspicious_files'] = $this->suspicious_files;
204
  $storage_array['last_scan'] = $this->last_scan;
 
205
 
 
206
  update_option( 'cg_tvs_data', $storage_array );
207
 
208
  }
209
 
210
  function show_message( $message, $error = false )
211
  {
 
 
 
212
  if ($error) {
213
  echo '<div id="message" class="error">';
214
  }
@@ -223,8 +254,11 @@ class CG_TVS_Plugin{
223
  if ( ! current_user_can( 'manage_options' ) ) {
224
  wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
225
  }
226
- $this->init();
227
-
 
 
 
228
  if ( isset( $_REQUEST['cg-tvs-action'] ) ) {
229
  switch ( $_REQUEST['cg-tvs-action'] ) {
230
  case 'scan':
@@ -232,7 +266,7 @@ class CG_TVS_Plugin{
232
  break;
233
  case 'fix':
234
  $this->get_timthumb_src_version();
235
- if($this->get_version_float($this->current_timthumb_src_version) < $this->script_latest_version){
236
  $this->download_new_timthumb_src();
237
  }
238
  if ( wp_verify_nonce( $_POST['_wpnonce'], 'fix_timthumb_files' ) ) {
@@ -256,6 +290,20 @@ class CG_TVS_Plugin{
256
  }
257
  }
258
  break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  }
260
  }
261
 
5
  var $script_latest_version;
6
  var $script_safe_version;
7
  var $last_version_check;
8
+ var $scan_daily;
9
 
10
  var $last_scan;
11
  var $script_instances;
14
  var $plugin_base;
15
 
16
  var $current_timthumb_src_version;
17
+ var $on_admin_page = false;
18
 
19
  function init(){
20
+ global $pagenow;
21
+ if($pagenow == 'tools.php' && $_GET['page'] == 'cg-timthumb-scanner'){
22
+ $this->on_admin_page = true;
23
+ }
24
  $storage_array = get_option( 'cg_tvs_data' );
25
  if(is_array($storage_array)){
26
  $this->script_latest_version = $storage_array['script_latest_version'];
30
  $this->script_instances = $storage_array['script_instances'];
31
  $this->suspicious_files = $storage_array['suspicious_files'];
32
  $this->last_scan = $storage_array['last_scan'];
33
+ $this->scan_daily = $storage_array['scan_daily'];
34
+
35
+ $this->scan_summary = $storage_array['scan_summary'];
36
 
37
  }else{
38
+ $this->script_latest_version = '2.8.5';
39
  $this->script_safe_version = '2.8.2';
40
 
41
  $this->last_version_check = 0;
43
  $this->script_instances = array();
44
  $this->suspicious_files = array();
45
  $this->last_scan = 0;
46
+ $this->scan_daily = true;
47
+ $this->scan_summary['Vulnerable'] = 0;
48
+ $this->scan_summary['Outdated'] = 0;
49
+ $this->scan_summary['Up to Date'] = 0;
50
+
51
  $this->save();
52
  }
53
  if($this->last_version_check < time()-86400){
55
  $this->save();
56
  }
57
  $this->plugin_base_dir = trailingslashit(dirname(__FILE__));
58
+
59
+ if( $this->scan_summary['Outdated'] > 0 && !$this->on_admin_page ){
60
+ $this->show_message( $this->scan_summary['Outdated']." outdated Timthumb "._n('file', 'files', $this->scan_summary['Outdated'])." found. <a href=\"tools.php?page=cg-timthumb-scanner\">Fix "._n('it', 'them', $this->scan_summary['Outdated'])." here</a>.", $error = false );
61
+ }
62
+ if( $this->scan_summary['Vulnerable'] > 0 && !$this->on_admin_page ){
63
+ $this->show_message( $this->scan_summary['Vulnerable']." vulnerable Timthumb "._n('file', 'files', $this->scan_summary['Vulnerable'])." found. <a href=\"tools.php?page=cg-timthumb-scanner\">Fix "._n('it', 'them', $this->scan_summary['Vulnerable'])." here</a>.", $error = true );
64
  }
65
  }
66
 
71
 
72
  function activate(){
73
  $this->init();
74
+ // Clear out older version data
75
  delete_option( 'cg_tvs_last_checked' );
76
  delete_option( 'cg_tvs_vulnerable_files' );
77
  delete_option( 'cg_tvs_safe_files' );
78
  }
79
 
80
  function deactivate(){
81
+ wp_clear_scheduled_hook('cg_tvs_daily_scan');
82
  delete_option( 'cg_tvs_data' );
83
  }
84
 
109
  $this->last_scan = time();
110
  $this->script_instances = $scanner->instances;
111
  $this->suspicious_files = $scanner->suspicious_files;
112
+ $this->scan_summary['Vulnerable'] = 0;
113
+ $this->scan_summary['Outdated'] = 0;
114
+ $this->scan_summary['Up to Date'] = 0;
115
+ foreach($scanner->instances as $file){
116
+ $this->scan_summary[$this->get_version_status($file['version'])]++;
117
+ }
118
  $this->show_message('Scan completed.');
119
  $this->save();
120
  }
228
  $storage_array['script_instances'] = $this->script_instances;
229
  $storage_array['suspicious_files'] = $this->suspicious_files;
230
  $storage_array['last_scan'] = $this->last_scan;
231
+ $storage_array['scan_daily'] = $this->scan_daily;
232
 
233
+ $storage_array['scan_summary'] = $this->scan_summary;
234
  update_option( 'cg_tvs_data', $storage_array );
235
 
236
  }
237
 
238
  function show_message( $message, $error = false )
239
  {
240
+ if(DOING_CRON === TRUE){
241
+ return;
242
+ }
243
  if ($error) {
244
  echo '<div id="message" class="error">';
245
  }
254
  if ( ! current_user_can( 'manage_options' ) ) {
255
  wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
256
  }
257
+
258
+ if(!is_writeable($this->plugin_base_dir)){
259
+ $this->show_message('The plugin directory (at '.$this->plugin_base_dir.') is not writeable. Because of this, we can\'t download an updated copy of timthumb to use. Try changing permissions on this directory to 755 (or in certain cases, 777)', 'error');
260
+ }
261
+
262
  if ( isset( $_REQUEST['cg-tvs-action'] ) ) {
263
  switch ( $_REQUEST['cg-tvs-action'] ) {
264
  case 'scan':
266
  break;
267
  case 'fix':
268
  $this->get_timthumb_src_version();
269
+ if($this->get_version_float($this->current_timthumb_src_version) < $this->get_version_float($this->script_latest_version)){
270
  $this->download_new_timthumb_src();
271
  }
272
  if ( wp_verify_nonce( $_POST['_wpnonce'], 'fix_timthumb_files' ) ) {
290
  }
291
  }
292
  break;
293
+ case 'update-options':
294
+ $nonce = $_POST['_wpnonce'];
295
+ if ( wp_verify_nonce( $nonce, 'update_tvs_options' ) ) {
296
+ if($_POST['scan-daily']){
297
+ $this->scan_daily = true;
298
+ if ( !wp_next_scheduled( 'cg_tvs_daily_scan' ) ) {
299
+ wp_schedule_event(time(), 'daily', 'cg_tvs_daily_scan');
300
+ }
301
+ }else{
302
+ $this->scan_daily = false;
303
+ wp_clear_scheduled_hook('cg_tvs_daily_scan');
304
+ }
305
+ }
306
+ break;
307
  }
308
  }
309
 
readme.txt CHANGED
@@ -1,8 +1,8 @@
1
  === Timthumb Vulnerability Scanner ===
2
  Contributors: peterebutler
3
- Tags: security, scanning, timthumb, hack
4
  Requires at least: 3.0
5
- Tested up to: 3.2.1
6
  Stable tag: trunk
7
 
8
  Scans your wp-content directory for vulnerable instances of timthumb.php, and optionally upgrades them to a safe version.
@@ -13,7 +13,7 @@ The recent Timthumb.php vulnerability (discussed [here](http://markmaunder.com/2
13
 
14
  The Timthumb Vulnerability Scanner plugin will scan your entire wp-content directory for instances of any outdated and insecure version of the timthumb script, and give you the option to automatically upgrade them with a single click. Doing so will protect you from hackers looking to exploit this particular vulnerability.
15
 
16
- After new, lesser vulnerabilities were found, it became apparent that the plugin needs to be dynamic - able to keep you up to date with the latest version of timthumb, without requiring a plugin upgrade. The plugin now checks for the latest available version of timthumb routinely (each time you visit the scanner page, but no more than once a day), and can download and install the latest version, rather than the one included with the plugin.
17
 
18
  More info at [CodeGarage](http://codegarage.com/blog/2011/09/wordpress-timthumb-vulnerability-scanner-plugin/).
19
 
@@ -47,6 +47,11 @@ If you've already been hacked, all is not lost - there are people out there who
47
 
48
  == Changelog ==
49
 
 
 
 
 
 
50
  = 1.4 =
51
  * Largely rewrote codebase to clean up code.
52
  * Added functionality to download latest version of timthumb rather than relying on static version included in plugin.
1
  === Timthumb Vulnerability Scanner ===
2
  Contributors: peterebutler
3
+ Tags: security, scanning, timthumb, hack, vulnerability
4
  Requires at least: 3.0
5
+ Tested up to: 3.3.1
6
  Stable tag: trunk
7
 
8
  Scans your wp-content directory for vulnerable instances of timthumb.php, and optionally upgrades them to a safe version.
13
 
14
  The Timthumb Vulnerability Scanner plugin will scan your entire wp-content directory for instances of any outdated and insecure version of the timthumb script, and give you the option to automatically upgrade them with a single click. Doing so will protect you from hackers looking to exploit this particular vulnerability.
15
 
16
+ After new, lesser vulnerabilities were found, it became apparent that the plugin needs to be dynamic - able to keep you up to date with the latest version of timthumb, without requiring a plugin upgrade. The plugin now checks for the latest available version of timthumb routinely (each time you visit the scanner page, but no more than once a day), and can download and install the latest version, rather than the one included with the plugin. Scans are run daily (unless you disable them via the options link on the scanner page) via wp-cron to keep up with any new plugins or themes you've installed.
17
 
18
  More info at [CodeGarage](http://codegarage.com/blog/2011/09/wordpress-timthumb-vulnerability-scanner-plugin/).
19
 
47
 
48
  == Changelog ==
49
 
50
+ = 1.5 =
51
+ * Added a daily automatic scan
52
+ * Added alerts across the admin section when vulnerable or outdated files are found
53
+ * Fixed issue with updating timthumb src file
54
+
55
  = 1.4 =
56
  * Largely rewrote codebase to clean up code.
57
  * Added functionality to download latest version of timthumb rather than relying on static version included in plugin.
timthumb-vulnerability-scanner.php CHANGED
@@ -4,13 +4,22 @@ Plugin Name: TimThumb Vulnerability Scanner
4
  Plugin URI: http://codegarage.com/blog/2011/09/wordpress-timthumb-vulnerability-scanner-plugin-1.4/
5
  Description: Keep your instances of Timthumb up to date and free from vulnerabilities simply. Bonus - checks for obvious signs of compromised sites.
6
  Author: Peter Butler
7
- Version: 1.43
8
  Author URI: http://codegarage.com/
9
  */
10
 
11
  include_once 'class-cg-tvs-plugin.php';
12
 
13
  $CG_TVS_Plugin = new CG_TVS_Plugin();
 
14
  add_action( 'admin_menu', array($CG_TVS_Plugin, 'add_menus' ) );
15
  register_activation_hook( __FILE__, array($CG_TVS_Plugin, 'activate' ) );
16
  register_deactivation_hook( __FILE__, array($CG_TVS_Plugin, 'deactivate' ) );
 
 
 
 
 
 
 
 
4
  Plugin URI: http://codegarage.com/blog/2011/09/wordpress-timthumb-vulnerability-scanner-plugin-1.4/
5
  Description: Keep your instances of Timthumb up to date and free from vulnerabilities simply. Bonus - checks for obvious signs of compromised sites.
6
  Author: Peter Butler
7
+ Version: 1.5
8
  Author URI: http://codegarage.com/
9
  */
10
 
11
  include_once 'class-cg-tvs-plugin.php';
12
 
13
  $CG_TVS_Plugin = new CG_TVS_Plugin();
14
+ $CG_TVS_Plugin->init();
15
  add_action( 'admin_menu', array($CG_TVS_Plugin, 'add_menus' ) );
16
  register_activation_hook( __FILE__, array($CG_TVS_Plugin, 'activate' ) );
17
  register_deactivation_hook( __FILE__, array($CG_TVS_Plugin, 'deactivate' ) );
18
+
19
+ // For automatic daily scans
20
+ add_action('cg_tvs_daily_scan', 'cg_tvs_daily_scan');
21
+
22
+ function cg_tvs_daily_scan() {
23
+ global $CG_TVS_Plugin;
24
+ $CG_TVS_Plugin->scan();
25
+ }